From d53658a079995e4d241bfa6d98fbd07158d71c47 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 14:35:49 -0700 Subject: [PATCH 001/174] Copy ice40 into xc7 --- xc7/arch.cc | 902 ++++++++++ xc7/arch.h | 841 ++++++++++ xc7/arch_place.cc | 162 ++ xc7/arch_pybindings.cc | 154 ++ xc7/arch_pybindings.h | 62 + xc7/archdefs.h | 194 +++ xc7/benchmark/.gitignore | 6 + xc7/benchmark/hx8kdemo.pcf | 40 + xc7/benchmark/hx8kdemo.v | 139 ++ xc7/benchmark/picorv32.v | 2977 +++++++++++++++++++++++++++++++++ xc7/benchmark/picosoc.v | 241 +++ xc7/benchmark/report.ipynb | 91 + xc7/benchmark/simpleuart.v | 137 ++ xc7/benchmark/spimemio.v | 579 +++++++ xc7/bitstream.cc | 999 +++++++++++ xc7/bitstream.h | 34 + xc7/blinky.pcf | 6 + xc7/blinky.proj | 15 + xc7/blinky.sh | 8 + xc7/blinky.v | 27 + xc7/blinky.ys | 3 + xc7/blinky_tb.v | 25 + xc7/carry_tests/.gitignore | 4 + xc7/carry_tests/counter.v | 9 + xc7/carry_tests/counter_tb.v | 23 + xc7/carry_tests/test.pcf | 10 + xc7/carry_tests/test.sh | 9 + xc7/cells.cc | 409 +++++ xc7/cells.h | 114 ++ xc7/chains.cc | 287 ++++ xc7/chains.h | 27 + xc7/chipdb.py | 1280 ++++++++++++++ xc7/constids.inc | 437 +++++ xc7/delay.cc | 238 +++ xc7/family.cmake | 84 + xc7/gfx.cc | 766 +++++++++ xc7/gfx.h | 523 ++++++ xc7/icebreaker.pcf | 14 + xc7/icebreaker.v | 31 + xc7/icebreaker.ys | 3 + xc7/main.cc | 164 ++ xc7/pack.cc | 907 ++++++++++ xc7/pack_tests/.gitignore | 2 + xc7/pack_tests/ffmodes.v | 43 + xc7/pack_tests/locals.v | 27 + xc7/pack_tests/place_constr.v | 54 + xc7/pack_tests/test.pcf | 10 + xc7/pack_tests/test.sh | 16 + xc7/pcf.cc | 76 + xc7/pcf.h | 34 + xc7/picorv32.proj | 15 + xc7/picorv32.sh | 7 + xc7/picorv32_benchmark.py | 42 + xc7/picorv32_top.v | 31 + xc7/project.cc | 73 + xc7/resource/chipdb.rc | 6 + xc7/resource/embed.cc | 30 + xc7/resource/resource.h | 5 + xc7/tmfuzz.py | 357 ++++ 59 files changed, 13809 insertions(+) create mode 100644 xc7/arch.cc create mode 100644 xc7/arch.h create mode 100644 xc7/arch_place.cc create mode 100644 xc7/arch_pybindings.cc create mode 100644 xc7/arch_pybindings.h create mode 100644 xc7/archdefs.h create mode 100644 xc7/benchmark/.gitignore create mode 100644 xc7/benchmark/hx8kdemo.pcf create mode 100644 xc7/benchmark/hx8kdemo.v create mode 100644 xc7/benchmark/picorv32.v create mode 100644 xc7/benchmark/picosoc.v create mode 100644 xc7/benchmark/report.ipynb create mode 100644 xc7/benchmark/simpleuart.v create mode 100644 xc7/benchmark/spimemio.v create mode 100644 xc7/bitstream.cc create mode 100644 xc7/bitstream.h create mode 100644 xc7/blinky.pcf create mode 100644 xc7/blinky.proj create mode 100755 xc7/blinky.sh create mode 100644 xc7/blinky.v create mode 100644 xc7/blinky.ys create mode 100644 xc7/blinky_tb.v create mode 100644 xc7/carry_tests/.gitignore create mode 100644 xc7/carry_tests/counter.v create mode 100644 xc7/carry_tests/counter_tb.v create mode 100644 xc7/carry_tests/test.pcf create mode 100755 xc7/carry_tests/test.sh create mode 100644 xc7/cells.cc create mode 100644 xc7/cells.h create mode 100644 xc7/chains.cc create mode 100644 xc7/chains.h create mode 100644 xc7/chipdb.py create mode 100644 xc7/constids.inc create mode 100644 xc7/delay.cc create mode 100644 xc7/family.cmake create mode 100644 xc7/gfx.cc create mode 100644 xc7/gfx.h create mode 100644 xc7/icebreaker.pcf create mode 100644 xc7/icebreaker.v create mode 100644 xc7/icebreaker.ys create mode 100644 xc7/main.cc create mode 100644 xc7/pack.cc create mode 100644 xc7/pack_tests/.gitignore create mode 100644 xc7/pack_tests/ffmodes.v create mode 100644 xc7/pack_tests/locals.v create mode 100644 xc7/pack_tests/place_constr.v create mode 100644 xc7/pack_tests/test.pcf create mode 100755 xc7/pack_tests/test.sh create mode 100644 xc7/pcf.cc create mode 100644 xc7/pcf.h create mode 100644 xc7/picorv32.proj create mode 100755 xc7/picorv32.sh create mode 100755 xc7/picorv32_benchmark.py create mode 100644 xc7/picorv32_top.v create mode 100644 xc7/project.cc create mode 100644 xc7/resource/chipdb.rc create mode 100644 xc7/resource/embed.cc create mode 100644 xc7/resource/resource.h create mode 100644 xc7/tmfuzz.py diff --git a/xc7/arch.cc b/xc7/arch.cc new file mode 100644 index 00000000..7e2dd7f7 --- /dev/null +++ b/xc7/arch.cc @@ -0,0 +1,902 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski + * + * 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 +#include +#include "cells.h" +#include "gfx.h" +#include "log.h" +#include "nextpnr.h" +#include "placer1.h" +#include "router1.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +// ----------------------------------------------------------------------- + +void IdString::initialize_arch(const BaseCtx *ctx) +{ +#define X(t) initialize_add(ctx, #t, ID_##t); +#include "constids.inc" +#undef X +} + +// ----------------------------------------------------------------------- + +static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } + +#if defined(_MSC_VER) +void load_chipdb(); +#endif + +Arch::Arch(ArchArgs args) : args(args) +{ +#if defined(_MSC_VER) + load_chipdb(); +#endif + +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + fast_part = true; + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + fast_part = false; + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_384)); + } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { + fast_part = args.type == ArchArgs::HX1K; + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + } else if (args.type == ArchArgs::UP5K) { + fast_part = false; + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_5k)); + } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { + fast_part = args.type == ArchArgs::HX8K; + chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_8k)); + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#endif + + package_info = nullptr; + for (int i = 0; i < chip_info->num_packages; i++) { + if (chip_info->packages_data[i].name.get() == 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_carry.resize(chip_info->num_bels); + bel_to_cell.resize(chip_info->num_bels); + wire_to_net.resize(chip_info->num_wires); + pip_to_net.resize(chip_info->num_pips); + switches_locked.resize(chip_info->num_switches); +} + +// ----------------------------------------------------------------------- + +std::string Arch::getChipName() const +{ +#ifdef ICE40_HX1K_ONLY + if (args.type == ArchArgs::HX1K) { + return "Lattice LP1K"; + } else { + log_error("Unsupported iCE40 chip type.\n"); + } +#else + if (args.type == ArchArgs::LP384) { + return "Lattice LP384"; + } else if (args.type == ArchArgs::LP1K) { + return "Lattice LP1K"; + } else if (args.type == ArchArgs::HX1K) { + return "Lattice HX1K"; + } else if (args.type == ArchArgs::UP5K) { + return "Lattice UP5K"; + } else if (args.type == ArchArgs::LP8K) { + return "Lattice LP8K"; + } else if (args.type == ArchArgs::HX8K) { + return "Lattice HX8K"; + } else { + log_error("Unknown chip\n"); + } +#endif +} + +// ----------------------------------------------------------------------- + +IdString Arch::archArgsToId(ArchArgs args) const +{ + if (args.type == ArchArgs::LP384) + return id("lp384"); + if (args.type == ArchArgs::LP1K) + return id("lp1k"); + if (args.type == ArchArgs::HX1K) + return id("hx1k"); + if (args.type == ArchArgs::UP5K) + return id("up5k"); + if (args.type == ArchArgs::LP8K) + return id("lp8k"); + if (args.type == ArchArgs::HX8K) + return id("hx8k"); + return IdString(); +} + +// ----------------------------------------------------------------------- + +BelId Arch::getBelByName(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + +BelId Arch::getBelByLocation(Loc loc) const +{ + BelId bel; + + if (bel_by_loc.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) { + BelId b; + b.index = i; + bel_by_loc[getBelLocation(b)] = i; + } + } + + auto it = bel_by_loc.find(loc); + if (it != bel_by_loc.end()) + bel.index = it->second; + + return bel; +} + +BelRange Arch::getBelsByTile(int x, int y) const +{ + // In iCE40 chipdb bels at the same tile are consecutive and dense z ordinates + // are used + BelRange br; + + br.b.cursor = Arch::getBelByLocation(Loc(x, y, 0)).index; + br.e.cursor = br.b.cursor; + + if (br.e.cursor != -1) { + while (br.e.cursor < chip_info->num_bels && chip_info->bel_data[br.e.cursor].x == x && + chip_info->bel_data[br.e.cursor].y == y) + br.e.cursor++; + } + + return br; +} + +PortType Arch::getBelPinType(BelId bel, IdString pin) const +{ + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + if (num_bel_wires < 7) { + for (int i = 0; i < num_bel_wires; i++) { + if (bel_wires[i].port == pin.index) + return PortType(bel_wires[i].type); + } + } else { + int b = 0, e = num_bel_wires - 1; + while (b <= e) { + int i = (b + e) / 2; + if (bel_wires[i].port == pin.index) + return PortType(bel_wires[i].type); + if (bel_wires[i].port > pin.index) + e = i - 1; + else + b = i + 1; + } + } + + return PORT_INOUT; +} + +WireId Arch::getBelPinWire(BelId bel, IdString pin) const +{ + WireId ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + if (num_bel_wires < 7) { + for (int i = 0; i < num_bel_wires; i++) { + if (bel_wires[i].port == pin.index) { + ret.index = bel_wires[i].wire_index; + break; + } + } + } else { + int b = 0, e = num_bel_wires - 1; + while (b <= e) { + int i = (b + e) / 2; + if (bel_wires[i].port == pin.index) { + ret.index = bel_wires[i].wire_index; + break; + } + if (bel_wires[i].port > pin.index) + e = i - 1; + else + b = i + 1; + } + } + + return ret; +} + +std::vector Arch::getBelPins(BelId bel) const +{ + std::vector ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + ret.push_back(IdString(bel_wires[i].port)); + + return ret; +} + +// ----------------------------------------------------------------------- + +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +IdString Arch::getWireType(WireId wire) const +{ + NPNR_ASSERT(wire != WireId()); + switch (chip_info->wire_data[wire.index].type) { + case WireInfoPOD::WIRE_TYPE_NONE: + return IdString(); + case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: + return id("GLB2LOCAL"); + case WireInfoPOD::WIRE_TYPE_GLB_NETWK: + return id("GLB_NETWK"); + case WireInfoPOD::WIRE_TYPE_LOCAL: + return id("LOCAL"); + case WireInfoPOD::WIRE_TYPE_LUTFF_IN: + return id("LUTFF_IN"); + case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: + return id("LUTFF_IN_LUT"); + case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: + return id("LUTFF_LOUT"); + case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: + return id("LUTFF_OUT"); + case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: + return id("LUTFF_COUT"); + case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: + return id("LUTFF_GLOBAL"); + case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: + return id("CARRY_IN_MUX"); + case WireInfoPOD::WIRE_TYPE_SP4_V: + return id("SP4_V"); + case WireInfoPOD::WIRE_TYPE_SP4_H: + return id("SP4_H"); + case WireInfoPOD::WIRE_TYPE_SP12_V: + return id("SP12_V"); + case WireInfoPOD::WIRE_TYPE_SP12_H: + return id("SP12_H"); + } + return IdString(); +} + +// ----------------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; + + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } + + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; + + return ret; +} + +IdString Arch::getPipName(PipId pip) const +{ + NPNR_ASSERT(pip != PipId()); + +#if 1 + int x = chip_info->pip_data[pip.index].x; + int y = chip_info->pip_data[pip.index].y; + + std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + std::replace(src_name.begin(), src_name.end(), '/', '.'); + + std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + + return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); +#else + return id(chip_info->pip_data[pip.index].name.get()); +#endif +} + +// ----------------------------------------------------------------------- + +BelId Arch::getPackagePinBel(const std::string &pin) const +{ + for (int i = 0; i < package_info->num_pins; i++) { + if (package_info->pins[i].name.get() == pin) { + BelId id; + id.index = package_info->pins[i].bel_index; + return id; + } + } + return BelId(); +} + +std::string Arch::getBelPackagePin(BelId bel) const +{ + for (int i = 0; i < package_info->num_pins; i++) { + if (package_info->pins[i].bel_index == bel.index) { + return std::string(package_info->pins[i].name.get()); + } + } + return ""; +} + +// ----------------------------------------------------------------------- + +GroupId Arch::getGroupByName(IdString name) const +{ + for (auto g : getGroups()) + if (getGroupName(g) == name) + return g; + return GroupId(); +} + +IdString Arch::getGroupName(GroupId group) const +{ + std::string suffix; + + switch (group.type) { + case GroupId::TYPE_FRAME: + suffix = "tile"; + break; + case GroupId::TYPE_MAIN_SW: + suffix = "main_sw"; + break; + case GroupId::TYPE_LOCAL_SW: + suffix = "local_sw"; + break; + case GroupId::TYPE_LC0_SW: + suffix = "lc0_sw"; + break; + case GroupId::TYPE_LC1_SW: + suffix = "lc1_sw"; + break; + case GroupId::TYPE_LC2_SW: + suffix = "lc2_sw"; + break; + case GroupId::TYPE_LC3_SW: + suffix = "lc3_sw"; + break; + case GroupId::TYPE_LC4_SW: + suffix = "lc4_sw"; + break; + case GroupId::TYPE_LC5_SW: + suffix = "lc5_sw"; + break; + case GroupId::TYPE_LC6_SW: + suffix = "lc6_sw"; + break; + case GroupId::TYPE_LC7_SW: + suffix = "lc7_sw"; + break; + default: + return IdString(); + } + + return id("X" + std::to_string(group.x) + "/Y" + std::to_string(group.y) + "/" + suffix); +} + +std::vector Arch::getGroups() const +{ + std::vector ret; + + for (int y = 0; y < chip_info->height; y++) { + for (int x = 0; x < chip_info->width; x++) { + TileType type = chip_info->tile_grid[y * chip_info->width + x]; + if (type == TILE_NONE) + continue; + + GroupId group; + group.type = GroupId::TYPE_FRAME; + group.x = x; + group.y = y; + // ret.push_back(group); + + group.type = GroupId::TYPE_MAIN_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LOCAL_SW; + ret.push_back(group); + + if (type == TILE_LOGIC) { + group.type = GroupId::TYPE_LC0_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC1_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC2_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC3_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC4_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC5_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC6_SW; + ret.push_back(group); + + group.type = GroupId::TYPE_LC7_SW; + ret.push_back(group); + } + } + } + return ret; +} + +std::vector Arch::getGroupBels(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupWires(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupPips(GroupId group) const +{ + std::vector ret; + return ret; +} + +std::vector Arch::getGroupGroups(GroupId group) const +{ + std::vector ret; + return ret; +} + +// ----------------------------------------------------------------------- + +bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const +{ + const auto &driver = net_info->driver; + if (driver.port == id_COUT && sink.port == id_CIN) { + auto driver_loc = getBelLocation(driver.cell->bel); + auto sink_loc = getBelLocation(sink.cell->bel); + if (driver_loc.y == sink_loc.y) + budget = 0; + else + switch (args.type) { +#ifndef ICE40_HX1K_ONLY + case ArchArgs::HX8K: +#endif + case ArchArgs::HX1K: + budget = 190; + break; +#ifndef ICE40_HX1K_ONLY + case ArchArgs::LP384: + case ArchArgs::LP1K: + case ArchArgs::LP8K: + budget = 290; + break; + case ArchArgs::UP5K: + budget = 560; + break; +#endif + default: + log_error("Unsupported iCE40 chip type.\n"); + } + return true; + } + return false; +} + +// ----------------------------------------------------------------------- + +bool Arch::place() +{ + Placer1Cfg cfg; + cfg.constraintWeight = placer_constraintWeight; + return placer1(getCtx(), cfg); +} + +bool Arch::route() +{ + Router1Cfg cfg; + return router1(getCtx(), cfg); +} + +// ----------------------------------------------------------------------- + +DecalXY Arch::getBelDecal(BelId bel) const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_BEL; + decalxy.decal.index = bel.index; + decalxy.decal.active = bel_to_cell.at(bel.index) != nullptr; + return decalxy; +} + +DecalXY Arch::getWireDecal(WireId wire) const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_WIRE; + decalxy.decal.index = wire.index; + decalxy.decal.active = wire_to_net.at(wire.index) != nullptr; + return decalxy; +} + +DecalXY Arch::getPipDecal(PipId pip) const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_PIP; + decalxy.decal.index = pip.index; + decalxy.decal.active = pip_to_net.at(pip.index) != nullptr; + return decalxy; +}; + +DecalXY Arch::getGroupDecal(GroupId group) const +{ + DecalXY decalxy; + decalxy.decal.type = DecalId::TYPE_GROUP; + decalxy.decal.index = (group.type << 16) | (group.x << 8) | (group.y); + decalxy.decal.active = true; + return decalxy; +}; + +std::vector Arch::getDecalGraphics(DecalId decal) const +{ + std::vector ret; + + if (decal.type == DecalId::TYPE_GROUP) { + int type = (decal.index >> 16) & 255; + int x = (decal.index >> 8) & 255; + int y = decal.index & 255; + + if (type == GroupId::TYPE_FRAME) { + GraphicElement el; + el.type = GraphicElement::TYPE_LINE; + el.style = GraphicElement::STYLE_FRAME; + + el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.01, el.y2 = y + 0.01; + ret.push_back(el); + el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.01, el.y2 = y + 0.02; + ret.push_back(el); + + el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.01, el.y2 = y + 0.01; + ret.push_back(el); + el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.01, el.y2 = y + 0.02; + ret.push_back(el); + + el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.99, el.y2 = y + 0.99; + ret.push_back(el); + el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.99, el.y2 = y + 0.98; + ret.push_back(el); + + el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.99, el.y2 = y + 0.99; + ret.push_back(el); + el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.99, el.y2 = y + 0.98; + ret.push_back(el); + } + + if (type == GroupId::TYPE_MAIN_SW) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = GraphicElement::STYLE_FRAME; + + el.x1 = x + main_swbox_x1; + el.x2 = x + main_swbox_x2; + el.y1 = y + main_swbox_y1; + el.y2 = y + main_swbox_y2; + ret.push_back(el); + } + + if (type == GroupId::TYPE_LOCAL_SW) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = GraphicElement::STYLE_FRAME; + + el.x1 = x + local_swbox_x1; + el.x2 = x + local_swbox_x2; + el.y1 = y + local_swbox_y1; + el.y2 = y + local_swbox_y2; + ret.push_back(el); + } + + if (GroupId::TYPE_LC0_SW <= type && type <= GroupId::TYPE_LC7_SW) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = GraphicElement::STYLE_FRAME; + + el.x1 = x + lut_swbox_x1; + el.x2 = x + lut_swbox_x2; + el.y1 = y + logic_cell_y1 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW); + el.y2 = y + logic_cell_y2 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW); + ret.push_back(el); + } + } + + if (decal.type == DecalId::TYPE_WIRE) { + int n = chip_info->wire_data[decal.index].num_segments; + const WireSegmentPOD *p = chip_info->wire_data[decal.index].segments.get(); + + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + + for (int i = 0; i < n; i++) + gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); + } + + if (decal.type == DecalId::TYPE_PIP) { + const PipInfoPOD &p = chip_info->pip_data[decal.index]; + GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; + gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style); + } + + if (decal.type == DecalId::TYPE_BEL) { + BelId bel; + bel.index = decal.index; + + auto bel_type = getBelType(bel); + + if (bel_type == id_ICESTORM_LC) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + + (chip_info->bel_data[bel.index].z) * logic_cell_pitch; + ret.push_back(el); + } + + if (bel_type == id_SB_IO) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + + (4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + + (4 * chip_info->bel_data[bel.index].z + 3) * logic_cell_pitch; + ret.push_back(el); + } + + if (bel_type == id_ICESTORM_RAM) { + for (int i = 0; i < 2; i++) { + GraphicElement el; + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; + el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; + el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch; + ret.push_back(el); + } + } + } + + return ret; +} + +// ----------------------------------------------------------------------- + +bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const +{ + for (int i = 0; i < chip_info->num_timing_cells; i++) { + const auto &tc = chip_info->cell_timing[i]; + if (tc.type == cell->type.index) { + for (int j = 0; j < tc.num_paths; j++) { + const auto &path = tc.path_delays[j]; + if (path.from_port == fromPort.index && path.to_port == toPort.index) { + if (fast_part) + delay.delay = path.fast_delay; + else + delay.delay = path.slow_delay; + return true; + } + } + break; + } + } + return false; +} + +// Get the port class, also setting clockPort to associated clock if applicable +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +{ + if (cell->type == id_ICESTORM_LC) { + if (port == id_CLK) + return TMG_CLOCK_INPUT; + if (port == id_CIN) + return TMG_COMB_INPUT; + if (port == id_COUT || port == id_LO) + return TMG_COMB_OUTPUT; + if (cell->lcInfo.dffEnable) { + clockPort = id_CLK; + if (port == id_O) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; + } else { + if (port == id_O) + return TMG_COMB_OUTPUT; + else + return TMG_COMB_INPUT; + } + } else if (cell->type == id_ICESTORM_RAM) { + + if (port == id_RCLK || port == id_WCLK) + return TMG_CLOCK_INPUT; + + if (port.str(this)[0] == 'R') + clockPort = id_RCLK; + else + clockPort = id_WCLK; + + if (cell->ports.at(port).type == PORT_OUT) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; + } else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) { + clockPort = id_CLK; + if (port == id_CLK) + return TMG_CLOCK_INPUT; + else if (cell->ports.at(port).type == PORT_OUT) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; + } else if (cell->type == id_SB_IO) { + if (port == id_D_IN_0 || port == id_D_IN_1) + return TMG_STARTPOINT; + if (port == id_D_OUT_0 || port == id_D_OUT_1 || port == id_OUTPUT_ENABLE) + return TMG_ENDPOINT; + return TMG_IGNORE; + } else if (cell->type == id_ICESTORM_PLL) { + if (port == id_PLLOUT_A || port == id_PLLOUT_B) + return TMG_GEN_CLOCK; + return TMG_IGNORE; + } else if (cell->type == id_ICESTORM_LFOSC) { + if (port == id_CLKLF) + return TMG_GEN_CLOCK; + return TMG_IGNORE; + } else if (cell->type == id_ICESTORM_HFOSC) { + if (port == id_CLKHF) + return TMG_GEN_CLOCK; + return TMG_IGNORE; + } else if (cell->type == id_SB_GB) { + if (port == id_GLOBAL_BUFFER_OUTPUT) + return TMG_COMB_OUTPUT; + return TMG_COMB_INPUT; + } else if (cell->type == id_SB_WARMBOOT) { + return TMG_ENDPOINT; + } + log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); +} + +bool Arch::isGlobalNet(const NetInfo *net) const +{ + if (net == nullptr) + return false; + return net->driver.cell != nullptr && net->driver.port == id_GLOBAL_BUFFER_OUTPUT; +} + +// Assign arch arg info +void Arch::assignArchInfo() +{ + for (auto &net : getCtx()->nets) { + NetInfo *ni = net.second.get(); + if (isGlobalNet(ni)) + ni->is_global = true; + ni->is_enable = false; + ni->is_reset = false; + for (auto usr : ni->users) { + if (is_enable_port(this, usr)) + ni->is_enable = true; + if (is_reset_port(this, usr)) + ni->is_reset = true; + } + } + for (auto &cell : getCtx()->cells) { + CellInfo *ci = cell.second.get(); + assignCellInfo(ci); + } +} + +void Arch::assignCellInfo(CellInfo *cell) +{ + cell->belType = cell->type; + if (cell->type == id_ICESTORM_LC) { + cell->lcInfo.dffEnable = bool_or_default(cell->params, id_DFF_ENABLE); + cell->lcInfo.carryEnable = bool_or_default(cell->params, id_CARRY_ENABLE); + cell->lcInfo.negClk = bool_or_default(cell->params, id_NEG_CLK); + cell->lcInfo.clk = get_net_or_empty(cell, id_CLK); + cell->lcInfo.cen = get_net_or_empty(cell, id_CEN); + cell->lcInfo.sr = get_net_or_empty(cell, id_SR); + cell->lcInfo.inputCount = 0; + if (get_net_or_empty(cell, id_I0)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I1)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I2)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I3)) + cell->lcInfo.inputCount++; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/arch.h b/xc7/arch.h new file mode 100644 index 00000000..8fd1af23 --- /dev/null +++ b/xc7/arch.h @@ -0,0 +1,841 @@ +/* + * 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 NEXTPNR_H +#error Include "arch.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +/**** Everything in this section must be kept in sync with chipdb.py ****/ + +template struct RelPtr +{ + int32_t offset; + + // void set(const T *ptr) { + // offset = reinterpret_cast(ptr) - + // reinterpret_cast(this); + // } + + const T *get() const { return reinterpret_cast(reinterpret_cast(this) + offset); } + + const T &operator[](size_t index) const { return get()[index]; } + + const T &operator*() const { return *(get()); } + + const T *operator->() const { return get(); } +}; + +NPNR_PACKED_STRUCT(struct BelWirePOD { + int32_t port; + int32_t type; + int32_t wire_index; +}); + +NPNR_PACKED_STRUCT(struct BelInfoPOD { + RelPtr name; + int32_t type; + int32_t num_bel_wires; + RelPtr bel_wires; + int8_t x, y, z; + int8_t padding_0; +}); + +NPNR_PACKED_STRUCT(struct BelPortPOD { + int32_t bel_index; + int32_t port; +}); + +NPNR_PACKED_STRUCT(struct PipInfoPOD { + enum PipFlags : uint32_t + { + FLAG_NONE = 0, + FLAG_ROUTETHRU = 1, + FLAG_NOCARRY = 2 + }; + + // RelPtr name; + int32_t src, dst; + int32_t fast_delay; + int32_t slow_delay; + int8_t x, y; + int16_t src_seg, dst_seg; + int16_t switch_mask; + int32_t switch_index; + PipFlags flags; +}); + +NPNR_PACKED_STRUCT(struct WireSegmentPOD { + int8_t x, y; + int16_t index; +}); + +NPNR_PACKED_STRUCT(struct WireInfoPOD { + enum WireType : int8_t + { + WIRE_TYPE_NONE = 0, + WIRE_TYPE_GLB2LOCAL = 1, + WIRE_TYPE_GLB_NETWK = 2, + WIRE_TYPE_LOCAL = 3, + WIRE_TYPE_LUTFF_IN = 4, + WIRE_TYPE_LUTFF_IN_LUT = 5, + WIRE_TYPE_LUTFF_LOUT = 6, + WIRE_TYPE_LUTFF_OUT = 7, + WIRE_TYPE_LUTFF_COUT = 8, + WIRE_TYPE_LUTFF_GLOBAL = 9, + WIRE_TYPE_CARRY_IN_MUX = 10, + WIRE_TYPE_SP4_V = 11, + WIRE_TYPE_SP4_H = 12, + WIRE_TYPE_SP12_V = 13, + WIRE_TYPE_SP12_H = 14 + }; + + RelPtr name; + int32_t num_uphill, num_downhill; + RelPtr pips_uphill, pips_downhill; + + int32_t num_bel_pins; + RelPtr bel_pins; + + int32_t num_segments; + RelPtr segments; + + int32_t fast_delay; + int32_t slow_delay; + + int8_t x, y, z; + WireType type; +}); + +NPNR_PACKED_STRUCT(struct PackagePinPOD { + RelPtr name; + int32_t bel_index; +}); + +NPNR_PACKED_STRUCT(struct PackageInfoPOD { + RelPtr name; + int32_t num_pins; + RelPtr pins; +}); + +enum TileType : uint32_t +{ + TILE_NONE = 0, + TILE_LOGIC = 1, + TILE_IO = 2, + TILE_RAMB = 3, + TILE_RAMT = 4, + TILE_DSP0 = 5, + TILE_DSP1 = 6, + TILE_DSP2 = 7, + TILE_DSP3 = 8, + TILE_IPCON = 9 +}; + +NPNR_PACKED_STRUCT(struct ConfigBitPOD { int8_t row, col; }); + +NPNR_PACKED_STRUCT(struct ConfigEntryPOD { + RelPtr name; + int32_t num_bits; + RelPtr bits; +}); + +NPNR_PACKED_STRUCT(struct TileInfoPOD { + int8_t cols, rows; + int16_t num_config_entries; + RelPtr entries; +}); + +static const int max_switch_bits = 5; + +NPNR_PACKED_STRUCT(struct SwitchInfoPOD { + int32_t num_bits; + int32_t bel; + int8_t x, y; + ConfigBitPOD cbits[max_switch_bits]; +}); + +NPNR_PACKED_STRUCT(struct IerenInfoPOD { + int8_t iox, ioy, ioz; + int8_t ierx, iery, ierz; +}); + +NPNR_PACKED_STRUCT(struct BitstreamInfoPOD { + int32_t num_switches, num_ierens; + RelPtr tiles_nonrouting; + RelPtr switches; + RelPtr ierens; +}); + +NPNR_PACKED_STRUCT(struct BelConfigEntryPOD { + RelPtr entry_name; + RelPtr cbit_name; + int8_t x, y; + int16_t padding; +}); + +// Stores mapping between bel parameters and config bits, +// for extra cells where this mapping is non-trivial +NPNR_PACKED_STRUCT(struct BelConfigPOD { + int32_t bel_index; + int32_t num_entries; + RelPtr entries; +}); + +NPNR_PACKED_STRUCT(struct CellPathDelayPOD { + int32_t from_port; + int32_t to_port; + int32_t fast_delay; + int32_t slow_delay; +}); + +NPNR_PACKED_STRUCT(struct CellTimingPOD { + int32_t type; + int32_t num_paths; + RelPtr path_delays; +}); + +NPNR_PACKED_STRUCT(struct ChipInfoPOD { + int32_t width, height; + int32_t num_bels, num_wires, num_pips; + int32_t num_switches, num_belcfgs, num_packages; + int32_t num_timing_cells; + RelPtr bel_data; + RelPtr wire_data; + RelPtr pip_data; + RelPtr tile_grid; + RelPtr bits_info; + RelPtr bel_config; + RelPtr packages_data; + RelPtr cell_timing; +}); + +#if defined(_MSC_VER) +extern const char *chipdb_blob_384; +extern const char *chipdb_blob_1k; +extern const char *chipdb_blob_5k; +extern const char *chipdb_blob_8k; +#else +extern const char chipdb_blob_384[]; +extern const char chipdb_blob_1k[]; +extern const char chipdb_blob_5k[]; +extern const char chipdb_blob_8k[]; +#endif + +/************************ End of chipdb section. ************************/ + +struct BelIterator +{ + int cursor; + + BelIterator operator++() + { + cursor++; + return *this; + } + BelIterator operator++(int) + { + BelIterator prior(*this); + cursor++; + return prior; + } + + bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } + + bool operator==(const BelIterator &other) const { return cursor == other.cursor; } + + BelId operator*() const + { + BelId ret; + ret.index = cursor; + return ret; + } +}; + +struct BelRange +{ + BelIterator b, e; + BelIterator begin() const { return b; } + BelIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct BelPinIterator +{ + const BelPortPOD *ptr = nullptr; + + void operator++() { ptr++; } + bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } + + BelPin operator*() const + { + BelPin ret; + ret.bel.index = ptr->bel_index; + ret.pin = ptr->port; + return ret; + } +}; + +struct BelPinRange +{ + BelPinIterator b, e; + BelPinIterator begin() const { return b; } + BelPinIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct WireIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } + + WireId operator*() const + { + WireId ret; + ret.index = cursor; + return ret; + } +}; + +struct WireRange +{ + WireIterator b, e; + WireIterator begin() const { return b; } + WireIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct AllPipIterator +{ + int cursor = -1; + + void operator++() { cursor++; } + bool operator!=(const AllPipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = cursor; + return ret; + } +}; + +struct AllPipRange +{ + AllPipIterator b, e; + AllPipIterator begin() const { return b; } + AllPipIterator end() const { return e; } +}; + +// ----------------------------------------------------------------------- + +struct PipIterator +{ + const int *cursor = nullptr; + + void operator++() { cursor++; } + bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } + + PipId operator*() const + { + PipId ret; + ret.index = *cursor; + return ret; + } +}; + +struct PipRange +{ + PipIterator b, e; + PipIterator begin() const { return b; } + PipIterator end() const { return e; } +}; + +struct ArchArgs +{ + enum ArchArgsTypes + { + NONE, + LP384, + LP1K, + LP8K, + HX1K, + HX8K, + UP5K + } type = NONE; + std::string package; +}; + +struct Arch : BaseCtx +{ + bool fast_part; + const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; + + mutable std::unordered_map bel_by_name; + mutable std::unordered_map wire_by_name; + mutable std::unordered_map pip_by_name; + mutable std::unordered_map bel_by_loc; + + std::vector bel_carry; + std::vector bel_to_cell; + std::vector wire_to_net; + std::vector pip_to_net; + std::vector switches_locked; + + ArchArgs args; + Arch(ArchArgs args); + + std::string getChipName() const; + + IdString archId() const { return id("ice40"); } + ArchArgs archArgs() const { return args; } + IdString archArgsToId(ArchArgs args) const; + + // ------------------------------------------------- + + int getGridDimX() const { return 34; } + int getGridDimY() const { return 34; } + int getTileBelDimZ(int, int) const { return 8; } + int getTilePipDimZ(int, int) const { return 1; } + + // ------------------------------------------------- + + BelId getBelByName(IdString name) const; + + IdString getBelName(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return id(chip_info->bel_data[bel.index].name.get()); + } + + uint32_t getBelChecksum(BelId bel) const { return bel.index; } + + void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] == nullptr); + + bel_to_cell[bel.index] = cell; + bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable); + cell->bel = bel; + cell->belStrength = strength; + refreshUiBel(bel); + } + + void unbindBel(BelId bel) + { + NPNR_ASSERT(bel != BelId()); + NPNR_ASSERT(bel_to_cell[bel.index] != nullptr); + bel_to_cell[bel.index]->bel = BelId(); + bel_to_cell[bel.index]->belStrength = STRENGTH_NONE; + bel_to_cell[bel.index] = nullptr; + bel_carry[bel.index] = false; + refreshUiBel(bel); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index] == nullptr; + } + + CellInfo *getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + CellInfo *getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + BelRange getBels() const + { + BelRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_bels; + return range; + } + + Loc getBelLocation(BelId bel) const + { + Loc loc; + loc.x = chip_info->bel_data[bel.index].x; + loc.y = chip_info->bel_data[bel.index].y; + loc.z = chip_info->bel_data[bel.index].z; + return loc; + } + + BelId getBelByLocation(Loc loc) const; + BelRange getBelsByTile(int x, int y) const; + + bool getBelGlobalBuf(BelId bel) const { return chip_info->bel_data[bel.index].type == ID_SB_GB; } + + IdString getBelType(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return IdString(chip_info->bel_data[bel.index].type); + } + + WireId getBelPinWire(BelId bel, IdString pin) const; + PortType getBelPinType(BelId bel, IdString pin) const; + std::vector getBelPins(BelId bel) const; + + // ------------------------------------------------- + + WireId getWireByName(IdString name) const; + + IdString getWireName(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return id(chip_info->wire_data[wire.index].name.get()); + } + + IdString getWireType(WireId wire) const; + + uint32_t getWireChecksum(WireId wire) const { return wire.index; } + + void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] == nullptr); + wire_to_net[wire.index] = net; + net->wires[wire].pip = PipId(); + net->wires[wire].strength = strength; + refreshUiWire(wire); + } + + void unbindWire(WireId wire) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] != nullptr); + + auto &net_wires = wire_to_net[wire.index]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = nullptr; + switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + } + + net_wires.erase(it); + wire_to_net[wire.index] = nullptr; + refreshUiWire(wire); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == nullptr; + } + + NetInfo *getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + NetInfo *getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + DelayInfo getWireDelay(WireId wire) const + { + DelayInfo delay; + NPNR_ASSERT(wire != WireId()); + if (fast_part) + delay.delay = chip_info->wire_data[wire.index].fast_delay; + else + delay.delay = chip_info->wire_data[wire.index].slow_delay; + return delay; + } + + BelPinRange getWireBelPins(WireId wire) const + { + BelPinRange range; + NPNR_ASSERT(wire != WireId()); + range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); + range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; + return range; + } + + WireRange getWires() const + { + WireRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_wires; + return range; + } + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + + void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] == nullptr); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); + + pip_to_net[pip.index] = net; + switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] == nullptr); + wire_to_net[dst.index] = net; + net->wires[dst].pip = pip; + net->wires[dst].strength = strength; + refreshUiPip(pip); + refreshUiWire(dst); + } + + void unbindPip(PipId pip) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] != nullptr); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_ASSERT(wire_to_net[dst.index] != nullptr); + wire_to_net[dst.index] = nullptr; + pip_to_net[pip.index]->wires.erase(dst); + + pip_to_net[pip.index] = nullptr; + switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + refreshUiPip(pip); + refreshUiWire(dst); + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + auto &pi = chip_info->pip_data[pip.index]; + auto &si = chip_info->bits_info->switches[pi.switch_index]; + + if (switches_locked[pi.switch_index] != nullptr) + return false; + + if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { + NPNR_ASSERT(si.bel >= 0); + if (bel_to_cell[si.bel] != nullptr) + return false; + } + + if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { + NPNR_ASSERT(si.bel >= 0); + if (bel_carry[si.bel]) + return false; + } + + return true; + } + + NetInfo *getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net[pip.index]; + } + + NetInfo *getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + + AllPipRange getPips() const + { + AllPipRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_pips; + return range; + } + + Loc getPipLocation(PipId pip) const + { + Loc loc; + loc.x = chip_info->pip_data[pip.index].x; + loc.y = chip_info->pip_data[pip.index].y; + loc.z = 0; + return loc; + } + + IdString getPipName(PipId pip) const; + + IdString getPipType(PipId pip) const { return IdString(); } + + uint32_t getPipChecksum(PipId pip) const { return pip.index; } + + WireId getPipSrcWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = chip_info->pip_data[pip.index].src; + return wire; + } + + WireId getPipDstWire(PipId pip) const + { + WireId wire; + NPNR_ASSERT(pip != PipId()); + wire.index = chip_info->pip_data[pip.index].dst; + return wire; + } + + DelayInfo getPipDelay(PipId pip) const + { + DelayInfo delay; + NPNR_ASSERT(pip != PipId()); + if (fast_part) + delay.delay = chip_info->pip_data[pip.index].fast_delay; + else + delay.delay = chip_info->pip_data[pip.index].slow_delay; + return delay; + } + + PipRange getPipsDownhill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); + range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + return range; + } + + PipRange getPipsUphill(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); + range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + return range; + } + + PipRange getWireAliases(WireId wire) const + { + PipRange range; + NPNR_ASSERT(wire != WireId()); + range.b.cursor = nullptr; + range.e.cursor = nullptr; + return range; + } + + BelId getPackagePinBel(const std::string &pin) const; + std::string getBelPackagePin(BelId bel) const; + + // ------------------------------------------------- + + GroupId getGroupByName(IdString name) const; + IdString getGroupName(GroupId group) const; + std::vector getGroups() const; + std::vector getGroupBels(GroupId group) const; + std::vector getGroupWires(GroupId group) const; + std::vector getGroupPips(GroupId group) const; + std::vector getGroupGroups(GroupId group) const; + + // ------------------------------------------------- + + delay_t estimateDelay(WireId src, WireId dst) const; + delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const; + delay_t getDelayEpsilon() const { return 20; } + delay_t getRipupDelayPenalty() const { return 200; } + float getDelayNS(delay_t v) const { return v * 0.001; } + uint32_t getDelayChecksum(delay_t v) const { return v; } + bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; + + // ------------------------------------------------- + + bool pack(); + bool place(); + bool route(); + + // ------------------------------------------------- + + std::vector getDecalGraphics(DecalId decal) const; + + DecalXY getBelDecal(BelId bel) const; + DecalXY getWireDecal(WireId wire) const; + DecalXY getPipDecal(PipId pip) const; + DecalXY getGroupDecal(GroupId group) const; + + // ------------------------------------------------- + + // Get the delay through a cell from one port to another, returning false + // if no path exists + bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; + // Get the port class, also setting clockDomain if applicable + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockDomain) const; + // Return true if a port is a net + bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + + // Perform placement validity checks, returning false on failure (all + // implemented in arch_place.cc) + + // 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(CellInfo *cell, BelId bel) const; + + // Return true whether all Bels at a given location are valid + bool isBelLocationValid(BelId bel) const; + + // Helper function for above + bool logicCellsCompatible(const CellInfo** it, const size_t size) const; + + // ------------------------------------------------- + // Assign architecure-specific arguments to nets and cells, which must be + // called between packing or further + // netlist modifications, and validity checks + void assignArchInfo(); + void assignCellInfo(CellInfo *cell); + + // ------------------------------------------------- + BelPin getIOBSharingPLLPin(BelId pll, IdString pll_pin) const + { + auto wire = getBelPinWire(pll, pll_pin); + for (auto src_bel : getWireBelPins(wire)) { + if (getBelType(src_bel.bel) == id_SB_IO && src_bel.pin == id_D_IN_0) { + return src_bel; + } + } + NPNR_ASSERT_FALSE("Expected PLL pin to share an output with an SB_IO D_IN_{0,1}"); + } + + float placer_constraintWeight = 10; +}; + +void ice40DelayFuzzerMain(Context *ctx); + +NEXTPNR_NAMESPACE_END diff --git a/xc7/arch_place.cc b/xc7/arch_place.cc new file mode 100644 index 00000000..c69fd34f --- /dev/null +++ b/xc7/arch_place.cc @@ -0,0 +1,162 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski + * + * 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 "cells.h" +#include "nextpnr.h" +#include "util.h" + +#include + +NEXTPNR_NAMESPACE_BEGIN + +bool Arch::logicCellsCompatible(const CellInfo** it, const size_t size) const +{ + bool dffs_exist = false, dffs_neg = false; + const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; + int locals_count = 0; + + for (auto cell : boost::make_iterator_range(it, it+size)) { + NPNR_ASSERT(cell->belType == id_ICESTORM_LC); + if (cell->lcInfo.dffEnable) { + if (!dffs_exist) { + dffs_exist = true; + cen = cell->lcInfo.cen; + clk = cell->lcInfo.clk; + sr = cell->lcInfo.sr; + + if (cen != nullptr && !cen->is_global) + locals_count++; + if (clk != nullptr && !clk->is_global) + locals_count++; + if (sr != nullptr && !sr->is_global) + locals_count++; + + if (cell->lcInfo.negClk) { + dffs_neg = true; + } + } else { + if (cen != cell->lcInfo.cen) + return false; + if (clk != cell->lcInfo.clk) + return false; + if (sr != cell->lcInfo.sr) + return false; + if (dffs_neg != cell->lcInfo.negClk) + return false; + } + } + + locals_count += cell->lcInfo.inputCount; + } + + return locals_count <= 32; +} + +bool Arch::isBelLocationValid(BelId bel) const +{ + if (getBelType(bel) == id_ICESTORM_LC) { + std::array bel_cells; + size_t num_cells = 0; + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { + CellInfo *ci_other = getBoundBelCell(bel_other); + if (ci_other != nullptr) + bel_cells[num_cells++] = ci_other; + } + return logicCellsCompatible(bel_cells.data(), num_cells); + } else { + CellInfo *ci = getBoundBelCell(bel); + if (ci == nullptr) + return true; + else + return isValidBelForCell(ci, bel); + } +} + +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const +{ + if (cell->type == id_ICESTORM_LC) { + NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); + + std::array bel_cells; + size_t num_cells = 0; + + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { + CellInfo *ci_other = getBoundBelCell(bel_other); + if (ci_other != nullptr && bel_other != bel) + bel_cells[num_cells++] = ci_other; + } + + bel_cells[num_cells++] = cell; + return logicCellsCompatible(bel_cells.data(), num_cells); + } else if (cell->type == id_SB_IO) { + // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. + + // Find shared PLL by looking for driving bel siblings from D_IN_0 + // that are a PLL clock output. + auto wire = getBelPinWire(bel, id_D_IN_0); + IdString pll_bel_pin; + BelId pll_bel; + for (auto pin : getWireBelPins(wire)) { + if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { + pll_bel = pin.bel; + pll_bel_pin = pin.pin; + break; + } + } + // Is there a PLL that shares this IO buffer? + if (pll_bel.index != -1) { + auto pll_cell = getBoundBelCell(pll_bel); + // Is a PLL placed in this PLL bel? + if (pll_cell != nullptr) { + // Is the shared port driving a net? + auto pi = pll_cell->ports[pll_bel_pin]; + if (pi.net != nullptr) { + // Are we perhaps a PAD INPUT Bel that can be placed here? + if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { + return true; + } + return false; + } + } + } + return getBelPackagePin(bel) != ""; + } else if (cell->type == id_SB_GB) { + NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); + const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; + IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); + int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); + if (net->is_reset && net->is_enable) + return false; + else if (net->is_reset) + return (glb_id % 2) == 0; + else if (net->is_enable) + return (glb_id % 2) == 1; + else + return true; + } else { + // TODO: IO cell clock checks + return true; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/arch_pybindings.cc b/xc7/arch_pybindings.cc new file mode 100644 index 00000000..f1639ba6 --- /dev/null +++ b/xc7/arch_pybindings.cc @@ -0,0 +1,154 @@ +/* + * 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. + * + */ + +#ifndef NO_PYTHON + +#include "arch_pybindings.h" +#include "nextpnr.h" +#include "pybindings.h" + +NEXTPNR_NAMESPACE_BEGIN + +void arch_wrap_python() +{ + using namespace PythonConversion; + class_("ArchArgs").def_readwrite("type", &ArchArgs::type); + + enum_().type)>("iCE40Type") + .value("NONE", ArchArgs::NONE) + .value("LP384", ArchArgs::LP384) + .value("LP1K", ArchArgs::LP1K) + .value("LP8K", ArchArgs::LP8K) + .value("HX1K", ArchArgs::HX1K) + .value("HX8K", ArchArgs::HX8K) + .value("UP5K", ArchArgs::UP5K) + .export_values(); + + class_("BelId").def_readwrite("index", &BelId::index); + + class_("WireId").def_readwrite("index", &WireId::index); + + class_("PipId").def_readwrite("index", &PipId::index); + + class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); + + auto arch_cls = class_, boost::noncopyable>("Arch", init()); + auto ctx_cls = class_, boost::noncopyable>("Context", no_init) + .def("checksum", &Context::checksum) + .def("pack", &Context::pack) + .def("place", &Context::place) + .def("route", &Context::route); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBelType"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkBelAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBelChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingBelCell"); + fn_wrapper_0a>::def_wrap(ctx_cls, + "getBels"); + + fn_wrapper_2a, + conv_from_str, conv_from_str>::def_wrap(ctx_cls, "getBelPinWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getWireBelPins"); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getWireChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingWireNet"); + + fn_wrapper_0a>::def_wrap( + ctx_cls, "getWires"); + + fn_wrapper_0a>::def_wrap( + ctx_cls, "getPips"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipChecksum"); + fn_wrapper_3a_v, + addr_and_unwrap, pass_through>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a, conv_from_str>::def_wrap(ctx_cls, "getConflictingPipNet"); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipsDownhill"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipsUphill"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getWireAliases"); + + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipSrcWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipDstWire"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getPipDelay"); + + fn_wrapper_1a, + pass_through>::def_wrap(ctx_cls, "getPackagePinBel"); + fn_wrapper_1a, + conv_from_str>::def_wrap(ctx_cls, "getBelPackagePin"); + + fn_wrapper_0a>::def_wrap( + ctx_cls, "getChipName"); + fn_wrapper_0a>::def_wrap(ctx_cls, + "archId"); + + typedef std::unordered_map> CellMap; + typedef std::unordered_map> NetMap; + + readonly_wrapper>::def_wrap(ctx_cls, + "cells"); + readonly_wrapper>::def_wrap(ctx_cls, + "nets"); + WRAP_RANGE(Bel, conv_to_str); + WRAP_RANGE(Wire, conv_to_str); + WRAP_RANGE(AllPip, conv_to_str); + WRAP_RANGE(Pip, conv_to_str); + + WRAP_MAP_UPTR(CellMap, "IdCellMap"); + WRAP_MAP_UPTR(NetMap, "IdNetMap"); +} + +NEXTPNR_NAMESPACE_END + +#endif // NO_PYTHON diff --git a/xc7/arch_pybindings.h b/xc7/arch_pybindings.h new file mode 100644 index 00000000..070c2396 --- /dev/null +++ b/xc7/arch_pybindings.h @@ -0,0 +1,62 @@ +/* + * 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. + * + */ +#ifndef ARCH_PYBINDINGS_H +#define ARCH_PYBINDINGS_H +#ifndef NO_PYTHON + +#include "nextpnr.h" +#include "pybindings.h" +#include "pywrappers.h" + +NEXTPNR_NAMESPACE_BEGIN + +namespace PythonConversion { + +template <> struct string_converter +{ + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + + std::string to_str(Context *ctx, BelId id) + { + if (id == BelId()) + throw bad_wrap(); + return ctx->getBelName(id).str(ctx); + } +}; + +template <> struct string_converter +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + + std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } +}; + +template <> struct string_converter +{ + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + + std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } +}; + +} // namespace PythonConversion + +NEXTPNR_NAMESPACE_END +#endif +#endif diff --git a/xc7/archdefs.h b/xc7/archdefs.h new file mode 100644 index 00000000..360617fd --- /dev/null +++ b/xc7/archdefs.h @@ -0,0 +1,194 @@ +/* + * 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 NEXTPNR_H +#error Include "archdefs.h" via "nextpnr.h" only. +#endif + +NEXTPNR_NAMESPACE_BEGIN + +typedef int delay_t; + +struct DelayInfo +{ + delay_t delay = 0; + + delay_t minRaiseDelay() const { return delay; } + delay_t maxRaiseDelay() const { return delay; } + + delay_t minFallDelay() const { return delay; } + delay_t maxFallDelay() const { return delay; } + + delay_t minDelay() const { return delay; } + delay_t maxDelay() const { return delay; } + + DelayInfo operator+(const DelayInfo &other) const + { + DelayInfo ret; + ret.delay = this->delay + other.delay; + return ret; + } +}; + +// ----------------------------------------------------------------------- + +enum ConstIds +{ + ID_NONE +#define X(t) , ID_##t +#include "constids.inc" +#undef X +}; + +#define X(t) static constexpr auto id_##t = IdString(ID_##t); +#include "constids.inc" +#undef X + +struct BelId +{ + int32_t index = -1; + + bool operator==(const BelId &other) const { return index == other.index; } + bool operator!=(const BelId &other) const { return index != other.index; } +}; + +struct WireId +{ + int32_t index = -1; + + bool operator==(const WireId &other) const { return index == other.index; } + bool operator!=(const WireId &other) const { return index != other.index; } +}; + +struct PipId +{ + int32_t index = -1; + + bool operator==(const PipId &other) const { return index == other.index; } + bool operator!=(const PipId &other) const { return index != other.index; } +}; + +struct GroupId +{ + enum : int8_t + { + TYPE_NONE, + TYPE_FRAME, + TYPE_MAIN_SW, + TYPE_LOCAL_SW, + TYPE_LC0_SW, + TYPE_LC1_SW, + TYPE_LC2_SW, + TYPE_LC3_SW, + TYPE_LC4_SW, + TYPE_LC5_SW, + TYPE_LC6_SW, + TYPE_LC7_SW + } type = TYPE_NONE; + int8_t x = 0, y = 0; + + bool operator==(const GroupId &other) const { return (type == other.type) && (x == other.x) && (y == other.y); } + bool operator!=(const GroupId &other) const { return (type != other.type) || (x != other.x) || (y == other.y); } +}; + +struct DecalId +{ + enum : int8_t + { + TYPE_NONE, + TYPE_BEL, + TYPE_WIRE, + TYPE_PIP, + TYPE_GROUP + } type = TYPE_NONE; + int32_t index = -1; + bool active = false; + + bool operator==(const DecalId &other) const { return (type == other.type) && (index == other.index); } + bool operator!=(const DecalId &other) const { return (type != other.type) || (index != other.index); } +}; + +struct ArchNetInfo +{ + bool is_global = false; + bool is_reset = false, is_enable = false; +}; + +struct NetInfo; + +struct ArchCellInfo +{ + IdString belType; + union + { + struct + { + bool dffEnable; + bool carryEnable; + bool negClk; + int inputCount; + const NetInfo *clk, *cen, *sr; + } lcInfo; + }; +}; + +NEXTPNR_NAMESPACE_END + +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash()(bel.index); } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept + { + return hash()(wire.index); + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash()(pip.index); } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(group.type)); + boost::hash_combine(seed, hash()(group.x)); + boost::hash_combine(seed, hash()(group.y)); + return seed; + } +}; + +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept + { + std::size_t seed = 0; + boost::hash_combine(seed, hash()(decal.type)); + boost::hash_combine(seed, hash()(decal.index)); + return seed; + } +}; +} // namespace std diff --git a/xc7/benchmark/.gitignore b/xc7/benchmark/.gitignore new file mode 100644 index 00000000..306b5c6e --- /dev/null +++ b/xc7/benchmark/.gitignore @@ -0,0 +1,6 @@ +hx8kdemo.log +hx8kdemo.blif +hx8kdemo.json +hx8kdemo_[an][0-9].asc +hx8kdemo_[an][0-9].log +report_[an][0-9].txt diff --git a/xc7/benchmark/hx8kdemo.pcf b/xc7/benchmark/hx8kdemo.pcf new file mode 100644 index 00000000..418bae89 --- /dev/null +++ b/xc7/benchmark/hx8kdemo.pcf @@ -0,0 +1,40 @@ + +# Pinout for the iCE40-HX8K Breakout Board + +set_io clk J3 + +set_io flash_csb R12 +set_io flash_clk R11 +set_io flash_io0 P12 +set_io flash_io1 P11 + +# for QSPI mode the flash chip on the iCE40-HX8K Breakout Board +# must be replaced with one that supports QSPI and the IO2 and IO3 +# pins must be soldered to T9 and P8 (center on J3) +set_io flash_io2 T9 +set_io flash_io3 P8 + +set_io ser_tx B12 +set_io ser_rx B10 + +# left on J3 +set_io debug_ser_tx T1 +set_io debug_ser_rx R3 + +# right on J3 +set_io debug_flash_csb T15 +set_io debug_flash_clk R16 +set_io debug_flash_io0 N12 +set_io debug_flash_io1 P13 +set_io debug_flash_io2 T13 +set_io debug_flash_io3 T14 + +set_io leds[7] B5 # D9 +set_io leds[6] B4 # D8 +set_io leds[5] A2 # D7 +set_io leds[4] A1 # D6 +set_io leds[3] C5 # D5 +set_io leds[2] C4 # D4 +set_io leds[1] B3 # D3 +set_io leds[0] C3 # D2 + diff --git a/xc7/benchmark/hx8kdemo.v b/xc7/benchmark/hx8kdemo.v new file mode 100644 index 00000000..9b784f8f --- /dev/null +++ b/xc7/benchmark/hx8kdemo.v @@ -0,0 +1,139 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 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. + * + */ + +module hx8kdemo ( + input clk, + + output ser_tx, + input ser_rx, + + output [7:0] leds, + + output flash_csb, + output flash_clk, + inout flash_io0, + inout flash_io1, + inout flash_io2, + inout flash_io3, + + output debug_ser_tx, + output debug_ser_rx, + + output debug_flash_csb, + output debug_flash_clk, + output debug_flash_io0, + output debug_flash_io1, + output debug_flash_io2, + output debug_flash_io3 +); + reg [5:0] reset_cnt = 0; + wire resetn = &reset_cnt; + + always @(posedge clk) begin + reset_cnt <= reset_cnt + !resetn; + end + + wire flash_io0_oe, flash_io0_do, flash_io0_di; + wire flash_io1_oe, flash_io1_do, flash_io1_di; + wire flash_io2_oe, flash_io2_do, flash_io2_di; + wire flash_io3_oe, flash_io3_do, flash_io3_di; + + SB_IO #( + .PIN_TYPE(6'b 1010_01), + .PULLUP(1'b 0) + ) flash_io_buf [3:0] ( + .PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}), + .OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}), + .D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}), + .D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}) + ); + + wire iomem_valid; + reg iomem_ready; + wire [3:0] iomem_wstrb; + wire [31:0] iomem_addr; + wire [31:0] iomem_wdata; + reg [31:0] iomem_rdata; + + reg [31:0] gpio; + assign leds = gpio; + + always @(posedge clk) begin + if (!resetn) begin + gpio <= 0; + end else begin + iomem_ready <= 0; + if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin + iomem_ready <= 1; + iomem_rdata <= gpio; + if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0]; + if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8]; + if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16]; + if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24]; + end + end + end + + picosoc soc ( + .clk (clk ), + .resetn (resetn ), + + .ser_tx (ser_tx ), + .ser_rx (ser_rx ), + + .flash_csb (flash_csb ), + .flash_clk (flash_clk ), + + .flash_io0_oe (flash_io0_oe), + .flash_io1_oe (flash_io1_oe), + .flash_io2_oe (flash_io2_oe), + .flash_io3_oe (flash_io3_oe), + + .flash_io0_do (flash_io0_do), + .flash_io1_do (flash_io1_do), + .flash_io2_do (flash_io2_do), + .flash_io3_do (flash_io3_do), + + .flash_io0_di (flash_io0_di), + .flash_io1_di (flash_io1_di), + .flash_io2_di (flash_io2_di), + .flash_io3_di (flash_io3_di), + + .irq_5 (1'b0 ), + .irq_6 (1'b0 ), + .irq_7 (1'b0 ), + + .iomem_valid (iomem_valid ), + .iomem_ready (iomem_ready ), + .iomem_wstrb (iomem_wstrb ), + .iomem_addr (iomem_addr ), + .iomem_wdata (iomem_wdata ), + .iomem_rdata (iomem_rdata ) + ); + + assign debug_ser_tx = ser_tx; + assign debug_ser_rx = ser_rx; + + assign debug_flash_csb = flash_csb; + assign debug_flash_clk = flash_clk; + assign debug_flash_io0 = flash_io0_di; + assign debug_flash_io1 = flash_io1_di; + assign debug_flash_io2 = flash_io2_di; + assign debug_flash_io3 = flash_io3_di; +endmodule diff --git a/xc7/benchmark/picorv32.v b/xc7/benchmark/picorv32.v new file mode 100644 index 00000000..af634b47 --- /dev/null +++ b/xc7/benchmark/picorv32.v @@ -0,0 +1,2977 @@ +/* + * PicoRV32 -- A Small RISC-V (RV32I) Processor Core + * + * Copyright (C) 2015 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. + * + */ + +`timescale 1 ns / 1 ps +// `default_nettype none +// `define DEBUGNETS +// `define DEBUGREGS +// `define DEBUGASM +// `define DEBUG + +`ifdef DEBUG + `define debug(debug_command) debug_command +`else + `define debug(debug_command) +`endif + +`ifdef FORMAL + `define FORMAL_KEEP (* keep *) + `define assert(assert_expr) assert(assert_expr) +`else + `ifdef DEBUGNETS + `define FORMAL_KEEP (* keep *) + `else + `define FORMAL_KEEP + `endif + `define assert(assert_expr) empty_statement +`endif + +// uncomment this for register file in extra module +// `define PICORV32_REGS picorv32_regs + +// this macro can be used to check if the verilog files in your +// design are read in the correct order. +`define PICORV32_V + + +/*************************************************************** + * picorv32 + ***************************************************************/ + +module picorv32 #( + parameter [ 0:0] ENABLE_COUNTERS = 1, + parameter [ 0:0] ENABLE_COUNTERS64 = 1, + parameter [ 0:0] ENABLE_REGS_16_31 = 1, + parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, + parameter [ 0:0] LATCHED_MEM_RDATA = 0, + parameter [ 0:0] TWO_STAGE_SHIFT = 1, + parameter [ 0:0] BARREL_SHIFTER = 0, + parameter [ 0:0] TWO_CYCLE_COMPARE = 0, + parameter [ 0:0] TWO_CYCLE_ALU = 0, + parameter [ 0:0] COMPRESSED_ISA = 0, + parameter [ 0:0] CATCH_MISALIGN = 1, + parameter [ 0:0] CATCH_ILLINSN = 1, + parameter [ 0:0] ENABLE_PCPI = 0, + parameter [ 0:0] ENABLE_MUL = 0, + parameter [ 0:0] ENABLE_FAST_MUL = 0, + parameter [ 0:0] ENABLE_DIV = 0, + parameter [ 0:0] ENABLE_IRQ = 0, + parameter [ 0:0] ENABLE_IRQ_QREGS = 1, + parameter [ 0:0] ENABLE_IRQ_TIMER = 1, + parameter [ 0:0] ENABLE_TRACE = 0, + parameter [ 0:0] REGS_INIT_ZERO = 0, + parameter [31:0] MASKED_IRQ = 32'h 0000_0000, + parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, + parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, + parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, + parameter [31:0] STACKADDR = 32'h ffff_ffff +) ( + input clk, resetn, + output reg trap, + + output reg mem_valid, + output reg mem_instr, + input mem_ready, + + output reg [31:0] mem_addr, + output reg [31:0] mem_wdata, + output reg [ 3:0] mem_wstrb, + input [31:0] mem_rdata, + + // Look-Ahead Interface + output mem_la_read, + output mem_la_write, + output [31:0] mem_la_addr, + output reg [31:0] mem_la_wdata, + output reg [ 3:0] mem_la_wstrb, + + // Pico Co-Processor Interface (PCPI) + output reg pcpi_valid, + output reg [31:0] pcpi_insn, + output [31:0] pcpi_rs1, + output [31:0] pcpi_rs2, + input pcpi_wr, + input [31:0] pcpi_rd, + input pcpi_wait, + input pcpi_ready, + + // IRQ Interface + input [31:0] irq, + output reg [31:0] eoi, + +`ifdef RISCV_FORMAL + output reg rvfi_valid, + output reg [63:0] rvfi_order, + output reg [31:0] rvfi_insn, + output reg rvfi_trap, + output reg rvfi_halt, + output reg rvfi_intr, + output reg [ 4:0] rvfi_rs1_addr, + output reg [ 4:0] rvfi_rs2_addr, + output reg [31:0] rvfi_rs1_rdata, + output reg [31:0] rvfi_rs2_rdata, + output reg [ 4:0] rvfi_rd_addr, + output reg [31:0] rvfi_rd_wdata, + output reg [31:0] rvfi_pc_rdata, + output reg [31:0] rvfi_pc_wdata, + output reg [31:0] rvfi_mem_addr, + output reg [ 3:0] rvfi_mem_rmask, + output reg [ 3:0] rvfi_mem_wmask, + output reg [31:0] rvfi_mem_rdata, + output reg [31:0] rvfi_mem_wdata, +`endif + + // Trace Interface + output reg trace_valid, + output reg [35:0] trace_data +); + localparam integer irq_timer = 0; + localparam integer irq_ebreak = 1; + localparam integer irq_buserror = 2; + + localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16; + localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS; + localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS; + + localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV; + + localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0}; + localparam [35:0] TRACE_ADDR = {4'b 0010, 32'b 0}; + localparam [35:0] TRACE_IRQ = {4'b 1000, 32'b 0}; + + reg [63:0] count_cycle, count_instr; + reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; + reg [4:0] reg_sh; + + reg [31:0] next_insn_opcode; + reg [31:0] dbg_insn_opcode; + reg [31:0] dbg_insn_addr; + + wire dbg_mem_valid = mem_valid; + wire dbg_mem_instr = mem_instr; + wire dbg_mem_ready = mem_ready; + wire [31:0] dbg_mem_addr = mem_addr; + wire [31:0] dbg_mem_wdata = mem_wdata; + wire [ 3:0] dbg_mem_wstrb = mem_wstrb; + wire [31:0] dbg_mem_rdata = mem_rdata; + + assign pcpi_rs1 = reg_op1; + assign pcpi_rs2 = reg_op2; + + wire [31:0] next_pc; + + reg irq_delay; + reg irq_active; + reg [31:0] irq_mask; + reg [31:0] irq_pending; + reg [31:0] timer; + +`ifndef PICORV32_REGS + reg [31:0] cpuregs [0:regfile_size-1]; + + integer i; + initial begin + if (REGS_INIT_ZERO) begin + for (i = 0; i < regfile_size; i = i+1) + cpuregs[i] = 0; + end + end +`endif + + task empty_statement; + // This task is used by the `assert directive in non-formal mode to + // avoid empty statement (which are unsupported by plain Verilog syntax). + begin end + endtask + +`ifdef DEBUGREGS + wire [31:0] dbg_reg_x0 = 0; + wire [31:0] dbg_reg_x1 = cpuregs[1]; + wire [31:0] dbg_reg_x2 = cpuregs[2]; + wire [31:0] dbg_reg_x3 = cpuregs[3]; + wire [31:0] dbg_reg_x4 = cpuregs[4]; + wire [31:0] dbg_reg_x5 = cpuregs[5]; + wire [31:0] dbg_reg_x6 = cpuregs[6]; + wire [31:0] dbg_reg_x7 = cpuregs[7]; + wire [31:0] dbg_reg_x8 = cpuregs[8]; + wire [31:0] dbg_reg_x9 = cpuregs[9]; + wire [31:0] dbg_reg_x10 = cpuregs[10]; + wire [31:0] dbg_reg_x11 = cpuregs[11]; + wire [31:0] dbg_reg_x12 = cpuregs[12]; + wire [31:0] dbg_reg_x13 = cpuregs[13]; + wire [31:0] dbg_reg_x14 = cpuregs[14]; + wire [31:0] dbg_reg_x15 = cpuregs[15]; + wire [31:0] dbg_reg_x16 = cpuregs[16]; + wire [31:0] dbg_reg_x17 = cpuregs[17]; + wire [31:0] dbg_reg_x18 = cpuregs[18]; + wire [31:0] dbg_reg_x19 = cpuregs[19]; + wire [31:0] dbg_reg_x20 = cpuregs[20]; + wire [31:0] dbg_reg_x21 = cpuregs[21]; + wire [31:0] dbg_reg_x22 = cpuregs[22]; + wire [31:0] dbg_reg_x23 = cpuregs[23]; + wire [31:0] dbg_reg_x24 = cpuregs[24]; + wire [31:0] dbg_reg_x25 = cpuregs[25]; + wire [31:0] dbg_reg_x26 = cpuregs[26]; + wire [31:0] dbg_reg_x27 = cpuregs[27]; + wire [31:0] dbg_reg_x28 = cpuregs[28]; + wire [31:0] dbg_reg_x29 = cpuregs[29]; + wire [31:0] dbg_reg_x30 = cpuregs[30]; + wire [31:0] dbg_reg_x31 = cpuregs[31]; +`endif + + // Internal PCPI Cores + + wire pcpi_mul_wr; + wire [31:0] pcpi_mul_rd; + wire pcpi_mul_wait; + wire pcpi_mul_ready; + + wire pcpi_div_wr; + wire [31:0] pcpi_div_rd; + wire pcpi_div_wait; + wire pcpi_div_ready; + + reg pcpi_int_wr; + reg [31:0] pcpi_int_rd; + reg pcpi_int_wait; + reg pcpi_int_ready; + + generate if (ENABLE_FAST_MUL) begin + picorv32_pcpi_fast_mul pcpi_mul ( + .clk (clk ), + .resetn (resetn ), + .pcpi_valid(pcpi_valid ), + .pcpi_insn (pcpi_insn ), + .pcpi_rs1 (pcpi_rs1 ), + .pcpi_rs2 (pcpi_rs2 ), + .pcpi_wr (pcpi_mul_wr ), + .pcpi_rd (pcpi_mul_rd ), + .pcpi_wait (pcpi_mul_wait ), + .pcpi_ready(pcpi_mul_ready ) + ); + end else if (ENABLE_MUL) begin + picorv32_pcpi_mul pcpi_mul ( + .clk (clk ), + .resetn (resetn ), + .pcpi_valid(pcpi_valid ), + .pcpi_insn (pcpi_insn ), + .pcpi_rs1 (pcpi_rs1 ), + .pcpi_rs2 (pcpi_rs2 ), + .pcpi_wr (pcpi_mul_wr ), + .pcpi_rd (pcpi_mul_rd ), + .pcpi_wait (pcpi_mul_wait ), + .pcpi_ready(pcpi_mul_ready ) + ); + end else begin + assign pcpi_mul_wr = 0; + assign pcpi_mul_rd = 32'bx; + assign pcpi_mul_wait = 0; + assign pcpi_mul_ready = 0; + end endgenerate + + generate if (ENABLE_DIV) begin + picorv32_pcpi_div pcpi_div ( + .clk (clk ), + .resetn (resetn ), + .pcpi_valid(pcpi_valid ), + .pcpi_insn (pcpi_insn ), + .pcpi_rs1 (pcpi_rs1 ), + .pcpi_rs2 (pcpi_rs2 ), + .pcpi_wr (pcpi_div_wr ), + .pcpi_rd (pcpi_div_rd ), + .pcpi_wait (pcpi_div_wait ), + .pcpi_ready(pcpi_div_ready ) + ); + end else begin + assign pcpi_div_wr = 0; + assign pcpi_div_rd = 32'bx; + assign pcpi_div_wait = 0; + assign pcpi_div_ready = 0; + end endgenerate + + always @* begin + pcpi_int_wr = 0; + pcpi_int_rd = 32'bx; + pcpi_int_wait = |{ENABLE_PCPI && pcpi_wait, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait, ENABLE_DIV && pcpi_div_wait}; + pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready}; + + (* parallel_case *) + case (1'b1) + ENABLE_PCPI && pcpi_ready: begin + pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0; + pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0; + end + (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin + pcpi_int_wr = pcpi_mul_wr; + pcpi_int_rd = pcpi_mul_rd; + end + ENABLE_DIV && pcpi_div_ready: begin + pcpi_int_wr = pcpi_div_wr; + pcpi_int_rd = pcpi_div_rd; + end + endcase + end + + + // Memory Interface + + reg [1:0] mem_state; + reg [1:0] mem_wordsize; + reg [31:0] mem_rdata_word; + reg [31:0] mem_rdata_q; + reg mem_do_prefetch; + reg mem_do_rinst; + reg mem_do_rdata; + reg mem_do_wdata; + + wire mem_xfer; + reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid; + wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword; + wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg); + + reg prefetched_high_word; + reg clear_prefetched_high_word; + reg [15:0] mem_16bit_buffer; + + wire [31:0] mem_rdata_latched_noshuffle; + wire [31:0] mem_rdata_latched; + + wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word; + assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst); + + wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata}; + wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) && + (!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer)); + + assign mem_la_write = resetn && !mem_state && mem_do_wdata; + assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) || + (COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0])); + assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; + + assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q; + + assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} : + COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} : + COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle; + + always @(posedge clk) begin + if (!resetn) begin + mem_la_firstword_reg <= 0; + last_mem_valid <= 0; + end else begin + if (!last_mem_valid) + mem_la_firstword_reg <= mem_la_firstword; + last_mem_valid <= mem_valid && !mem_ready; + end + end + + always @* begin + (* full_case *) + case (mem_wordsize) + 0: begin + mem_la_wdata = reg_op2; + mem_la_wstrb = 4'b1111; + mem_rdata_word = mem_rdata; + end + 1: begin + mem_la_wdata = {2{reg_op2[15:0]}}; + mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; + case (reg_op1[1]) + 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; + 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; + endcase + end + 2: begin + mem_la_wdata = {4{reg_op2[7:0]}}; + mem_la_wstrb = 4'b0001 << reg_op1[1:0]; + case (reg_op1[1:0]) + 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; + 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; + 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; + 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; + endcase + end + endcase + end + + always @(posedge clk) begin + if (mem_xfer) begin + mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; + next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; + end + + if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin + case (mem_rdata_latched[1:0]) + 2'b00: begin // Quadrant 0 + case (mem_rdata_latched[15:13]) + 3'b000: begin // C.ADDI4SPN + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00}; + end + 3'b010: begin // C.LW + mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; + mem_rdata_q[14:12] <= 3'b 010; + end + 3'b 110: begin // C.SW + {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; + mem_rdata_q[14:12] <= 3'b 010; + end + endcase + end + 2'b01: begin // Quadrant 1 + case (mem_rdata_latched[15:13]) + 3'b 000: begin // C.ADDI + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); + end + 3'b 010: begin // C.LI + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); + end + 3'b 011: begin + if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3], + mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000}); + end else begin // C.LUI + mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); + end + end + 3'b100: begin + if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI + mem_rdata_q[31:25] <= 7'b0000000; + mem_rdata_q[14:12] <= 3'b 101; + end + if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI + mem_rdata_q[31:25] <= 7'b0100000; + mem_rdata_q[14:12] <= 3'b 101; + end + if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI + mem_rdata_q[14:12] <= 3'b111; + mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); + end + if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND + if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000; + if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100; + if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110; + if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111; + mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000; + end + end + 3'b 110: begin // C.BEQZ + mem_rdata_q[14:12] <= 3'b000; + { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= + $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], + mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); + end + 3'b 111: begin // C.BNEZ + mem_rdata_q[14:12] <= 3'b001; + { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= + $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], + mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); + end + endcase + end + 2'b10: begin // Quadrant 2 + case (mem_rdata_latched[15:13]) + 3'b000: begin // C.SLLI + mem_rdata_q[31:25] <= 7'b0000000; + mem_rdata_q[14:12] <= 3'b 001; + end + 3'b010: begin // C.LWSP + mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00}; + mem_rdata_q[14:12] <= 3'b 010; + end + 3'b100: begin + if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= 12'b0; + end + if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:25] <= 7'b0000000; + end + if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:20] <= 12'b0; + end + if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD + mem_rdata_q[14:12] <= 3'b000; + mem_rdata_q[31:25] <= 7'b0000000; + end + end + 3'b110: begin // C.SWSP + {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00}; + mem_rdata_q[14:12] <= 3'b 010; + end + endcase + end + endcase + end + end + + always @(posedge clk) begin + if (resetn && !trap) begin + if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) + `assert(!mem_do_wdata); + + if (mem_do_prefetch || mem_do_rinst) + `assert(!mem_do_rdata); + + if (mem_do_rdata) + `assert(!mem_do_prefetch && !mem_do_rinst); + + if (mem_do_wdata) + `assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata)); + + if (mem_state == 2 || mem_state == 3) + `assert(mem_valid || mem_do_prefetch); + end + end + + always @(posedge clk) begin + if (!resetn || trap) begin + if (!resetn) + mem_state <= 0; + if (!resetn || mem_ready) + mem_valid <= 0; + mem_la_secondword <= 0; + prefetched_high_word <= 0; + end else begin + if (mem_la_read || mem_la_write) begin + mem_addr <= mem_la_addr; + mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; + end + if (mem_la_write) begin + mem_wdata <= mem_la_wdata; + end + case (mem_state) + 0: begin + if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin + mem_valid <= !mem_la_use_prefetched_high_word; + mem_instr <= mem_do_prefetch || mem_do_rinst; + mem_wstrb <= 0; + mem_state <= 1; + end + if (mem_do_wdata) begin + mem_valid <= 1; + mem_instr <= 0; + mem_state <= 2; + end + end + 1: begin + `assert(mem_wstrb == 0); + `assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata); + `assert(mem_valid == !mem_la_use_prefetched_high_word); + `assert(mem_instr == (mem_do_prefetch || mem_do_rinst)); + if (mem_xfer) begin + if (COMPRESSED_ISA && mem_la_read) begin + mem_valid <= 1; + mem_la_secondword <= 1; + if (!mem_la_use_prefetched_high_word) + mem_16bit_buffer <= mem_rdata[31:16]; + end else begin + mem_valid <= 0; + mem_la_secondword <= 0; + if (COMPRESSED_ISA && !mem_do_rdata) begin + if (~&mem_rdata[1:0] || mem_la_secondword) begin + mem_16bit_buffer <= mem_rdata[31:16]; + prefetched_high_word <= 1; + end else begin + prefetched_high_word <= 0; + end + end + mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3; + end + end + end + 2: begin + `assert(mem_wstrb != 0); + `assert(mem_do_wdata); + if (mem_xfer) begin + mem_valid <= 0; + mem_state <= 0; + end + end + 3: begin + `assert(mem_wstrb == 0); + `assert(mem_do_prefetch); + if (mem_do_rinst) begin + mem_state <= 0; + end + end + endcase + end + + if (clear_prefetched_high_word) + prefetched_high_word <= 0; + end + + + // Instruction Decoder + + reg instr_lui, instr_auipc, instr_jal, instr_jalr; + reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu; + reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw; + reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai; + reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and; + reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak; + reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer; + wire instr_trap; + + reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2; + reg [31:0] decoded_imm, decoded_imm_uj; + reg decoder_trigger; + reg decoder_trigger_q; + reg decoder_pseudo_trigger; + reg decoder_pseudo_trigger_q; + reg compressed_instr; + + reg is_lui_auipc_jal; + reg is_lb_lh_lw_lbu_lhu; + reg is_slli_srli_srai; + reg is_jalr_addi_slti_sltiu_xori_ori_andi; + reg is_sb_sh_sw; + reg is_sll_srl_sra; + reg is_lui_auipc_jal_jalr_addi_add_sub; + reg is_slti_blt_slt; + reg is_sltiu_bltu_sltu; + reg is_beq_bne_blt_bge_bltu_bgeu; + reg is_lbu_lhu_lw; + reg is_alu_reg_imm; + reg is_alu_reg_reg; + reg is_compare; + + assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr, + instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu, + instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw, + instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai, + instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and, + instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, + instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer}; + + wire is_rdcycle_rdcycleh_rdinstr_rdinstrh; + assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh}; + + reg [63:0] new_ascii_instr; + `FORMAL_KEEP reg [63:0] dbg_ascii_instr; + `FORMAL_KEEP reg [31:0] dbg_insn_imm; + `FORMAL_KEEP reg [4:0] dbg_insn_rs1; + `FORMAL_KEEP reg [4:0] dbg_insn_rs2; + `FORMAL_KEEP reg [4:0] dbg_insn_rd; + `FORMAL_KEEP reg [31:0] dbg_rs1val; + `FORMAL_KEEP reg [31:0] dbg_rs2val; + `FORMAL_KEEP reg dbg_rs1val_valid; + `FORMAL_KEEP reg dbg_rs2val_valid; + + always @* begin + new_ascii_instr = ""; + + if (instr_lui) new_ascii_instr = "lui"; + if (instr_auipc) new_ascii_instr = "auipc"; + if (instr_jal) new_ascii_instr = "jal"; + if (instr_jalr) new_ascii_instr = "jalr"; + + if (instr_beq) new_ascii_instr = "beq"; + if (instr_bne) new_ascii_instr = "bne"; + if (instr_blt) new_ascii_instr = "blt"; + if (instr_bge) new_ascii_instr = "bge"; + if (instr_bltu) new_ascii_instr = "bltu"; + if (instr_bgeu) new_ascii_instr = "bgeu"; + + if (instr_lb) new_ascii_instr = "lb"; + if (instr_lh) new_ascii_instr = "lh"; + if (instr_lw) new_ascii_instr = "lw"; + if (instr_lbu) new_ascii_instr = "lbu"; + if (instr_lhu) new_ascii_instr = "lhu"; + if (instr_sb) new_ascii_instr = "sb"; + if (instr_sh) new_ascii_instr = "sh"; + if (instr_sw) new_ascii_instr = "sw"; + + if (instr_addi) new_ascii_instr = "addi"; + if (instr_slti) new_ascii_instr = "slti"; + if (instr_sltiu) new_ascii_instr = "sltiu"; + if (instr_xori) new_ascii_instr = "xori"; + if (instr_ori) new_ascii_instr = "ori"; + if (instr_andi) new_ascii_instr = "andi"; + if (instr_slli) new_ascii_instr = "slli"; + if (instr_srli) new_ascii_instr = "srli"; + if (instr_srai) new_ascii_instr = "srai"; + + if (instr_add) new_ascii_instr = "add"; + if (instr_sub) new_ascii_instr = "sub"; + if (instr_sll) new_ascii_instr = "sll"; + if (instr_slt) new_ascii_instr = "slt"; + if (instr_sltu) new_ascii_instr = "sltu"; + if (instr_xor) new_ascii_instr = "xor"; + if (instr_srl) new_ascii_instr = "srl"; + if (instr_sra) new_ascii_instr = "sra"; + if (instr_or) new_ascii_instr = "or"; + if (instr_and) new_ascii_instr = "and"; + + if (instr_rdcycle) new_ascii_instr = "rdcycle"; + if (instr_rdcycleh) new_ascii_instr = "rdcycleh"; + if (instr_rdinstr) new_ascii_instr = "rdinstr"; + if (instr_rdinstrh) new_ascii_instr = "rdinstrh"; + + if (instr_getq) new_ascii_instr = "getq"; + if (instr_setq) new_ascii_instr = "setq"; + if (instr_retirq) new_ascii_instr = "retirq"; + if (instr_maskirq) new_ascii_instr = "maskirq"; + if (instr_waitirq) new_ascii_instr = "waitirq"; + if (instr_timer) new_ascii_instr = "timer"; + end + + reg [63:0] q_ascii_instr; + reg [31:0] q_insn_imm; + reg [31:0] q_insn_opcode; + reg [4:0] q_insn_rs1; + reg [4:0] q_insn_rs2; + reg [4:0] q_insn_rd; + reg dbg_next; + + wire launch_next_insn; + reg dbg_valid_insn; + + reg [63:0] cached_ascii_instr; + reg [31:0] cached_insn_imm; + reg [31:0] cached_insn_opcode; + reg [4:0] cached_insn_rs1; + reg [4:0] cached_insn_rs2; + reg [4:0] cached_insn_rd; + + always @(posedge clk) begin + q_ascii_instr <= dbg_ascii_instr; + q_insn_imm <= dbg_insn_imm; + q_insn_opcode <= dbg_insn_opcode; + q_insn_rs1 <= dbg_insn_rs1; + q_insn_rs2 <= dbg_insn_rs2; + q_insn_rd <= dbg_insn_rd; + dbg_next <= launch_next_insn; + + if (!resetn || trap) + dbg_valid_insn <= 0; + else if (launch_next_insn) + dbg_valid_insn <= 1; + + if (decoder_trigger_q) begin + cached_ascii_instr <= new_ascii_instr; + cached_insn_imm <= decoded_imm; + if (&next_insn_opcode[1:0]) + cached_insn_opcode <= next_insn_opcode; + else + cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]}; + cached_insn_rs1 <= decoded_rs1; + cached_insn_rs2 <= decoded_rs2; + cached_insn_rd <= decoded_rd; + end + + if (launch_next_insn) begin + dbg_insn_addr <= next_pc; + end + end + + always @* begin + dbg_ascii_instr = q_ascii_instr; + dbg_insn_imm = q_insn_imm; + dbg_insn_opcode = q_insn_opcode; + dbg_insn_rs1 = q_insn_rs1; + dbg_insn_rs2 = q_insn_rs2; + dbg_insn_rd = q_insn_rd; + + if (dbg_next) begin + if (decoder_pseudo_trigger_q) begin + dbg_ascii_instr = cached_ascii_instr; + dbg_insn_imm = cached_insn_imm; + dbg_insn_opcode = cached_insn_opcode; + dbg_insn_rs1 = cached_insn_rs1; + dbg_insn_rs2 = cached_insn_rs2; + dbg_insn_rd = cached_insn_rd; + end else begin + dbg_ascii_instr = new_ascii_instr; + if (&next_insn_opcode[1:0]) + dbg_insn_opcode = next_insn_opcode; + else + dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]}; + dbg_insn_imm = decoded_imm; + dbg_insn_rs1 = decoded_rs1; + dbg_insn_rs2 = decoded_rs2; + dbg_insn_rd = decoded_rd; + end + end + end + +`ifdef DEBUGASM + always @(posedge clk) begin + if (dbg_next) begin + $display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*"); + end + end +`endif + +`ifdef DEBUG + always @(posedge clk) begin + if (dbg_next) begin + if (&dbg_insn_opcode[1:0]) + $display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); + else + $display("DECODE: 0x%08x 0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); + end + end +`endif + + always @(posedge clk) begin + is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal}; + is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub}; + is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt}; + is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu}; + is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw}; + is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu}; + + if (mem_do_rinst && mem_done) begin + instr_lui <= mem_rdata_latched[6:0] == 7'b0110111; + instr_auipc <= mem_rdata_latched[6:0] == 7'b0010111; + instr_jal <= mem_rdata_latched[6:0] == 7'b1101111; + instr_jalr <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000; + instr_retirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ; + instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ; + + is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011; + is_lb_lh_lw_lbu_lhu <= mem_rdata_latched[6:0] == 7'b0000011; + is_sb_sh_sw <= mem_rdata_latched[6:0] == 7'b0100011; + is_alu_reg_imm <= mem_rdata_latched[6:0] == 7'b0010011; + is_alu_reg_reg <= mem_rdata_latched[6:0] == 7'b0110011; + + { decoded_imm_uj[31:20], decoded_imm_uj[10:1], decoded_imm_uj[11], decoded_imm_uj[19:12], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[31:12], 1'b0}); + + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= mem_rdata_latched[19:15]; + decoded_rs2 <= mem_rdata_latched[24:20]; + + if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS) + decoded_rs1[regindex_bits-1] <= 1; // instr_getq + + if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ) + decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq + + compressed_instr <= 0; + if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin + compressed_instr <= 1; + decoded_rd <= 0; + decoded_rs1 <= 0; + decoded_rs2 <= 0; + + { decoded_imm_uj[31:11], decoded_imm_uj[4], decoded_imm_uj[9:8], decoded_imm_uj[10], decoded_imm_uj[6], + decoded_imm_uj[7], decoded_imm_uj[3:1], decoded_imm_uj[5], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[12:2], 1'b0}); + + case (mem_rdata_latched[1:0]) + 2'b00: begin // Quadrant 0 + case (mem_rdata_latched[15:13]) + 3'b000: begin // C.ADDI4SPN + is_alu_reg_imm <= |mem_rdata_latched[12:5]; + decoded_rs1 <= 2; + decoded_rd <= 8 + mem_rdata_latched[4:2]; + end + 3'b010: begin // C.LW + is_lb_lh_lw_lbu_lhu <= 1; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rd <= 8 + mem_rdata_latched[4:2]; + end + 3'b110: begin // C.SW + is_sb_sh_sw <= 1; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rs2 <= 8 + mem_rdata_latched[4:2]; + end + endcase + end + 2'b01: begin // Quadrant 1 + case (mem_rdata_latched[15:13]) + 3'b000: begin // C.NOP / C.ADDI + is_alu_reg_imm <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= mem_rdata_latched[11:7]; + end + 3'b001: begin // C.JAL + instr_jal <= 1; + decoded_rd <= 1; + end + 3'b 010: begin // C.LI + is_alu_reg_imm <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= 0; + end + 3'b 011: begin + if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin + if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP + is_alu_reg_imm <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= mem_rdata_latched[11:7]; + end else begin // C.LUI + instr_lui <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= 0; + end + end + end + 3'b100: begin + if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI + is_alu_reg_imm <= 1; + decoded_rd <= 8 + mem_rdata_latched[9:7]; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; + end + if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI + is_alu_reg_imm <= 1; + decoded_rd <= 8 + mem_rdata_latched[9:7]; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + end + if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND + is_alu_reg_reg <= 1; + decoded_rd <= 8 + mem_rdata_latched[9:7]; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rs2 <= 8 + mem_rdata_latched[4:2]; + end + end + 3'b101: begin // C.J + instr_jal <= 1; + end + 3'b110: begin // C.BEQZ + is_beq_bne_blt_bge_bltu_bgeu <= 1; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rs2 <= 0; + end + 3'b111: begin // C.BNEZ + is_beq_bne_blt_bge_bltu_bgeu <= 1; + decoded_rs1 <= 8 + mem_rdata_latched[9:7]; + decoded_rs2 <= 0; + end + endcase + end + 2'b10: begin // Quadrant 2 + case (mem_rdata_latched[15:13]) + 3'b000: begin // C.SLLI + if (!mem_rdata_latched[12]) begin + is_alu_reg_imm <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= mem_rdata_latched[11:7]; + decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; + end + end + 3'b010: begin // C.LWSP + if (mem_rdata_latched[11:7]) begin + is_lb_lh_lw_lbu_lhu <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= 2; + end + end + 3'b100: begin + if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR + instr_jalr <= 1; + decoded_rd <= 0; + decoded_rs1 <= mem_rdata_latched[11:7]; + end + if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV + is_alu_reg_reg <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= 0; + decoded_rs2 <= mem_rdata_latched[6:2]; + end + if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR + instr_jalr <= 1; + decoded_rd <= 1; + decoded_rs1 <= mem_rdata_latched[11:7]; + end + if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD + is_alu_reg_reg <= 1; + decoded_rd <= mem_rdata_latched[11:7]; + decoded_rs1 <= mem_rdata_latched[11:7]; + decoded_rs2 <= mem_rdata_latched[6:2]; + end + end + 3'b110: begin // C.SWSP + is_sb_sh_sw <= 1; + decoded_rs1 <= 2; + decoded_rs2 <= mem_rdata_latched[6:2]; + end + endcase + end + endcase + end + end + + if (decoder_trigger && !decoder_pseudo_trigger) begin + pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx; + + instr_beq <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000; + instr_bne <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001; + instr_blt <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100; + instr_bge <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101; + instr_bltu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110; + instr_bgeu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111; + + instr_lb <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000; + instr_lh <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001; + instr_lw <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010; + instr_lbu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100; + instr_lhu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101; + + instr_sb <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000; + instr_sh <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001; + instr_sw <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010; + + instr_addi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000; + instr_slti <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010; + instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011; + instr_xori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100; + instr_ori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110; + instr_andi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111; + + instr_slli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; + instr_srli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; + instr_srai <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; + + instr_add <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000; + instr_sub <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000; + instr_sll <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; + instr_slt <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000; + instr_sltu <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000; + instr_xor <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000; + instr_srl <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; + instr_sra <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; + instr_or <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000; + instr_and <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000; + + instr_rdcycle <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) || + (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS; + instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) || + (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64; + instr_rdinstr <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS; + instr_rdinstrh <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64; + + instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) || + (COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002)); + + instr_getq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS; + instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS; + instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ; + instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER; + + is_slli_srli_srai <= is_alu_reg_imm && |{ + mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, + mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, + mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 + }; + + is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{ + mem_rdata_q[14:12] == 3'b000, + mem_rdata_q[14:12] == 3'b010, + mem_rdata_q[14:12] == 3'b011, + mem_rdata_q[14:12] == 3'b100, + mem_rdata_q[14:12] == 3'b110, + mem_rdata_q[14:12] == 3'b111 + }; + + is_sll_srl_sra <= is_alu_reg_reg && |{ + mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, + mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, + mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 + }; + + is_lui_auipc_jal_jalr_addi_add_sub <= 0; + is_compare <= 0; + + (* parallel_case *) + case (1'b1) + instr_jal: + decoded_imm <= decoded_imm_uj; + |{instr_lui, instr_auipc}: + decoded_imm <= mem_rdata_q[31:12] << 12; + |{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}: + decoded_imm <= $signed(mem_rdata_q[31:20]); + is_beq_bne_blt_bge_bltu_bgeu: + decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0}); + is_sb_sh_sw: + decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]}); + default: + decoded_imm <= 1'bx; + endcase + end + + if (!resetn) begin + is_beq_bne_blt_bge_bltu_bgeu <= 0; + is_compare <= 0; + + instr_beq <= 0; + instr_bne <= 0; + instr_blt <= 0; + instr_bge <= 0; + instr_bltu <= 0; + instr_bgeu <= 0; + + instr_addi <= 0; + instr_slti <= 0; + instr_sltiu <= 0; + instr_xori <= 0; + instr_ori <= 0; + instr_andi <= 0; + + instr_add <= 0; + instr_sub <= 0; + instr_sll <= 0; + instr_slt <= 0; + instr_sltu <= 0; + instr_xor <= 0; + instr_srl <= 0; + instr_sra <= 0; + instr_or <= 0; + instr_and <= 0; + end + end + + + // Main State Machine + + localparam cpu_state_trap = 8'b10000000; + localparam cpu_state_fetch = 8'b01000000; + localparam cpu_state_ld_rs1 = 8'b00100000; + localparam cpu_state_ld_rs2 = 8'b00010000; + localparam cpu_state_exec = 8'b00001000; + localparam cpu_state_shift = 8'b00000100; + localparam cpu_state_stmem = 8'b00000010; + localparam cpu_state_ldmem = 8'b00000001; + + reg [7:0] cpu_state; + reg [1:0] irq_state; + + `FORMAL_KEEP reg [127:0] dbg_ascii_state; + + always @* begin + dbg_ascii_state = ""; + if (cpu_state == cpu_state_trap) dbg_ascii_state = "trap"; + if (cpu_state == cpu_state_fetch) dbg_ascii_state = "fetch"; + if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1"; + if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2"; + if (cpu_state == cpu_state_exec) dbg_ascii_state = "exec"; + if (cpu_state == cpu_state_shift) dbg_ascii_state = "shift"; + if (cpu_state == cpu_state_stmem) dbg_ascii_state = "stmem"; + if (cpu_state == cpu_state_ldmem) dbg_ascii_state = "ldmem"; + end + + reg set_mem_do_rinst; + reg set_mem_do_rdata; + reg set_mem_do_wdata; + + reg latched_store; + reg latched_stalu; + reg latched_branch; + reg latched_compr; + reg latched_trace; + reg latched_is_lu; + reg latched_is_lh; + reg latched_is_lb; + reg [regindex_bits-1:0] latched_rd; + + reg [31:0] current_pc; + assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc; + + reg [3:0] pcpi_timeout_counter; + reg pcpi_timeout; + + reg [31:0] next_irq_pending; + reg do_waitirq; + + reg [31:0] alu_out, alu_out_q; + reg alu_out_0, alu_out_0_q; + reg alu_wait, alu_wait_2; + + reg [31:0] alu_add_sub; + reg [31:0] alu_shl, alu_shr; + reg alu_eq, alu_ltu, alu_lts; + + generate if (TWO_CYCLE_ALU) begin + always @(posedge clk) begin + alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; + alu_eq <= reg_op1 == reg_op2; + alu_lts <= $signed(reg_op1) < $signed(reg_op2); + alu_ltu <= reg_op1 < reg_op2; + alu_shl <= reg_op1 << reg_op2[4:0]; + alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; + end + end else begin + always @* begin + alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; + alu_eq = reg_op1 == reg_op2; + alu_lts = $signed(reg_op1) < $signed(reg_op2); + alu_ltu = reg_op1 < reg_op2; + alu_shl = reg_op1 << reg_op2[4:0]; + alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; + end + end endgenerate + + always @* begin + alu_out_0 = 'bx; + (* parallel_case, full_case *) + case (1'b1) + instr_beq: + alu_out_0 = alu_eq; + instr_bne: + alu_out_0 = !alu_eq; + instr_bge: + alu_out_0 = !alu_lts; + instr_bgeu: + alu_out_0 = !alu_ltu; + is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): + alu_out_0 = alu_lts; + is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): + alu_out_0 = alu_ltu; + endcase + + alu_out = 'bx; + (* parallel_case, full_case *) + case (1'b1) + is_lui_auipc_jal_jalr_addi_add_sub: + alu_out = alu_add_sub; + is_compare: + alu_out = alu_out_0; + instr_xori || instr_xor: + alu_out = reg_op1 ^ reg_op2; + instr_ori || instr_or: + alu_out = reg_op1 | reg_op2; + instr_andi || instr_and: + alu_out = reg_op1 & reg_op2; + BARREL_SHIFTER && (instr_sll || instr_slli): + alu_out = alu_shl; + BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai): + alu_out = alu_shr; + endcase + +`ifdef RISCV_FORMAL_BLACKBOX_ALU + alu_out_0 = $anyseq; + alu_out = $anyseq; +`endif + end + + reg clear_prefetched_high_word_q; + always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word; + + always @* begin + clear_prefetched_high_word = clear_prefetched_high_word_q; + if (!prefetched_high_word) + clear_prefetched_high_word = 0; + if (latched_branch || irq_state || !resetn) + clear_prefetched_high_word = COMPRESSED_ISA; + end + + reg cpuregs_write; + reg [31:0] cpuregs_wrdata; + reg [31:0] cpuregs_rs1; + reg [31:0] cpuregs_rs2; + reg [regindex_bits-1:0] decoded_rs; + + always @* begin + cpuregs_write = 0; + cpuregs_wrdata = 'bx; + + if (cpu_state == cpu_state_fetch) begin + (* parallel_case *) + case (1'b1) + latched_branch: begin + cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4); + cpuregs_write = 1; + end + latched_store && !latched_branch: begin + cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out; + cpuregs_write = 1; + end + ENABLE_IRQ && irq_state[0]: begin + cpuregs_wrdata = reg_next_pc | latched_compr; + cpuregs_write = 1; + end + ENABLE_IRQ && irq_state[1]: begin + cpuregs_wrdata = irq_pending & ~irq_mask; + cpuregs_write = 1; + end + endcase + end + end + +`ifndef PICORV32_REGS + always @(posedge clk) begin + if (resetn && cpuregs_write && latched_rd) + cpuregs[latched_rd] <= cpuregs_wrdata; + end + + always @* begin + decoded_rs = 'bx; + if (ENABLE_REGS_DUALPORT) begin +`ifndef RISCV_FORMAL_BLACKBOX_REGS + cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0; + cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0; +`else + cpuregs_rs1 = decoded_rs1 ? $anyseq : 0; + cpuregs_rs2 = decoded_rs2 ? $anyseq : 0; +`endif + end else begin + decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; +`ifndef RISCV_FORMAL_BLACKBOX_REGS + cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0; +`else + cpuregs_rs1 = decoded_rs ? $anyseq : 0; +`endif + cpuregs_rs2 = cpuregs_rs1; + end + end +`else + wire[31:0] cpuregs_rdata1; + wire[31:0] cpuregs_rdata2; + + wire [5:0] cpuregs_waddr = latched_rd; + wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs; + wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0; + + `PICORV32_REGS cpuregs ( + .clk(clk), + .wen(resetn && cpuregs_write && latched_rd), + .waddr(cpuregs_waddr), + .raddr1(cpuregs_raddr1), + .raddr2(cpuregs_raddr2), + .wdata(cpuregs_wrdata), + .rdata1(cpuregs_rdata1), + .rdata2(cpuregs_rdata2) + ); + + always @* begin + decoded_rs = 'bx; + if (ENABLE_REGS_DUALPORT) begin + cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0; + cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0; + end else begin + decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; + cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0; + cpuregs_rs2 = cpuregs_rs1; + end + end +`endif + + assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask)); + + always @(posedge clk) begin + trap <= 0; + reg_sh <= 'bx; + reg_out <= 'bx; + set_mem_do_rinst = 0; + set_mem_do_rdata = 0; + set_mem_do_wdata = 0; + + alu_out_0_q <= alu_out_0; + alu_out_q <= alu_out; + + alu_wait <= 0; + alu_wait_2 <= 0; + + if (launch_next_insn) begin + dbg_rs1val <= 'bx; + dbg_rs2val <= 'bx; + dbg_rs1val_valid <= 0; + dbg_rs2val_valid <= 0; + end + + if (WITH_PCPI && CATCH_ILLINSN) begin + if (resetn && pcpi_valid && !pcpi_int_wait) begin + if (pcpi_timeout_counter) + pcpi_timeout_counter <= pcpi_timeout_counter - 1; + end else + pcpi_timeout_counter <= ~0; + pcpi_timeout <= !pcpi_timeout_counter; + end + + if (ENABLE_COUNTERS) begin + count_cycle <= resetn ? count_cycle + 1 : 0; + if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0; + end else begin + count_cycle <= 'bx; + count_instr <= 'bx; + end + + next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx; + + if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin + if (timer - 1 == 0) + next_irq_pending[irq_timer] = 1; + timer <= timer - 1; + end + + if (ENABLE_IRQ) begin + next_irq_pending = next_irq_pending | irq; + end + + decoder_trigger <= mem_do_rinst && mem_done; + decoder_trigger_q <= decoder_trigger; + decoder_pseudo_trigger <= 0; + decoder_pseudo_trigger_q <= decoder_pseudo_trigger; + do_waitirq <= 0; + + trace_valid <= 0; + + if (!ENABLE_TRACE) + trace_data <= 'bx; + + if (!resetn) begin + reg_pc <= PROGADDR_RESET; + reg_next_pc <= PROGADDR_RESET; + if (ENABLE_COUNTERS) + count_instr <= 0; + latched_store <= 0; + latched_stalu <= 0; + latched_branch <= 0; + latched_trace <= 0; + latched_is_lu <= 0; + latched_is_lh <= 0; + latched_is_lb <= 0; + pcpi_valid <= 0; + pcpi_timeout <= 0; + irq_active <= 0; + irq_delay <= 0; + irq_mask <= ~0; + next_irq_pending = 0; + irq_state <= 0; + eoi <= 0; + timer <= 0; + if (~STACKADDR) begin + latched_store <= 1; + latched_rd <= 2; + reg_out <= STACKADDR; + end + cpu_state <= cpu_state_fetch; + end else + (* parallel_case, full_case *) + case (cpu_state) + cpu_state_trap: begin + trap <= 1; + end + + cpu_state_fetch: begin + mem_do_rinst <= !decoder_trigger && !do_waitirq; + mem_wordsize <= 0; + + current_pc = reg_next_pc; + + (* parallel_case *) + case (1'b1) + latched_branch: begin + current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc; + `debug($display("ST_RD: %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);) + end + latched_store && !latched_branch: begin + `debug($display("ST_RD: %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);) + end + ENABLE_IRQ && irq_state[0]: begin + current_pc = PROGADDR_IRQ; + irq_active <= 1; + mem_do_rinst <= 1; + end + ENABLE_IRQ && irq_state[1]: begin + eoi <= irq_pending & ~irq_mask; + next_irq_pending = next_irq_pending & irq_mask; + end + endcase + + if (ENABLE_TRACE && latched_trace) begin + latched_trace <= 0; + trace_valid <= 1; + if (latched_branch) + trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe); + else + trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out); + end + + reg_pc <= current_pc; + reg_next_pc <= current_pc; + + latched_store <= 0; + latched_stalu <= 0; + latched_branch <= 0; + latched_is_lu <= 0; + latched_is_lh <= 0; + latched_is_lb <= 0; + latched_rd <= decoded_rd; + latched_compr <= compressed_instr; + + if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin + irq_state <= + irq_state == 2'b00 ? 2'b01 : + irq_state == 2'b01 ? 2'b10 : 2'b00; + latched_compr <= latched_compr; + if (ENABLE_IRQ_QREGS) + latched_rd <= irqregs_offset | irq_state[0]; + else + latched_rd <= irq_state[0] ? 4 : 3; + end else + if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin + if (irq_pending) begin + latched_store <= 1; + reg_out <= irq_pending; + reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); + mem_do_rinst <= 1; + end else + do_waitirq <= 1; + end else + if (decoder_trigger) begin + `debug($display("-- %-0t", $time);) + irq_delay <= irq_active; + reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); + if (ENABLE_TRACE) + latched_trace <= 1; + if (ENABLE_COUNTERS) begin + count_instr <= count_instr + 1; + if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0; + end + if (instr_jal) begin + mem_do_rinst <= 1; + reg_next_pc <= current_pc + decoded_imm_uj; + latched_branch <= 1; + end else begin + mem_do_rinst <= 0; + mem_do_prefetch <= !instr_jalr && !instr_retirq; + cpu_state <= cpu_state_ld_rs1; + end + end + end + + cpu_state_ld_rs1: begin + reg_op1 <= 'bx; + reg_op2 <= 'bx; + + (* parallel_case *) + case (1'b1) + (CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin + if (WITH_PCPI) begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_op1 <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + if (ENABLE_REGS_DUALPORT) begin + pcpi_valid <= 1; + `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) + reg_sh <= cpuregs_rs2; + reg_op2 <= cpuregs_rs2; + dbg_rs2val <= cpuregs_rs2; + dbg_rs2val_valid <= 1; + if (pcpi_int_ready) begin + mem_do_rinst <= 1; + pcpi_valid <= 0; + reg_out <= pcpi_int_rd; + latched_store <= pcpi_int_wr; + cpu_state <= cpu_state_fetch; + end else + if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin + pcpi_valid <= 0; + `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) + if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin + next_irq_pending[irq_ebreak] = 1; + cpu_state <= cpu_state_fetch; + end else + cpu_state <= cpu_state_trap; + end + end else begin + cpu_state <= cpu_state_ld_rs2; + end + end else begin + `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) + if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin + next_irq_pending[irq_ebreak] = 1; + cpu_state <= cpu_state_fetch; + end else + cpu_state <= cpu_state_trap; + end + end + ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin + (* parallel_case, full_case *) + case (1'b1) + instr_rdcycle: + reg_out <= count_cycle[31:0]; + instr_rdcycleh && ENABLE_COUNTERS64: + reg_out <= count_cycle[63:32]; + instr_rdinstr: + reg_out <= count_instr[31:0]; + instr_rdinstrh && ENABLE_COUNTERS64: + reg_out <= count_instr[63:32]; + endcase + latched_store <= 1; + cpu_state <= cpu_state_fetch; + end + is_lui_auipc_jal: begin + reg_op1 <= instr_lui ? 0 : reg_pc; + reg_op2 <= decoded_imm; + if (TWO_CYCLE_ALU) + alu_wait <= 1; + else + mem_do_rinst <= mem_do_prefetch; + cpu_state <= cpu_state_exec; + end + ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_out <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + latched_store <= 1; + cpu_state <= cpu_state_fetch; + end + ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_out <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + latched_rd <= latched_rd | irqregs_offset; + latched_store <= 1; + cpu_state <= cpu_state_fetch; + end + ENABLE_IRQ && instr_retirq: begin + eoi <= 0; + irq_active <= 0; + latched_branch <= 1; + latched_store <= 1; + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + cpu_state <= cpu_state_fetch; + end + ENABLE_IRQ && instr_maskirq: begin + latched_store <= 1; + reg_out <= irq_mask; + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + irq_mask <= cpuregs_rs1 | MASKED_IRQ; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + cpu_state <= cpu_state_fetch; + end + ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin + latched_store <= 1; + reg_out <= timer; + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + timer <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + cpu_state <= cpu_state_fetch; + end + is_lb_lh_lw_lbu_lhu && !instr_trap: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_op1 <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + cpu_state <= cpu_state_ldmem; + mem_do_rinst <= 1; + end + is_slli_srli_srai && !BARREL_SHIFTER: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_op1 <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + reg_sh <= decoded_rs2; + cpu_state <= cpu_state_shift; + end + is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_op1 <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm; + if (TWO_CYCLE_ALU) + alu_wait <= 1; + else + mem_do_rinst <= mem_do_prefetch; + cpu_state <= cpu_state_exec; + end + default: begin + `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) + reg_op1 <= cpuregs_rs1; + dbg_rs1val <= cpuregs_rs1; + dbg_rs1val_valid <= 1; + if (ENABLE_REGS_DUALPORT) begin + `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) + reg_sh <= cpuregs_rs2; + reg_op2 <= cpuregs_rs2; + dbg_rs2val <= cpuregs_rs2; + dbg_rs2val_valid <= 1; + (* parallel_case *) + case (1'b1) + is_sb_sh_sw: begin + cpu_state <= cpu_state_stmem; + mem_do_rinst <= 1; + end + is_sll_srl_sra && !BARREL_SHIFTER: begin + cpu_state <= cpu_state_shift; + end + default: begin + if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin + alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); + alu_wait <= 1; + end else + mem_do_rinst <= mem_do_prefetch; + cpu_state <= cpu_state_exec; + end + endcase + end else + cpu_state <= cpu_state_ld_rs2; + end + endcase + end + + cpu_state_ld_rs2: begin + `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) + reg_sh <= cpuregs_rs2; + reg_op2 <= cpuregs_rs2; + dbg_rs2val <= cpuregs_rs2; + dbg_rs2val_valid <= 1; + + (* parallel_case *) + case (1'b1) + WITH_PCPI && instr_trap: begin + pcpi_valid <= 1; + if (pcpi_int_ready) begin + mem_do_rinst <= 1; + pcpi_valid <= 0; + reg_out <= pcpi_int_rd; + latched_store <= pcpi_int_wr; + cpu_state <= cpu_state_fetch; + end else + if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin + pcpi_valid <= 0; + `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) + if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin + next_irq_pending[irq_ebreak] = 1; + cpu_state <= cpu_state_fetch; + end else + cpu_state <= cpu_state_trap; + end + end + is_sb_sh_sw: begin + cpu_state <= cpu_state_stmem; + mem_do_rinst <= 1; + end + is_sll_srl_sra && !BARREL_SHIFTER: begin + cpu_state <= cpu_state_shift; + end + default: begin + if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin + alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); + alu_wait <= 1; + end else + mem_do_rinst <= mem_do_prefetch; + cpu_state <= cpu_state_exec; + end + endcase + end + + cpu_state_exec: begin + reg_out <= reg_pc + decoded_imm; + if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin + mem_do_rinst <= mem_do_prefetch && !alu_wait_2; + alu_wait <= alu_wait_2; + end else + if (is_beq_bne_blt_bge_bltu_bgeu) begin + latched_rd <= 0; + latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; + latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; + if (mem_done) + cpu_state <= cpu_state_fetch; + if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin + decoder_trigger <= 0; + set_mem_do_rinst = 1; + end + end else begin + latched_branch <= instr_jalr; + latched_store <= 1; + latched_stalu <= 1; + cpu_state <= cpu_state_fetch; + end + end + + cpu_state_shift: begin + latched_store <= 1; + if (reg_sh == 0) begin + reg_out <= reg_op1; + mem_do_rinst <= mem_do_prefetch; + cpu_state <= cpu_state_fetch; + end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin + (* parallel_case, full_case *) + case (1'b1) + instr_slli || instr_sll: reg_op1 <= reg_op1 << 4; + instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4; + instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4; + endcase + reg_sh <= reg_sh - 4; + end else begin + (* parallel_case, full_case *) + case (1'b1) + instr_slli || instr_sll: reg_op1 <= reg_op1 << 1; + instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1; + instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1; + endcase + reg_sh <= reg_sh - 1; + end + end + + cpu_state_stmem: begin + if (ENABLE_TRACE) + reg_out <= reg_op2; + if (!mem_do_prefetch || mem_done) begin + if (!mem_do_wdata) begin + (* parallel_case, full_case *) + case (1'b1) + instr_sb: mem_wordsize <= 2; + instr_sh: mem_wordsize <= 1; + instr_sw: mem_wordsize <= 0; + endcase + if (ENABLE_TRACE) begin + trace_valid <= 1; + trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); + end + reg_op1 <= reg_op1 + decoded_imm; + set_mem_do_wdata = 1; + end + if (!mem_do_prefetch && mem_done) begin + cpu_state <= cpu_state_fetch; + decoder_trigger <= 1; + decoder_pseudo_trigger <= 1; + end + end + end + + cpu_state_ldmem: begin + latched_store <= 1; + if (!mem_do_prefetch || mem_done) begin + if (!mem_do_rdata) begin + (* parallel_case, full_case *) + case (1'b1) + instr_lb || instr_lbu: mem_wordsize <= 2; + instr_lh || instr_lhu: mem_wordsize <= 1; + instr_lw: mem_wordsize <= 0; + endcase + latched_is_lu <= is_lbu_lhu_lw; + latched_is_lh <= instr_lh; + latched_is_lb <= instr_lb; + if (ENABLE_TRACE) begin + trace_valid <= 1; + trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); + end + reg_op1 <= reg_op1 + decoded_imm; + set_mem_do_rdata = 1; + end + if (!mem_do_prefetch && mem_done) begin + (* parallel_case, full_case *) + case (1'b1) + latched_is_lu: reg_out <= mem_rdata_word; + latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]); + latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]); + endcase + decoder_trigger <= 1; + decoder_pseudo_trigger <= 1; + cpu_state <= cpu_state_fetch; + end + end + end + endcase + + if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin + if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin + `debug($display("MISALIGNED WORD: 0x%08x", reg_op1);) + if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin + next_irq_pending[irq_buserror] = 1; + end else + cpu_state <= cpu_state_trap; + end + if (mem_wordsize == 1 && reg_op1[0] != 0) begin + `debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);) + if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin + next_irq_pending[irq_buserror] = 1; + end else + cpu_state <= cpu_state_trap; + end + end + if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin + `debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);) + if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin + next_irq_pending[irq_buserror] = 1; + end else + cpu_state <= cpu_state_trap; + end + if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin + cpu_state <= cpu_state_trap; + end + + if (!resetn || mem_done) begin + mem_do_prefetch <= 0; + mem_do_rinst <= 0; + mem_do_rdata <= 0; + mem_do_wdata <= 0; + end + + if (set_mem_do_rinst) + mem_do_rinst <= 1; + if (set_mem_do_rdata) + mem_do_rdata <= 1; + if (set_mem_do_wdata) + mem_do_wdata <= 1; + + irq_pending <= next_irq_pending & ~MASKED_IRQ; + + if (!CATCH_MISALIGN) begin + if (COMPRESSED_ISA) begin + reg_pc[0] <= 0; + reg_next_pc[0] <= 0; + end else begin + reg_pc[1:0] <= 0; + reg_next_pc[1:0] <= 0; + end + end + current_pc = 'bx; + end + +`ifdef RISCV_FORMAL + reg dbg_irq_call; + reg dbg_irq_enter; + reg [31:0] dbg_irq_ret; + always @(posedge clk) begin + rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn; + rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0; + + rvfi_insn <= dbg_insn_opcode; + rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0; + rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0; + rvfi_pc_rdata <= dbg_insn_addr; + rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0; + rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0; + rvfi_trap <= trap; + rvfi_halt <= trap; + rvfi_intr <= dbg_irq_enter; + + if (!resetn) begin + dbg_irq_call <= 0; + dbg_irq_enter <= 0; + end else + if (rvfi_valid) begin + dbg_irq_call <= 0; + dbg_irq_enter <= dbg_irq_call; + end else + if (irq_state == 1) begin + dbg_irq_call <= 1; + dbg_irq_ret <= next_pc; + end + + if (!resetn) begin + rvfi_rd_addr <= 0; + rvfi_rd_wdata <= 0; + end else + if (cpuregs_write && !irq_state) begin + rvfi_rd_addr <= latched_rd; + rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0; + end else + if (rvfi_valid) begin + rvfi_rd_addr <= 0; + rvfi_rd_wdata <= 0; + end + + casez (dbg_insn_opcode) + 32'b 0000000_?????_000??_???_?????_0001011: begin // getq + rvfi_rs1_addr <= 0; + rvfi_rs1_rdata <= 0; + end + 32'b 0000001_?????_?????_???_000??_0001011: begin // setq + rvfi_rd_addr <= 0; + rvfi_rd_wdata <= 0; + end + 32'b 0000010_?????_00000_???_00000_0001011: begin // retirq + rvfi_rs1_addr <= 0; + rvfi_rs1_rdata <= 0; + end + endcase + + if (!dbg_irq_call) begin + if (dbg_mem_instr) begin + rvfi_mem_addr <= 0; + rvfi_mem_rmask <= 0; + rvfi_mem_wmask <= 0; + rvfi_mem_rdata <= 0; + rvfi_mem_wdata <= 0; + end else + if (dbg_mem_valid && dbg_mem_ready) begin + rvfi_mem_addr <= dbg_mem_addr; + rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0; + rvfi_mem_wmask <= dbg_mem_wstrb; + rvfi_mem_rdata <= dbg_mem_rdata; + rvfi_mem_wdata <= dbg_mem_wdata; + end + end + end + + always @* begin + rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr; + end +`endif + + // Formal Verification +`ifdef FORMAL + reg [3:0] last_mem_nowait; + always @(posedge clk) + last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid}; + + // stall the memory interface for max 4 cycles + restrict property (|last_mem_nowait || mem_ready || !mem_valid); + + // resetn low in first cycle, after that resetn high + restrict property (resetn != $initstate); + + // this just makes it much easier to read traces. uncomment as needed. + // assume property (mem_valid || !mem_ready); + + reg ok; + always @* begin + if (resetn) begin + // instruction fetches are read-only + if (mem_valid && mem_instr) + assert (mem_wstrb == 0); + + // cpu_state must be valid + ok = 0; + if (cpu_state == cpu_state_trap) ok = 1; + if (cpu_state == cpu_state_fetch) ok = 1; + if (cpu_state == cpu_state_ld_rs1) ok = 1; + if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT; + if (cpu_state == cpu_state_exec) ok = 1; + if (cpu_state == cpu_state_shift) ok = 1; + if (cpu_state == cpu_state_stmem) ok = 1; + if (cpu_state == cpu_state_ldmem) ok = 1; + assert (ok); + end + end + + reg last_mem_la_read = 0; + reg last_mem_la_write = 0; + reg [31:0] last_mem_la_addr; + reg [31:0] last_mem_la_wdata; + reg [3:0] last_mem_la_wstrb = 0; + + always @(posedge clk) begin + last_mem_la_read <= mem_la_read; + last_mem_la_write <= mem_la_write; + last_mem_la_addr <= mem_la_addr; + last_mem_la_wdata <= mem_la_wdata; + last_mem_la_wstrb <= mem_la_wstrb; + + if (last_mem_la_read) begin + assert(mem_valid); + assert(mem_addr == last_mem_la_addr); + assert(mem_wstrb == 0); + end + if (last_mem_la_write) begin + assert(mem_valid); + assert(mem_addr == last_mem_la_addr); + assert(mem_wdata == last_mem_la_wdata); + assert(mem_wstrb == last_mem_la_wstrb); + end + if (mem_la_read || mem_la_write) begin + assert(!mem_valid || mem_ready); + end + end +`endif +endmodule + +// This is a simple example implementation of PICORV32_REGS. +// Use the PICORV32_REGS mechanism if you want to use custom +// memory resources to implement the processor register file. +// Note that your implementation must match the requirements of +// the PicoRV32 configuration. (e.g. QREGS, etc) +module picorv32_regs ( + input clk, wen, + input [5:0] waddr, + input [5:0] raddr1, + input [5:0] raddr2, + input [31:0] wdata, + output [31:0] rdata1, + output [31:0] rdata2 +); + reg [31:0] regs [0:30]; + + always @(posedge clk) + if (wen) regs[~waddr[4:0]] <= wdata; + + assign rdata1 = regs[~raddr1[4:0]]; + assign rdata2 = regs[~raddr2[4:0]]; +endmodule + + +/*************************************************************** + * picorv32_pcpi_mul + ***************************************************************/ + +module picorv32_pcpi_mul #( + parameter STEPS_AT_ONCE = 1, + parameter CARRY_CHAIN = 4 +) ( + input clk, resetn, + + input pcpi_valid, + input [31:0] pcpi_insn, + input [31:0] pcpi_rs1, + input [31:0] pcpi_rs2, + output reg pcpi_wr, + output reg [31:0] pcpi_rd, + output reg pcpi_wait, + output reg pcpi_ready +); + reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; + wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; + wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; + wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; + wire instr_rs2_signed = |{instr_mulh}; + + reg pcpi_wait_q; + wire mul_start = pcpi_wait && !pcpi_wait_q; + + always @(posedge clk) begin + instr_mul <= 0; + instr_mulh <= 0; + instr_mulhsu <= 0; + instr_mulhu <= 0; + + if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin + case (pcpi_insn[14:12]) + 3'b000: instr_mul <= 1; + 3'b001: instr_mulh <= 1; + 3'b010: instr_mulhsu <= 1; + 3'b011: instr_mulhu <= 1; + endcase + end + + pcpi_wait <= instr_any_mul; + pcpi_wait_q <= pcpi_wait; + end + + reg [63:0] rs1, rs2, rd, rdx; + reg [63:0] next_rs1, next_rs2, this_rs2; + reg [63:0] next_rd, next_rdx, next_rdt; + reg [6:0] mul_counter; + reg mul_waiting; + reg mul_finish; + integer i, j; + + // carry save accumulator + always @* begin + next_rd = rd; + next_rdx = rdx; + next_rs1 = rs1; + next_rs2 = rs2; + + for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin + this_rs2 = next_rs1[0] ? next_rs2 : 0; + if (CARRY_CHAIN == 0) begin + next_rdt = next_rd ^ next_rdx ^ this_rs2; + next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1; + next_rd = next_rdt; + end else begin + next_rdt = 0; + for (j = 0; j < 64; j = j + CARRY_CHAIN) + {next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} = + next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN]; + next_rdx = next_rdt << 1; + end + next_rs1 = next_rs1 >> 1; + next_rs2 = next_rs2 << 1; + end + end + + always @(posedge clk) begin + mul_finish <= 0; + if (!resetn) begin + mul_waiting <= 1; + end else + if (mul_waiting) begin + if (instr_rs1_signed) + rs1 <= $signed(pcpi_rs1); + else + rs1 <= $unsigned(pcpi_rs1); + + if (instr_rs2_signed) + rs2 <= $signed(pcpi_rs2); + else + rs2 <= $unsigned(pcpi_rs2); + + rd <= 0; + rdx <= 0; + mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE); + mul_waiting <= !mul_start; + end else begin + rd <= next_rd; + rdx <= next_rdx; + rs1 <= next_rs1; + rs2 <= next_rs2; + + mul_counter <= mul_counter - STEPS_AT_ONCE; + if (mul_counter[6]) begin + mul_finish <= 1; + mul_waiting <= 1; + end + end + end + + always @(posedge clk) begin + pcpi_wr <= 0; + pcpi_ready <= 0; + if (mul_finish && resetn) begin + pcpi_wr <= 1; + pcpi_ready <= 1; + pcpi_rd <= instr_any_mulh ? rd >> 32 : rd; + end + end +endmodule + +module picorv32_pcpi_fast_mul #( + parameter EXTRA_MUL_FFS = 0, + parameter EXTRA_INSN_FFS = 0, + parameter MUL_CLKGATE = 0 +) ( + input clk, resetn, + + input pcpi_valid, + input [31:0] pcpi_insn, + input [31:0] pcpi_rs1, + input [31:0] pcpi_rs2, + output pcpi_wr, + output [31:0] pcpi_rd, + output pcpi_wait, + output pcpi_ready +); + reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; + wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; + wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; + wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; + wire instr_rs2_signed = |{instr_mulh}; + + reg shift_out; + reg [3:0] active; + reg [32:0] rs1, rs2, rs1_q, rs2_q; + reg [63:0] rd, rd_q; + + wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001; + reg pcpi_insn_valid_q; + + always @* begin + instr_mul = 0; + instr_mulh = 0; + instr_mulhsu = 0; + instr_mulhu = 0; + + if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin + case (pcpi_insn[14:12]) + 3'b000: instr_mul = 1; + 3'b001: instr_mulh = 1; + 3'b010: instr_mulhsu = 1; + 3'b011: instr_mulhu = 1; + endcase + end + end + + always @(posedge clk) begin + pcpi_insn_valid_q <= pcpi_insn_valid; + if (!MUL_CLKGATE || active[0]) begin + rs1_q <= rs1; + rs2_q <= rs2; + end + if (!MUL_CLKGATE || active[1]) begin + rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2); + end + if (!MUL_CLKGATE || active[2]) begin + rd_q <= rd; + end + end + + always @(posedge clk) begin + if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin + if (instr_rs1_signed) + rs1 <= $signed(pcpi_rs1); + else + rs1 <= $unsigned(pcpi_rs1); + + if (instr_rs2_signed) + rs2 <= $signed(pcpi_rs2); + else + rs2 <= $unsigned(pcpi_rs2); + active[0] <= 1; + end else begin + active[0] <= 0; + end + + active[3:1] <= active; + shift_out <= instr_any_mulh; + + if (!resetn) + active <= 0; + end + + assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1]; + assign pcpi_wait = 0; + assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1]; +`ifdef RISCV_FORMAL_ALTOPS + assign pcpi_rd = + instr_mul ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e : + instr_mulh ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 : + instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 : + instr_mulhu ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx; +`else + assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd); +`endif +endmodule + + +/*************************************************************** + * picorv32_pcpi_div + ***************************************************************/ + +module picorv32_pcpi_div ( + input clk, resetn, + + input pcpi_valid, + input [31:0] pcpi_insn, + input [31:0] pcpi_rs1, + input [31:0] pcpi_rs2, + output reg pcpi_wr, + output reg [31:0] pcpi_rd, + output reg pcpi_wait, + output reg pcpi_ready +); + reg instr_div, instr_divu, instr_rem, instr_remu; + wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu}; + + reg pcpi_wait_q; + wire start = pcpi_wait && !pcpi_wait_q; + + always @(posedge clk) begin + instr_div <= 0; + instr_divu <= 0; + instr_rem <= 0; + instr_remu <= 0; + + if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin + case (pcpi_insn[14:12]) + 3'b100: instr_div <= 1; + 3'b101: instr_divu <= 1; + 3'b110: instr_rem <= 1; + 3'b111: instr_remu <= 1; + endcase + end + + pcpi_wait <= instr_any_div_rem && resetn; + pcpi_wait_q <= pcpi_wait && resetn; + end + + reg [31:0] dividend; + reg [62:0] divisor; + reg [31:0] quotient; + reg [31:0] quotient_msk; + reg running; + reg outsign; + + always @(posedge clk) begin + pcpi_ready <= 0; + pcpi_wr <= 0; + pcpi_rd <= 'bx; + + if (!resetn) begin + running <= 0; + end else + if (start) begin + running <= 1; + dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1; + divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31; + outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]); + quotient <= 0; + quotient_msk <= 1 << 31; + end else + if (!quotient_msk && running) begin + running <= 0; + pcpi_ready <= 1; + pcpi_wr <= 1; +`ifdef RISCV_FORMAL_ALTOPS + case (1) + instr_div: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec; + instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70; + instr_rem: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5; + instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1; + endcase +`else + if (instr_div || instr_divu) + pcpi_rd <= outsign ? -quotient : quotient; + else + pcpi_rd <= outsign ? -dividend : dividend; +`endif + end else begin + if (divisor <= dividend) begin + dividend <= dividend - divisor; + quotient <= quotient | quotient_msk; + end + divisor <= divisor >> 1; +`ifdef RISCV_FORMAL_ALTOPS + quotient_msk <= quotient_msk >> 5; +`else + quotient_msk <= quotient_msk >> 1; +`endif + end + end +endmodule + + +/*************************************************************** + * picorv32_axi + ***************************************************************/ + +module picorv32_axi #( + parameter [ 0:0] ENABLE_COUNTERS = 1, + parameter [ 0:0] ENABLE_COUNTERS64 = 1, + parameter [ 0:0] ENABLE_REGS_16_31 = 1, + parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, + parameter [ 0:0] TWO_STAGE_SHIFT = 1, + parameter [ 0:0] BARREL_SHIFTER = 0, + parameter [ 0:0] TWO_CYCLE_COMPARE = 0, + parameter [ 0:0] TWO_CYCLE_ALU = 0, + parameter [ 0:0] COMPRESSED_ISA = 0, + parameter [ 0:0] CATCH_MISALIGN = 1, + parameter [ 0:0] CATCH_ILLINSN = 1, + parameter [ 0:0] ENABLE_PCPI = 0, + parameter [ 0:0] ENABLE_MUL = 0, + parameter [ 0:0] ENABLE_FAST_MUL = 0, + parameter [ 0:0] ENABLE_DIV = 0, + parameter [ 0:0] ENABLE_IRQ = 0, + parameter [ 0:0] ENABLE_IRQ_QREGS = 1, + parameter [ 0:0] ENABLE_IRQ_TIMER = 1, + parameter [ 0:0] ENABLE_TRACE = 0, + parameter [ 0:0] REGS_INIT_ZERO = 0, + parameter [31:0] MASKED_IRQ = 32'h 0000_0000, + parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, + parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, + parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, + parameter [31:0] STACKADDR = 32'h ffff_ffff +) ( + input clk, resetn, + output trap, + + // AXI4-lite master memory interface + + output mem_axi_awvalid, + input mem_axi_awready, + output [31:0] mem_axi_awaddr, + output [ 2:0] mem_axi_awprot, + + output mem_axi_wvalid, + input mem_axi_wready, + output [31:0] mem_axi_wdata, + output [ 3:0] mem_axi_wstrb, + + input mem_axi_bvalid, + output mem_axi_bready, + + output mem_axi_arvalid, + input mem_axi_arready, + output [31:0] mem_axi_araddr, + output [ 2:0] mem_axi_arprot, + + input mem_axi_rvalid, + output mem_axi_rready, + input [31:0] mem_axi_rdata, + + // Pico Co-Processor Interface (PCPI) + output pcpi_valid, + output [31:0] pcpi_insn, + output [31:0] pcpi_rs1, + output [31:0] pcpi_rs2, + input pcpi_wr, + input [31:0] pcpi_rd, + input pcpi_wait, + input pcpi_ready, + + // IRQ interface + input [31:0] irq, + output [31:0] eoi, + +`ifdef RISCV_FORMAL + output rvfi_valid, + output [63:0] rvfi_order, + output [31:0] rvfi_insn, + output rvfi_trap, + output rvfi_halt, + output rvfi_intr, + output [ 4:0] rvfi_rs1_addr, + output [ 4:0] rvfi_rs2_addr, + output [31:0] rvfi_rs1_rdata, + output [31:0] rvfi_rs2_rdata, + output [ 4:0] rvfi_rd_addr, + output [31:0] rvfi_rd_wdata, + output [31:0] rvfi_pc_rdata, + output [31:0] rvfi_pc_wdata, + output [31:0] rvfi_mem_addr, + output [ 3:0] rvfi_mem_rmask, + output [ 3:0] rvfi_mem_wmask, + output [31:0] rvfi_mem_rdata, + output [31:0] rvfi_mem_wdata, +`endif + + // Trace Interface + output trace_valid, + output [35:0] trace_data +); + wire mem_valid; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [ 3:0] mem_wstrb; + wire mem_instr; + wire mem_ready; + wire [31:0] mem_rdata; + + picorv32_axi_adapter axi_adapter ( + .clk (clk ), + .resetn (resetn ), + .mem_axi_awvalid(mem_axi_awvalid), + .mem_axi_awready(mem_axi_awready), + .mem_axi_awaddr (mem_axi_awaddr ), + .mem_axi_awprot (mem_axi_awprot ), + .mem_axi_wvalid (mem_axi_wvalid ), + .mem_axi_wready (mem_axi_wready ), + .mem_axi_wdata (mem_axi_wdata ), + .mem_axi_wstrb (mem_axi_wstrb ), + .mem_axi_bvalid (mem_axi_bvalid ), + .mem_axi_bready (mem_axi_bready ), + .mem_axi_arvalid(mem_axi_arvalid), + .mem_axi_arready(mem_axi_arready), + .mem_axi_araddr (mem_axi_araddr ), + .mem_axi_arprot (mem_axi_arprot ), + .mem_axi_rvalid (mem_axi_rvalid ), + .mem_axi_rready (mem_axi_rready ), + .mem_axi_rdata (mem_axi_rdata ), + .mem_valid (mem_valid ), + .mem_instr (mem_instr ), + .mem_ready (mem_ready ), + .mem_addr (mem_addr ), + .mem_wdata (mem_wdata ), + .mem_wstrb (mem_wstrb ), + .mem_rdata (mem_rdata ) + ); + + picorv32 #( + .ENABLE_COUNTERS (ENABLE_COUNTERS ), + .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), + .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), + .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), + .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), + .BARREL_SHIFTER (BARREL_SHIFTER ), + .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), + .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), + .COMPRESSED_ISA (COMPRESSED_ISA ), + .CATCH_MISALIGN (CATCH_MISALIGN ), + .CATCH_ILLINSN (CATCH_ILLINSN ), + .ENABLE_PCPI (ENABLE_PCPI ), + .ENABLE_MUL (ENABLE_MUL ), + .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), + .ENABLE_DIV (ENABLE_DIV ), + .ENABLE_IRQ (ENABLE_IRQ ), + .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), + .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), + .ENABLE_TRACE (ENABLE_TRACE ), + .REGS_INIT_ZERO (REGS_INIT_ZERO ), + .MASKED_IRQ (MASKED_IRQ ), + .LATCHED_IRQ (LATCHED_IRQ ), + .PROGADDR_RESET (PROGADDR_RESET ), + .PROGADDR_IRQ (PROGADDR_IRQ ), + .STACKADDR (STACKADDR ) + ) picorv32_core ( + .clk (clk ), + .resetn (resetn), + .trap (trap ), + + .mem_valid(mem_valid), + .mem_addr (mem_addr ), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_instr(mem_instr), + .mem_ready(mem_ready), + .mem_rdata(mem_rdata), + + .pcpi_valid(pcpi_valid), + .pcpi_insn (pcpi_insn ), + .pcpi_rs1 (pcpi_rs1 ), + .pcpi_rs2 (pcpi_rs2 ), + .pcpi_wr (pcpi_wr ), + .pcpi_rd (pcpi_rd ), + .pcpi_wait (pcpi_wait ), + .pcpi_ready(pcpi_ready), + + .irq(irq), + .eoi(eoi), + +`ifdef RISCV_FORMAL + .rvfi_valid (rvfi_valid ), + .rvfi_order (rvfi_order ), + .rvfi_insn (rvfi_insn ), + .rvfi_trap (rvfi_trap ), + .rvfi_halt (rvfi_halt ), + .rvfi_intr (rvfi_intr ), + .rvfi_rs1_addr (rvfi_rs1_addr ), + .rvfi_rs2_addr (rvfi_rs2_addr ), + .rvfi_rs1_rdata(rvfi_rs1_rdata), + .rvfi_rs2_rdata(rvfi_rs2_rdata), + .rvfi_rd_addr (rvfi_rd_addr ), + .rvfi_rd_wdata (rvfi_rd_wdata ), + .rvfi_pc_rdata (rvfi_pc_rdata ), + .rvfi_pc_wdata (rvfi_pc_wdata ), + .rvfi_mem_addr (rvfi_mem_addr ), + .rvfi_mem_rmask(rvfi_mem_rmask), + .rvfi_mem_wmask(rvfi_mem_wmask), + .rvfi_mem_rdata(rvfi_mem_rdata), + .rvfi_mem_wdata(rvfi_mem_wdata), +`endif + + .trace_valid(trace_valid), + .trace_data (trace_data) + ); +endmodule + + +/*************************************************************** + * picorv32_axi_adapter + ***************************************************************/ + +module picorv32_axi_adapter ( + input clk, resetn, + + // AXI4-lite master memory interface + + output mem_axi_awvalid, + input mem_axi_awready, + output [31:0] mem_axi_awaddr, + output [ 2:0] mem_axi_awprot, + + output mem_axi_wvalid, + input mem_axi_wready, + output [31:0] mem_axi_wdata, + output [ 3:0] mem_axi_wstrb, + + input mem_axi_bvalid, + output mem_axi_bready, + + output mem_axi_arvalid, + input mem_axi_arready, + output [31:0] mem_axi_araddr, + output [ 2:0] mem_axi_arprot, + + input mem_axi_rvalid, + output mem_axi_rready, + input [31:0] mem_axi_rdata, + + // Native PicoRV32 memory interface + + input mem_valid, + input mem_instr, + output mem_ready, + input [31:0] mem_addr, + input [31:0] mem_wdata, + input [ 3:0] mem_wstrb, + output [31:0] mem_rdata +); + reg ack_awvalid; + reg ack_arvalid; + reg ack_wvalid; + reg xfer_done; + + assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid; + assign mem_axi_awaddr = mem_addr; + assign mem_axi_awprot = 0; + + assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid; + assign mem_axi_araddr = mem_addr; + assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000; + + assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid; + assign mem_axi_wdata = mem_wdata; + assign mem_axi_wstrb = mem_wstrb; + + assign mem_ready = mem_axi_bvalid || mem_axi_rvalid; + assign mem_axi_bready = mem_valid && |mem_wstrb; + assign mem_axi_rready = mem_valid && !mem_wstrb; + assign mem_rdata = mem_axi_rdata; + + always @(posedge clk) begin + if (!resetn) begin + ack_awvalid <= 0; + end else begin + xfer_done <= mem_valid && mem_ready; + if (mem_axi_awready && mem_axi_awvalid) + ack_awvalid <= 1; + if (mem_axi_arready && mem_axi_arvalid) + ack_arvalid <= 1; + if (mem_axi_wready && mem_axi_wvalid) + ack_wvalid <= 1; + if (xfer_done || !mem_valid) begin + ack_awvalid <= 0; + ack_arvalid <= 0; + ack_wvalid <= 0; + end + end + end +endmodule + + +/*************************************************************** + * picorv32_wb + ***************************************************************/ + +module picorv32_wb #( + parameter [ 0:0] ENABLE_COUNTERS = 1, + parameter [ 0:0] ENABLE_COUNTERS64 = 1, + parameter [ 0:0] ENABLE_REGS_16_31 = 1, + parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, + parameter [ 0:0] TWO_STAGE_SHIFT = 1, + parameter [ 0:0] BARREL_SHIFTER = 0, + parameter [ 0:0] TWO_CYCLE_COMPARE = 0, + parameter [ 0:0] TWO_CYCLE_ALU = 0, + parameter [ 0:0] COMPRESSED_ISA = 0, + parameter [ 0:0] CATCH_MISALIGN = 1, + parameter [ 0:0] CATCH_ILLINSN = 1, + parameter [ 0:0] ENABLE_PCPI = 0, + parameter [ 0:0] ENABLE_MUL = 0, + parameter [ 0:0] ENABLE_FAST_MUL = 0, + parameter [ 0:0] ENABLE_DIV = 0, + parameter [ 0:0] ENABLE_IRQ = 0, + parameter [ 0:0] ENABLE_IRQ_QREGS = 1, + parameter [ 0:0] ENABLE_IRQ_TIMER = 1, + parameter [ 0:0] ENABLE_TRACE = 0, + parameter [ 0:0] REGS_INIT_ZERO = 0, + parameter [31:0] MASKED_IRQ = 32'h 0000_0000, + parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, + parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, + parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, + parameter [31:0] STACKADDR = 32'h ffff_ffff +) ( + output trap, + + // Wishbone interfaces + input wb_rst_i, + input wb_clk_i, + + output reg [31:0] wbm_adr_o, + output reg [31:0] wbm_dat_o, + input [31:0] wbm_dat_i, + output reg wbm_we_o, + output reg [3:0] wbm_sel_o, + output reg wbm_stb_o, + input wbm_ack_i, + output reg wbm_cyc_o, + + // Pico Co-Processor Interface (PCPI) + output pcpi_valid, + output [31:0] pcpi_insn, + output [31:0] pcpi_rs1, + output [31:0] pcpi_rs2, + input pcpi_wr, + input [31:0] pcpi_rd, + input pcpi_wait, + input pcpi_ready, + + // IRQ interface + input [31:0] irq, + output [31:0] eoi, + +`ifdef RISCV_FORMAL + output rvfi_valid, + output [63:0] rvfi_order, + output [31:0] rvfi_insn, + output rvfi_trap, + output rvfi_halt, + output rvfi_intr, + output [ 4:0] rvfi_rs1_addr, + output [ 4:0] rvfi_rs2_addr, + output [31:0] rvfi_rs1_rdata, + output [31:0] rvfi_rs2_rdata, + output [ 4:0] rvfi_rd_addr, + output [31:0] rvfi_rd_wdata, + output [31:0] rvfi_pc_rdata, + output [31:0] rvfi_pc_wdata, + output [31:0] rvfi_mem_addr, + output [ 3:0] rvfi_mem_rmask, + output [ 3:0] rvfi_mem_wmask, + output [31:0] rvfi_mem_rdata, + output [31:0] rvfi_mem_wdata, +`endif + + // Trace Interface + output trace_valid, + output [35:0] trace_data, + + output mem_instr +); + wire mem_valid; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [ 3:0] mem_wstrb; + reg mem_ready; + reg [31:0] mem_rdata; + + wire clk; + wire resetn; + + assign clk = wb_clk_i; + assign resetn = ~wb_rst_i; + + picorv32 #( + .ENABLE_COUNTERS (ENABLE_COUNTERS ), + .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), + .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), + .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), + .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), + .BARREL_SHIFTER (BARREL_SHIFTER ), + .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), + .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), + .COMPRESSED_ISA (COMPRESSED_ISA ), + .CATCH_MISALIGN (CATCH_MISALIGN ), + .CATCH_ILLINSN (CATCH_ILLINSN ), + .ENABLE_PCPI (ENABLE_PCPI ), + .ENABLE_MUL (ENABLE_MUL ), + .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), + .ENABLE_DIV (ENABLE_DIV ), + .ENABLE_IRQ (ENABLE_IRQ ), + .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), + .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), + .ENABLE_TRACE (ENABLE_TRACE ), + .REGS_INIT_ZERO (REGS_INIT_ZERO ), + .MASKED_IRQ (MASKED_IRQ ), + .LATCHED_IRQ (LATCHED_IRQ ), + .PROGADDR_RESET (PROGADDR_RESET ), + .PROGADDR_IRQ (PROGADDR_IRQ ), + .STACKADDR (STACKADDR ) + ) picorv32_core ( + .clk (clk ), + .resetn (resetn), + .trap (trap ), + + .mem_valid(mem_valid), + .mem_addr (mem_addr ), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_instr(mem_instr), + .mem_ready(mem_ready), + .mem_rdata(mem_rdata), + + .pcpi_valid(pcpi_valid), + .pcpi_insn (pcpi_insn ), + .pcpi_rs1 (pcpi_rs1 ), + .pcpi_rs2 (pcpi_rs2 ), + .pcpi_wr (pcpi_wr ), + .pcpi_rd (pcpi_rd ), + .pcpi_wait (pcpi_wait ), + .pcpi_ready(pcpi_ready), + + .irq(irq), + .eoi(eoi), + +`ifdef RISCV_FORMAL + .rvfi_valid (rvfi_valid ), + .rvfi_order (rvfi_order ), + .rvfi_insn (rvfi_insn ), + .rvfi_trap (rvfi_trap ), + .rvfi_halt (rvfi_halt ), + .rvfi_intr (rvfi_intr ), + .rvfi_rs1_addr (rvfi_rs1_addr ), + .rvfi_rs2_addr (rvfi_rs2_addr ), + .rvfi_rs1_rdata(rvfi_rs1_rdata), + .rvfi_rs2_rdata(rvfi_rs2_rdata), + .rvfi_rd_addr (rvfi_rd_addr ), + .rvfi_rd_wdata (rvfi_rd_wdata ), + .rvfi_pc_rdata (rvfi_pc_rdata ), + .rvfi_pc_wdata (rvfi_pc_wdata ), + .rvfi_mem_addr (rvfi_mem_addr ), + .rvfi_mem_rmask(rvfi_mem_rmask), + .rvfi_mem_wmask(rvfi_mem_wmask), + .rvfi_mem_rdata(rvfi_mem_rdata), + .rvfi_mem_wdata(rvfi_mem_wdata), +`endif + + .trace_valid(trace_valid), + .trace_data (trace_data) + ); + + localparam IDLE = 2'b00; + localparam WBSTART = 2'b01; + localparam WBEND = 2'b10; + + reg [1:0] state; + + wire we; + assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]); + + always @(posedge wb_clk_i) begin + if (wb_rst_i) begin + wbm_adr_o <= 0; + wbm_dat_o <= 0; + wbm_we_o <= 0; + wbm_sel_o <= 0; + wbm_stb_o <= 0; + wbm_cyc_o <= 0; + state <= IDLE; + end else begin + case (state) + IDLE: begin + if (mem_valid) begin + wbm_adr_o <= mem_addr; + wbm_dat_o <= mem_wdata; + wbm_we_o <= we; + wbm_sel_o <= mem_wstrb; + + wbm_stb_o <= 1'b1; + wbm_cyc_o <= 1'b1; + state <= WBSTART; + end else begin + mem_ready <= 1'b0; + + wbm_stb_o <= 1'b0; + wbm_cyc_o <= 1'b0; + wbm_we_o <= 1'b0; + end + end + WBSTART:begin + if (wbm_ack_i) begin + mem_rdata <= wbm_dat_i; + mem_ready <= 1'b1; + + state <= WBEND; + + wbm_stb_o <= 1'b0; + wbm_cyc_o <= 1'b0; + wbm_we_o <= 1'b0; + end + end + WBEND: begin + mem_ready <= 1'b0; + + state <= IDLE; + end + default: + state <= IDLE; + endcase + end + end +endmodule diff --git a/xc7/benchmark/picosoc.v b/xc7/benchmark/picosoc.v new file mode 100644 index 00000000..6298a8ef --- /dev/null +++ b/xc7/benchmark/picosoc.v @@ -0,0 +1,241 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 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 PICORV32_REGS +`ifdef PICORV32_V +`error "picosoc.v must be read before picorv32.v!" +`endif + +`define PICORV32_REGS picosoc_regs +`endif + +module picosoc ( + input clk, + input resetn, + + output iomem_valid, + input iomem_ready, + output [ 3:0] iomem_wstrb, + output [31:0] iomem_addr, + output [31:0] iomem_wdata, + input [31:0] iomem_rdata, + + input irq_5, + input irq_6, + input irq_7, + + output ser_tx, + input ser_rx, + + output flash_csb, + output flash_clk, + + output flash_io0_oe, + output flash_io1_oe, + output flash_io2_oe, + output flash_io3_oe, + + output flash_io0_do, + output flash_io1_do, + output flash_io2_do, + output flash_io3_do, + + input flash_io0_di, + input flash_io1_di, + input flash_io2_di, + input flash_io3_di +); + parameter integer MEM_WORDS = 256; + parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory + parameter [31:0] PROGADDR_RESET = 32'h 0010_0000; // 1 MB into flash + + reg [31:0] irq; + wire irq_stall = 0; + wire irq_uart = 0; + + always @* begin + irq = 0; + irq[3] = irq_stall; + irq[4] = irq_uart; + irq[5] = irq_5; + irq[6] = irq_6; + irq[7] = irq_7; + end + + wire mem_valid; + wire mem_instr; + wire mem_ready; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [3:0] mem_wstrb; + wire [31:0] mem_rdata; + + wire spimem_ready; + wire [31:0] spimem_rdata; + + reg ram_ready; + wire [31:0] ram_rdata; + + assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01); + assign iomem_wstrb = mem_wstrb; + assign iomem_addr = mem_addr; + assign iomem_wdata = mem_wdata; + + wire spimemio_cfgreg_sel = mem_valid && (mem_addr == 32'h 0200_0000); + wire [31:0] spimemio_cfgreg_do; + + wire simpleuart_reg_div_sel = mem_valid && (mem_addr == 32'h 0200_0004); + wire [31:0] simpleuart_reg_div_do; + + wire simpleuart_reg_dat_sel = mem_valid && (mem_addr == 32'h 0200_0008); + wire [31:0] simpleuart_reg_dat_do; + wire simpleuart_reg_dat_wait; + + assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel || + simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait); + + assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata : + spimemio_cfgreg_sel ? spimemio_cfgreg_do : simpleuart_reg_div_sel ? simpleuart_reg_div_do : + simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 32'h 0000_0000; + + picorv32 #( + .STACKADDR(STACKADDR), + .PROGADDR_RESET(PROGADDR_RESET), + .PROGADDR_IRQ(32'h 0000_0000), + .BARREL_SHIFTER(1), + .COMPRESSED_ISA(1), + .ENABLE_MUL(1), + .ENABLE_DIV(1), + .ENABLE_IRQ(1), + .ENABLE_IRQ_QREGS(0) + ) cpu ( + .clk (clk ), + .resetn (resetn ), + .mem_valid (mem_valid ), + .mem_instr (mem_instr ), + .mem_ready (mem_ready ), + .mem_addr (mem_addr ), + .mem_wdata (mem_wdata ), + .mem_wstrb (mem_wstrb ), + .mem_rdata (mem_rdata ), + .irq (irq ) + ); + + spimemio spimemio ( + .clk (clk), + .resetn (resetn), + .valid (mem_valid && mem_addr >= 4*MEM_WORDS && mem_addr < 32'h 0200_0000), + .ready (spimem_ready), + .addr (mem_addr[23:0]), + .rdata (spimem_rdata), + + .flash_csb (flash_csb ), + .flash_clk (flash_clk ), + + .flash_io0_oe (flash_io0_oe), + .flash_io1_oe (flash_io1_oe), + .flash_io2_oe (flash_io2_oe), + .flash_io3_oe (flash_io3_oe), + + .flash_io0_do (flash_io0_do), + .flash_io1_do (flash_io1_do), + .flash_io2_do (flash_io2_do), + .flash_io3_do (flash_io3_do), + + .flash_io0_di (flash_io0_di), + .flash_io1_di (flash_io1_di), + .flash_io2_di (flash_io2_di), + .flash_io3_di (flash_io3_di), + + .cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000), + .cfgreg_di(mem_wdata), + .cfgreg_do(spimemio_cfgreg_do) + ); + + simpleuart simpleuart ( + .clk (clk ), + .resetn (resetn ), + + .ser_tx (ser_tx ), + .ser_rx (ser_rx ), + + .reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000), + .reg_div_di (mem_wdata), + .reg_div_do (simpleuart_reg_div_do), + + .reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0), + .reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb), + .reg_dat_di (mem_wdata), + .reg_dat_do (simpleuart_reg_dat_do), + .reg_dat_wait(simpleuart_reg_dat_wait) + ); + + always @(posedge clk) + ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS; + + picosoc_mem #(.WORDS(MEM_WORDS)) memory ( + .clk(clk), + .wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0), + .addr(mem_addr[23:2]), + .wdata(mem_wdata), + .rdata(ram_rdata) + ); +endmodule + +// Implementation note: +// Replace the following two modules with wrappers for your SRAM cells. + +module picosoc_regs ( + input clk, wen, + input [5:0] waddr, + input [5:0] raddr1, + input [5:0] raddr2, + input [31:0] wdata, + output [31:0] rdata1, + output [31:0] rdata2 +); + reg [31:0] regs [0:31]; + + always @(posedge clk) + if (wen) regs[waddr[4:0]] <= wdata; + + assign rdata1 = regs[raddr1[4:0]]; + assign rdata2 = regs[raddr2[4:0]]; +endmodule + +module picosoc_mem #( + parameter integer WORDS = 256 +) ( + input clk, + input [3:0] wen, + input [21:0] addr, + input [31:0] wdata, + output reg [31:0] rdata +); + reg [31:0] mem [0:WORDS-1]; + + always @(posedge clk) begin + rdata <= mem[addr]; + if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0]; + if (wen[1]) mem[addr][15: 8] <= wdata[15: 8]; + if (wen[2]) mem[addr][23:16] <= wdata[23:16]; + if (wen[3]) mem[addr][31:24] <= wdata[31:24]; + end +endmodule + diff --git a/xc7/benchmark/report.ipynb b/xc7/benchmark/report.ipynb new file mode 100644 index 00000000..b4e03283 --- /dev/null +++ b/xc7/benchmark/report.ipynb @@ -0,0 +1,91 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import subprocess, re\n", + "\n", + "gitrev = subprocess.getoutput(\"git rev-parse --short HEAD\")\n", + "\n", + "data_a = np.zeros((10, 2))\n", + "data_n = np.zeros((10, 2))\n", + "\n", + "for i in range(10):\n", + " try:\n", + " with open(\"report_a%d.txt\" % i, \"r\") as f:\n", + " for line in f:\n", + " if line.startswith(\"Total path delay:\"):\n", + " data_a[i, 0] = float(line.split()[3])\n", + " except:\n", + " data_a[i, 0] = 1.0\n", + " \n", + " try:\n", + " with open(\"report_n%d.txt\" % i, \"r\") as f:\n", + " for line in f:\n", + " if line.startswith(\"Total path delay:\"):\n", + " data_n[i, 0] = float(line.split()[3])\n", + " except:\n", + " data_n[i, 0] = 1.0\n", + " \n", + " with open(\"hx8kdemo_a%d.log\" % i, \"r\") as f:\n", + " for line in f:\n", + " match = re.match(r\"real\\s+(\\d+)m(\\d+)\", line)\n", + " if match:\n", + " data_a[i, 1] = float(match.group(1)) + float(match.group(2))/60\n", + " \n", + " with open(\"hx8kdemo_n%d.log\" % i, \"r\") as f:\n", + " for line in f:\n", + " match = re.match(r\"real\\s+(\\d+)m(\\d+)\", line)\n", + " if match:\n", + " data_n[i, 1] = float(match.group(1)) + float(match.group(2))/60\n", + "\n", + "plt.figure(figsize=(9,3))\n", + "plt.title(\"nextpnr -- ice40/benchmark/ -- %s\" % gitrev)\n", + "plt.bar(np.arange(10), data_a[:, 0], color='blue')\n", + "plt.bar(15+np.arange(10), data_n[:, 0], color='red')\n", + "plt.ylabel('Longest path (ns)')\n", + "plt.xticks([5, 20], [\"arachne-pnr\", \"nextpnr\"])\n", + "plt.xlim(-2, 27)\n", + "plt.show()\n", + "\n", + "plt.figure(figsize=(9,3))\n", + "plt.title(\"nextpnr -- ice40/benchmark/ -- %s\" % gitrev)\n", + "plt.bar(np.arange(10), data_a[:, 1], color='blue')\n", + "plt.bar(15+np.arange(10), data_n[:, 1], color='red')\n", + "plt.ylabel('Runtime (minutes)')\n", + "plt.xticks([5, 20], [\"arachne-pnr\", \"nextpnr\"])\n", + "plt.xlim(-2, 27)\n", + "plt.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.2" + } + }, + "nbformat": 4, + "nbformat_minor": 1 +} diff --git a/xc7/benchmark/simpleuart.v b/xc7/benchmark/simpleuart.v new file mode 100644 index 00000000..50808cb3 --- /dev/null +++ b/xc7/benchmark/simpleuart.v @@ -0,0 +1,137 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 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. + * + */ + +module simpleuart ( + input clk, + input resetn, + + output ser_tx, + input ser_rx, + + input [3:0] reg_div_we, + input [31:0] reg_div_di, + output [31:0] reg_div_do, + + input reg_dat_we, + input reg_dat_re, + input [31:0] reg_dat_di, + output [31:0] reg_dat_do, + output reg_dat_wait +); + reg [31:0] cfg_divider; + + reg [3:0] recv_state; + reg [31:0] recv_divcnt; + reg [7:0] recv_pattern; + reg [7:0] recv_buf_data; + reg recv_buf_valid; + + reg [9:0] send_pattern; + reg [3:0] send_bitcnt; + reg [31:0] send_divcnt; + reg send_dummy; + + assign reg_div_do = cfg_divider; + + assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); + assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; + + always @(posedge clk) begin + if (!resetn) begin + cfg_divider <= 1; + end else begin + if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; + if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; + if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; + if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; + end + end + + always @(posedge clk) begin + if (!resetn) begin + recv_state <= 0; + recv_divcnt <= 0; + recv_pattern <= 0; + recv_buf_data <= 0; + recv_buf_valid <= 0; + end else begin + recv_divcnt <= recv_divcnt + 1; + if (reg_dat_re) + recv_buf_valid <= 0; + case (recv_state) + 0: begin + if (!ser_rx) + recv_state <= 1; + recv_divcnt <= 0; + end + 1: begin + if (2*recv_divcnt > cfg_divider) begin + recv_state <= 2; + recv_divcnt <= 0; + end + end + 10: begin + if (recv_divcnt > cfg_divider) begin + recv_buf_data <= recv_pattern; + recv_buf_valid <= 1; + recv_state <= 0; + end + end + default: begin + if (recv_divcnt > cfg_divider) begin + recv_pattern <= {ser_rx, recv_pattern[7:1]}; + recv_state <= recv_state + 1; + recv_divcnt <= 0; + end + end + endcase + end + end + + assign ser_tx = send_pattern[0]; + + always @(posedge clk) begin + if (reg_div_we) + send_dummy <= 1; + send_divcnt <= send_divcnt + 1; + if (!resetn) begin + send_pattern <= ~0; + send_bitcnt <= 0; + send_divcnt <= 0; + send_dummy <= 1; + end else begin + if (send_dummy && !send_bitcnt) begin + send_pattern <= ~0; + send_bitcnt <= 15; + send_divcnt <= 0; + send_dummy <= 0; + end else + if (reg_dat_we && !send_bitcnt) begin + send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; + send_bitcnt <= 10; + send_divcnt <= 0; + end else + if (send_divcnt > cfg_divider && send_bitcnt) begin + send_pattern <= {1'b1, send_pattern[9:1]}; + send_bitcnt <= send_bitcnt - 1; + send_divcnt <= 0; + end + end + end +endmodule diff --git a/xc7/benchmark/spimemio.v b/xc7/benchmark/spimemio.v new file mode 100644 index 00000000..0bbf5326 --- /dev/null +++ b/xc7/benchmark/spimemio.v @@ -0,0 +1,579 @@ +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 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. + * + */ + +module spimemio ( + input clk, resetn, + + input valid, + output ready, + input [23:0] addr, + output reg [31:0] rdata, + + output flash_csb, + output flash_clk, + + output flash_io0_oe, + output flash_io1_oe, + output flash_io2_oe, + output flash_io3_oe, + + output flash_io0_do, + output flash_io1_do, + output flash_io2_do, + output flash_io3_do, + + input flash_io0_di, + input flash_io1_di, + input flash_io2_di, + input flash_io3_di, + + input [3:0] cfgreg_we, + input [31:0] cfgreg_di, + output [31:0] cfgreg_do +); + reg xfer_resetn; + reg din_valid; + wire din_ready; + reg [7:0] din_data; + reg [3:0] din_tag; + reg din_cont; + reg din_qspi; + reg din_ddr; + reg din_rd; + + wire dout_valid; + wire [7:0] dout_data; + wire [3:0] dout_tag; + + reg [23:0] buffer; + + reg [23:0] rd_addr; + reg rd_valid; + reg rd_wait; + reg rd_inc; + + assign ready = valid && (addr == rd_addr) && rd_valid; + wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid; + + reg softreset; + + reg config_en; // cfgreg[31] + reg config_ddr; // cfgreg[22] + reg config_qspi; // cfgreg[21] + reg config_cont; // cfgreg[20] + reg [3:0] config_dummy; // cfgreg[19:16] + reg [3:0] config_oe; // cfgreg[11:8] + reg config_csb; // cfgreg[5] + reg config_clk; // cfgref[4] + reg [3:0] config_do; // cfgreg[3:0] + + assign cfgreg_do[31] = config_en; + assign cfgreg_do[30:23] = 0; + assign cfgreg_do[22] = config_ddr; + assign cfgreg_do[21] = config_qspi; + assign cfgreg_do[20] = config_cont; + assign cfgreg_do[19:16] = config_dummy; + assign cfgreg_do[15:12] = 0; + assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; + assign cfgreg_do[7:6] = 0; + assign cfgreg_do[5] = flash_csb; + assign cfgreg_do[4] = flash_clk; + assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; + + always @(posedge clk) begin + softreset <= !config_en || cfgreg_we; + if (!resetn) begin + softreset <= 1; + config_en <= 1; + config_csb <= 0; + config_clk <= 0; + config_oe <= 0; + config_do <= 0; + config_ddr <= 0; + config_qspi <= 0; + config_cont <= 0; + config_dummy <= 8; + end else begin + if (cfgreg_we[0]) begin + config_csb <= cfgreg_di[5]; + config_clk <= cfgreg_di[4]; + config_do <= cfgreg_di[3:0]; + end + if (cfgreg_we[1]) begin + config_oe <= cfgreg_di[11:8]; + end + if (cfgreg_we[2]) begin + config_ddr <= cfgreg_di[22]; + config_qspi <= cfgreg_di[21]; + config_cont <= cfgreg_di[20]; + config_dummy <= cfgreg_di[19:16]; + end + if (cfgreg_we[3]) begin + config_en <= cfgreg_di[31]; + end + end + end + + wire xfer_csb; + wire xfer_clk; + + wire xfer_io0_oe; + wire xfer_io1_oe; + wire xfer_io2_oe; + wire xfer_io3_oe; + + wire xfer_io0_do; + wire xfer_io1_do; + wire xfer_io2_do; + wire xfer_io3_do; + + reg xfer_io0_90; + reg xfer_io1_90; + reg xfer_io2_90; + reg xfer_io3_90; + + always @(negedge clk) begin + xfer_io0_90 <= xfer_io0_do; + xfer_io1_90 <= xfer_io1_do; + xfer_io2_90 <= xfer_io2_do; + xfer_io3_90 <= xfer_io3_do; + end + + assign flash_csb = config_en ? xfer_csb : config_csb; + assign flash_clk = config_en ? xfer_clk : config_clk; + + assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; + assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; + assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; + assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3]; + + assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0]; + assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1]; + assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2]; + assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3]; + + wire xfer_dspi = din_ddr && !din_qspi; + wire xfer_ddr = din_ddr && din_qspi; + + spimemio_xfer xfer ( + .clk (clk ), + .resetn (xfer_resetn ), + .din_valid (din_valid ), + .din_ready (din_ready ), + .din_data (din_data ), + .din_tag (din_tag ), + .din_cont (din_cont ), + .din_dspi (xfer_dspi ), + .din_qspi (din_qspi ), + .din_ddr (xfer_ddr ), + .din_rd (din_rd ), + .dout_valid (dout_valid ), + .dout_data (dout_data ), + .dout_tag (dout_tag ), + .flash_csb (xfer_csb ), + .flash_clk (xfer_clk ), + .flash_io0_oe (xfer_io0_oe ), + .flash_io1_oe (xfer_io1_oe ), + .flash_io2_oe (xfer_io2_oe ), + .flash_io3_oe (xfer_io3_oe ), + .flash_io0_do (xfer_io0_do ), + .flash_io1_do (xfer_io1_do ), + .flash_io2_do (xfer_io2_do ), + .flash_io3_do (xfer_io3_do ), + .flash_io0_di (flash_io0_di), + .flash_io1_di (flash_io1_di), + .flash_io2_di (flash_io2_di), + .flash_io3_di (flash_io3_di) + ); + + reg [3:0] state; + + always @(posedge clk) begin + xfer_resetn <= 1; + din_valid <= 0; + + if (!resetn || softreset) begin + state <= 0; + xfer_resetn <= 0; + rd_valid <= 0; + din_tag <= 0; + din_cont <= 0; + din_qspi <= 0; + din_ddr <= 0; + din_rd <= 0; + end else begin + if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data; + if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data; + if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data; + if (dout_valid && dout_tag == 4) begin + rdata <= {dout_data, buffer}; + rd_addr <= rd_inc ? rd_addr + 4 : addr; + rd_valid <= 1; + rd_wait <= rd_inc; + rd_inc <= 1; + end + + if (valid) + rd_wait <= 0; + + case (state) + 0: begin + din_valid <= 1; + din_data <= 8'h ff; + din_tag <= 0; + if (din_ready) begin + din_valid <= 0; + state <= 1; + end + end + 1: begin + if (dout_valid) begin + xfer_resetn <= 0; + state <= 2; + end + end + 2: begin + din_valid <= 1; + din_data <= 8'h ab; + din_tag <= 0; + if (din_ready) begin + din_valid <= 0; + state <= 3; + end + end + 3: begin + if (dout_valid) begin + xfer_resetn <= 0; + state <= 4; + end + end + 4: begin + rd_inc <= 0; + din_valid <= 1; + din_tag <= 0; + case ({config_ddr, config_qspi}) + 2'b11: din_data <= 8'h ED; + 2'b01: din_data <= 8'h EB; + 2'b10: din_data <= 8'h BB; + 2'b00: din_data <= 8'h 03; + endcase + if (din_ready) begin + din_valid <= 0; + state <= 5; + end + end + 5: begin + if (valid && !ready) begin + din_valid <= 1; + din_tag <= 0; + din_data <= addr[23:16]; + din_qspi <= config_qspi; + din_ddr <= config_ddr; + if (din_ready) begin + din_valid <= 0; + state <= 6; + end + end + end + 6: begin + din_valid <= 1; + din_tag <= 0; + din_data <= addr[15:8]; + if (din_ready) begin + din_valid <= 0; + state <= 7; + end + end + 7: begin + din_valid <= 1; + din_tag <= 0; + din_data <= addr[7:0]; + if (din_ready) begin + din_valid <= 0; + din_data <= 0; + state <= config_qspi || config_ddr ? 8 : 9; + end + end + 8: begin + din_valid <= 1; + din_tag <= 0; + din_data <= config_cont ? 8'h A5 : 8'h FF; + if (din_ready) begin + din_rd <= 1; + din_data <= config_dummy; + din_valid <= 0; + state <= 9; + end + end + 9: begin + din_valid <= 1; + din_tag <= 1; + if (din_ready) begin + din_valid <= 0; + state <= 10; + end + end + 10: begin + din_valid <= 1; + din_data <= 8'h 00; + din_tag <= 2; + if (din_ready) begin + din_valid <= 0; + state <= 11; + end + end + 11: begin + din_valid <= 1; + din_tag <= 3; + if (din_ready) begin + din_valid <= 0; + state <= 12; + end + end + 12: begin + if (!rd_wait || valid) begin + din_valid <= 1; + din_tag <= 4; + if (din_ready) begin + din_valid <= 0; + state <= 9; + end + end + end + endcase + + if (jump) begin + rd_inc <= 0; + rd_valid <= 0; + xfer_resetn <= 0; + if (config_cont) begin + state <= 5; + end else begin + state <= 4; + din_qspi <= 0; + din_ddr <= 0; + end + din_rd <= 0; + end + end + end +endmodule + +module spimemio_xfer ( + input clk, resetn, + + input din_valid, + output din_ready, + input [7:0] din_data, + input [3:0] din_tag, + input din_cont, + input din_dspi, + input din_qspi, + input din_ddr, + input din_rd, + + output dout_valid, + output [7:0] dout_data, + output [3:0] dout_tag, + + output reg flash_csb, + output reg flash_clk, + + output reg flash_io0_oe, + output reg flash_io1_oe, + output reg flash_io2_oe, + output reg flash_io3_oe, + + output reg flash_io0_do, + output reg flash_io1_do, + output reg flash_io2_do, + output reg flash_io3_do, + + input flash_io0_di, + input flash_io1_di, + input flash_io2_di, + input flash_io3_di +); + reg [7:0] obuffer; + reg [7:0] ibuffer; + + reg [3:0] count; + reg [3:0] dummy_count; + + reg xfer_cont; + reg xfer_dspi; + reg xfer_qspi; + reg xfer_ddr; + reg xfer_ddr_q; + reg xfer_rd; + reg [3:0] xfer_tag; + reg [3:0] xfer_tag_q; + + reg [7:0] next_obuffer; + reg [7:0] next_ibuffer; + reg [3:0] next_count; + + reg fetch; + reg next_fetch; + reg last_fetch; + + always @(posedge clk) begin + xfer_ddr_q <= xfer_ddr; + xfer_tag_q <= xfer_tag; + end + + assign din_ready = din_valid && resetn && next_fetch; + + assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn; + assign dout_data = ibuffer; + assign dout_tag = xfer_tag_q; + + always @* begin + flash_io0_oe = 0; + flash_io1_oe = 0; + flash_io2_oe = 0; + flash_io3_oe = 0; + + flash_io0_do = 0; + flash_io1_do = 0; + flash_io2_do = 0; + flash_io3_do = 0; + + next_obuffer = obuffer; + next_ibuffer = ibuffer; + next_count = count; + next_fetch = 0; + + if (dummy_count == 0) begin + casez ({xfer_ddr, xfer_qspi, xfer_dspi}) + 3'b 000: begin + flash_io0_oe = 1; + flash_io0_do = obuffer[7]; + + if (flash_clk) begin + next_obuffer = {obuffer[6:0], 1'b 0}; + next_count = count - |count; + end else begin + next_ibuffer = {ibuffer[6:0], flash_io1_di}; + end + + next_fetch = (next_count == 0); + end + 3'b 01?: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + flash_io2_oe = !xfer_rd; + flash_io3_oe = !xfer_rd; + + flash_io0_do = obuffer[4]; + flash_io1_do = obuffer[5]; + flash_io2_do = obuffer[6]; + flash_io3_do = obuffer[7]; + + if (flash_clk) begin + next_obuffer = {obuffer[3:0], 4'b 0000}; + next_count = count - {|count, 2'b00}; + end else begin + next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; + end + + next_fetch = (next_count == 0); + end + 3'b 11?: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + flash_io2_oe = !xfer_rd; + flash_io3_oe = !xfer_rd; + + flash_io0_do = obuffer[4]; + flash_io1_do = obuffer[5]; + flash_io2_do = obuffer[6]; + flash_io3_do = obuffer[7]; + + next_obuffer = {obuffer[3:0], 4'b 0000}; + next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; + next_count = count - {|count, 2'b00}; + + next_fetch = (next_count == 0); + end + 3'b ??1: begin + flash_io0_oe = !xfer_rd; + flash_io1_oe = !xfer_rd; + + flash_io0_do = obuffer[6]; + flash_io1_do = obuffer[7]; + + if (flash_clk) begin + next_obuffer = {obuffer[5:0], 2'b 00}; + next_count = count - {|count, 1'b0}; + end else begin + next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di}; + end + + next_fetch = (next_count == 0); + end + endcase + end + end + + always @(posedge clk) begin + if (!resetn) begin + fetch <= 1; + last_fetch <= 1; + flash_csb <= 1; + flash_clk <= 0; + count <= 0; + dummy_count <= 0; + xfer_tag <= 0; + xfer_cont <= 0; + xfer_dspi <= 0; + xfer_qspi <= 0; + xfer_ddr <= 0; + xfer_rd <= 0; + end else begin + fetch <= next_fetch; + last_fetch <= xfer_ddr ? fetch : 1; + if (dummy_count) begin + flash_clk <= !flash_clk && !flash_csb; + dummy_count <= dummy_count - flash_clk; + end else + if (count) begin + flash_clk <= !flash_clk && !flash_csb; + obuffer <= next_obuffer; + ibuffer <= next_ibuffer; + count <= next_count; + end + if (din_valid && din_ready) begin + flash_csb <= 0; + flash_clk <= 0; + + count <= 8; + dummy_count <= din_rd ? din_data : 0; + obuffer <= din_data; + + xfer_tag <= din_tag; + xfer_cont <= din_cont; + xfer_dspi <= din_dspi; + xfer_qspi <= din_qspi; + xfer_ddr <= din_ddr; + xfer_rd <= din_rd; + end + end + end +endmodule diff --git a/xc7/bitstream.cc b/xc7/bitstream.cc new file mode 100644 index 00000000..ee276e49 --- /dev/null +++ b/xc7/bitstream.cc @@ -0,0 +1,999 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski + * + * 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 "bitstream.h" +#include +#include +#include "cells.h" +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +inline TileType tile_at(const Context *ctx, int x, int y) +{ + return ctx->chip_info->tile_grid[y * ctx->chip_info->width + x]; +} + +const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const std::string &name) +{ + for (int i = 0; i < tile.num_config_entries; i++) { + if (std::string(tile.entries[i].name.get()) == name) { + return tile.entries[i]; + } + } + NPNR_ASSERT_FALSE_STR("unable to find config bit " + name); +} + +std::tuple get_ieren(const BitstreamInfoPOD &bi, int8_t x, int8_t y, int8_t z) +{ + for (int i = 0; i < bi.num_ierens; i++) { + auto ie = bi.ierens[i]; + if (ie.iox == x && ie.ioy == y && ie.ioz == z) { + return std::make_tuple(ie.ierx, ie.iery, ie.ierz); + } + } + // No pin at this location + return std::make_tuple(-1, -1, -1); +}; + +bool get_config(const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, + int index = -1) +{ + const ConfigEntryPOD &cfg = find_config(ti, name); + if (index == -1) { + for (int i = 0; i < cfg.num_bits; i++) { + return tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); + } + } else { + return tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); + } + return false; +} + +void set_config(const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, bool value, + int index = -1) +{ + const ConfigEntryPOD &cfg = find_config(ti, name); + if (index == -1) { + for (int i = 0; i < cfg.num_bits; i++) { + int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); + if (cbit && !value) + log_error("clearing already set config bit %s\n", name.c_str()); + cbit = value; + } + } else { + int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); + cbit = value; + if (cbit && !value) + log_error("clearing already set config bit %s[%d]\n", name.c_str(), index); + } +} + +// Set an IE_{EN,REN} logical bit in a tile config. Logical means enabled. +// On {HX,LP}1K devices these bits are active low, so we need to invert them. +void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, + const std::string &name, bool value) +{ + if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { + set_config(ti, tile_cfg, name, !value); + } else { + set_config(ti, tile_cfg, name, value); + } +} + +int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0) +{ + auto found = cell->params.find(param); + if (found != cell->params.end()) + return std::stoi(found->second); + else + return defval; +} + +std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std::string defval = "") +{ + auto found = cell->params.find(param); + if (found != cell->params.end()) + return found->second; + else + return defval; +} + +char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } + +static const BelConfigPOD &get_ec_config(const ChipInfoPOD *chip, BelId bel) +{ + for (int i = 0; i < chip->num_belcfgs; i++) { + if (chip->bel_config[i].bel_index == bel.index) + return chip->bel_config[i]; + } + NPNR_ASSERT_FALSE("failed to find bel config"); +} + +typedef std::vector>>> chipconfig_t; + +static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfigPOD &cell_cbits, std::string name, + bool value, std::string prefix) +{ + const ChipInfoPOD *chip = ctx->chip_info; + + for (int i = 0; i < cell_cbits.num_entries; i++) { + const auto &cbit = cell_cbits.entries[i]; + if (cbit.entry_name.get() == name) { + const auto &ti = chip->bits_info->tiles_nonrouting[tile_at(ctx, cbit.x, cbit.y)]; + set_config(ti, config.at(cbit.y).at(cbit.x), prefix + cbit.cbit_name.get(), value); + return; + } + } + NPNR_ASSERT_FALSE_STR("failed to config extra cell config bit " + name); +} + +void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *cell, + const std::vector> ¶ms, bool string_style, std::string prefix) +{ + const ChipInfoPOD *chip = ctx->chip_info; + const auto &bc = get_ec_config(chip, cell->bel); + for (auto p : params) { + std::vector value; + if (string_style) { + // Lattice's weird string style params, not sure if + // prefixes other than 0b should be supported, only 0b features in docs + std::string raw = get_param_str_or_def(cell, ctx->id(p.first), "0b0"); + assert(raw.substr(0, 2) == "0b"); + raw = raw.substr(2); + value.resize(raw.length()); + for (int i = 0; i < (int)raw.length(); i++) { + if (raw[i] == '1') { + value[(raw.length() - 1) - i] = 1; + } else { + assert(raw[i] == '0'); + value[(raw.length() - 1) - i] = 0; + } + } + } else { + int ival = get_param_or_def(cell, ctx->id(p.first), 0); + + for (int i = 0; i < p.second; i++) + value.push_back((ival >> i) & 0x1); + } + + value.resize(p.second); + if (p.second == 1) { + set_ec_cbit(config, ctx, bc, p.first, value.at(0), prefix); + } else { + for (int i = 0; i < p.second; i++) { + set_ec_cbit(config, ctx, bc, p.first + "_" + std::to_string(i), value.at(i), prefix); + } + } + } +} + +std::string tagTileType(TileType &tile) +{ + if (tile == TILE_NONE) + return ""; + switch (tile) { + case TILE_LOGIC: + return ".logic_tile"; + break; + case TILE_IO: + return ".io_tile"; + break; + case TILE_RAMB: + return ".ramb_tile"; + break; + case TILE_RAMT: + return ".ramt_tile"; + break; + case TILE_DSP0: + return ".dsp0_tile"; + break; + case TILE_DSP1: + return ".dsp1_tile"; + break; + case TILE_DSP2: + return ".dsp2_tile"; + break; + case TILE_DSP3: + return ".dsp3_tile"; + break; + case TILE_IPCON: + return ".ipcon_tile"; + break; + default: + NPNR_ASSERT(false); + } +} + +static BelPin get_one_bel_pin(const Context *ctx, WireId wire) +{ + auto pins = ctx->getWireBelPins(wire); + NPNR_ASSERT(pins.begin() != pins.end()); + return *pins.begin(); +} + +// Permute LUT init value given map (LUT input -> ext input) +unsigned permute_lut(unsigned orig_init, const std::unordered_map &input_permute) +{ + unsigned new_init = 0; + + for (int i = 0; i < 16; i++) { + int permute_address = 0; + for (int j = 0; j < 4; j++) { + if ((i >> j) & 0x1) + permute_address |= (1 << input_permute.at(j)); + } + if ((orig_init >> i) & 0x1) { + new_init |= (1 << permute_address); + } + } + + return new_init; +} + +void write_asc(const Context *ctx, std::ostream &out) +{ + + static const std::vector lut_perm = { + 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, + }; + + // [y][x][row][col] + const ChipInfoPOD &ci = *ctx->chip_info; + const BitstreamInfoPOD &bi = *ci.bits_info; + chipconfig_t config; + config.resize(ci.height); + for (int y = 0; y < ci.height; y++) { + config.at(y).resize(ci.width); + for (int x = 0; x < ci.width; x++) { + TileType tile = tile_at(ctx, x, y); + int rows = bi.tiles_nonrouting[tile].rows; + int cols = bi.tiles_nonrouting[tile].cols; + config.at(y).at(x).resize(rows, std::vector(cols)); + } + } + out << ".comment from next-pnr" << std::endl; + + switch (ctx->args.type) { + case ArchArgs::LP384: + out << ".device 384" << std::endl; + break; + case ArchArgs::HX1K: + case ArchArgs::LP1K: + out << ".device 1k" << std::endl; + break; + case ArchArgs::HX8K: + case ArchArgs::LP8K: + out << ".device 8k" << std::endl; + break; + case ArchArgs::UP5K: + out << ".device 5k" << std::endl; + break; + default: + NPNR_ASSERT_FALSE("unsupported device type\n"); + } + // Set pips + for (auto pip : ctx->getPips()) { + if (ctx->pip_to_net[pip.index] != nullptr) { + const PipInfoPOD &pi = ci.pip_data[pip.index]; + const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; + int sw_bel_idx = swi.bel; + if (sw_bel_idx >= 0) { + const BelInfoPOD &beli = ci.bel_data[sw_bel_idx]; + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; + BelId sw_bel; + sw_bel.index = sw_bel_idx; + NPNR_ASSERT(ctx->getBelType(sw_bel) == id_ICESTORM_LC); + + if (ci.wire_data[ctx->getPipDstWire(pip).index].type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT) + continue; // Permutation pips + BelPin output = get_one_bel_pin(ctx, ctx->getPipDstWire(pip)); + NPNR_ASSERT(output.bel == sw_bel && output.pin == id_O); + unsigned lut_init; + + WireId permWire; + for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) { + if (ctx->getBoundPipNet(permPip) != nullptr) { + permWire = ctx->getPipSrcWire(permPip); + } + } + NPNR_ASSERT(permWire != WireId()); + std::string dName = ci.wire_data[permWire.index].name.get(); + + switch (dName.back()) { + case '0': + lut_init = 2; + break; + case '1': + lut_init = 4; + break; + case '2': + lut_init = 16; + break; + case '3': + lut_init = 256; + break; + default: + NPNR_ASSERT_FALSE("bad feedthru LUT input"); + } + std::vector lc(20, false); + for (int i = 0; i < 16; i++) { + if ((lut_init >> i) & 0x1) + lc.at(lut_perm.at(i)) = true; + } + + for (int i = 0; i < 20; i++) + set_config(ti, config.at(beli.y).at(beli.x), "LC_" + std::to_string(beli.z), lc.at(i), i); + } else { + for (int i = 0; i < swi.num_bits; i++) { + bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; + int8_t &cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); + if (bool(cbit) != 0) + NPNR_ASSERT(false); + cbit = val; + } + } + } + } + + std::unordered_set sb_io_used_by_pll; + std::unordered_set sb_io_used_by_io; + + // Set logic cell config + for (auto &cell : ctx->cells) { + + BelId bel = cell.second.get()->bel; + if (bel == BelId()) { + std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl; + continue; + } + if (cell.second->type == ctx->id("ICESTORM_LC")) { + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; + unsigned lut_init = get_param_or_def(cell.second.get(), ctx->id("LUT_INIT")); + bool neg_clk = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK")); + bool dff_enable = get_param_or_def(cell.second.get(), ctx->id("DFF_ENABLE")); + bool async_sr = get_param_or_def(cell.second.get(), ctx->id("ASYNC_SR")); + bool set_noreset = get_param_or_def(cell.second.get(), ctx->id("SET_NORESET")); + bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE")); + std::vector lc(20, false); + + // Discover permutation + std::unordered_map input_perm; + std::set unused; + for (int i = 0; i < 4; i++) + unused.insert(i); + for (int i = 0; i < 4; i++) { + WireId lut_wire = ctx->getBelPinWire(bel, IdString(ID_I0 + i)); + for (auto pip : ctx->getPipsUphill(lut_wire)) { + if (ctx->getBoundPipNet(pip) != nullptr) { + std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get(); + switch (name.back()) { + case '0': + input_perm[i] = 0; + unused.erase(0); + break; + case '1': + input_perm[i] = 1; + unused.erase(1); + break; + case '2': + input_perm[i] = 2; + unused.erase(2); + break; + case '3': + input_perm[i] = 3; + unused.erase(3); + break; + default: + NPNR_ASSERT_FALSE("failed to determine LUT permutation"); + } + break; + } + } + } + for (int i = 0; i < 4; i++) { + if (!input_perm.count(i)) { + NPNR_ASSERT(!unused.empty()); + input_perm[i] = *(unused.begin()); + unused.erase(input_perm[i]); + } + } + lut_init = permute_lut(lut_init, input_perm); + for (int i = 0; i < 16; i++) { + if ((lut_init >> i) & 0x1) + lc.at(lut_perm.at(i)) = true; + } + lc.at(8) = carry_enable; + lc.at(9) = dff_enable; + lc.at(18) = set_noreset; + lc.at(19) = async_sr; + + for (int i = 0; i < 20; i++) + set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), lc.at(i), i); + if (dff_enable) + set_config(ti, config.at(y).at(x), "NegClk", neg_clk); + + bool carry_const = get_param_or_def(cell.second.get(), ctx->id("CIN_CONST")); + bool carry_set = get_param_or_def(cell.second.get(), ctx->id("CIN_SET")); + if (carry_const) { + if (!ctx->force) + NPNR_ASSERT(z == 0); + set_config(ti, config.at(y).at(x), "CarryInSet", carry_set); + } + } else if (cell.second->type == ctx->id("SB_IO")) { + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + sb_io_used_by_io.insert(Loc(x, y, z)); + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); + bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); + bool pullup = get_param_or_def(cell.second.get(), ctx->id("PULLUP")); + for (int i = 0; i < 6; i++) { + bool val = (pin_type >> i) & 0x01; + set_config(ti, config.at(y).at(x), "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i), val); + } + set_config(ti, config.at(y).at(x), "NegClk", neg_trigger); + auto ieren = get_ieren(bi, x, y, z); + int iex, iey, iez; + std::tie(iex, iey, iez) = ieren; + NPNR_ASSERT(iez != -1); + + bool input_en = false; + if ((ctx->wire_to_net[ctx->getBelPinWire(bel, id_D_IN_0).index] != nullptr) || + (ctx->wire_to_net[ctx->getBelPinWire(bel, id_D_IN_1).index] != nullptr)) { + input_en = true; + } + + if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { + set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), !input_en); + set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup); + } else { + set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), input_en); + set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup); + } + + if (ctx->args.type == ArchArgs::UP5K) { + if (iez == 0) { + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", !pullup); + } else if (iez == 1) { + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", !pullup); + } + } + } else if (cell.second->type == ctx->id("SB_GB")) { + // no cell config bits + } else if (cell.second->type == ctx->id("ICESTORM_RAM")) { + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y; + const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT]; + const TileInfoPOD &ti_ramb = bi.tiles_nonrouting[TILE_RAMB]; + if (!(ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) { + set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp", true); + } + bool negclk_r = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_R")); + bool negclk_w = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_W")); + int write_mode = get_param_or_def(cell.second.get(), ctx->id("WRITE_MODE")); + int read_mode = get_param_or_def(cell.second.get(), ctx->id("READ_MODE")); + set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w); + set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r); + + set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_0", write_mode & 0x1); + set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2); + set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1); + set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2); + } else if (cell.second->type == ctx->id("SB_WARMBOOT") || cell.second->type == ctx->id("ICESTORM_LFOSC")) { + // No config needed + } else if (cell.second->type == ctx->id("ICESTORM_SPRAM")) { + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + NPNR_ASSERT(ctx->args.type == ArchArgs::UP5K); + if (x == 0 && y == 0) { + const TileInfoPOD &ti_ipcon = bi.tiles_nonrouting[TILE_IPCON]; + if (z == 1) { + set_config(ti_ipcon, config.at(1).at(0), "IpConfig.CBIT_0", true); + } else if (z == 2) { + set_config(ti_ipcon, config.at(1).at(0), "IpConfig.CBIT_1", true); + } else { + NPNR_ASSERT(false); + } + } else if (x == 25 && y == 0) { + const TileInfoPOD &ti_ipcon = bi.tiles_nonrouting[TILE_IPCON]; + if (z == 3) { + set_config(ti_ipcon, config.at(1).at(25), "IpConfig.CBIT_0", true); + } else if (z == 4) { + set_config(ti_ipcon, config.at(1).at(25), "IpConfig.CBIT_1", true); + } else { + NPNR_ASSERT(false); + } + } + } else if (cell.second->type == ctx->id("ICESTORM_DSP")) { + const std::vector> mac16_params = {{"C_REG", 1}, + {"A_REG", 1}, + {"B_REG", 1}, + {"D_REG", 1}, + {"TOP_8x8_MULT_REG", 1}, + {"BOT_8x8_MULT_REG", 1}, + {"PIPELINE_16x16_MULT_REG1", 1}, + {"PIPELINE_16x16_MULT_REG2", 1}, + {"TOPOUTPUT_SELECT", 2}, + {"TOPADDSUB_LOWERINPUT", 2}, + {"TOPADDSUB_UPPERINPUT", 1}, + {"TOPADDSUB_CARRYSELECT", 2}, + {"BOTOUTPUT_SELECT", 2}, + {"BOTADDSUB_LOWERINPUT", 2}, + {"BOTADDSUB_UPPERINPUT", 1}, + {"BOTADDSUB_CARRYSELECT", 2}, + {"MODE_8x8", 1}, + {"A_SIGNED", 1}, + {"B_SIGNED", 1}}; + configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false, std::string("IpConfig.")); + } else if (cell.second->type == ctx->id("ICESTORM_HFOSC")) { + const std::vector> hfosc_params = {{"CLKHF_DIV", 2}, {"TRIM_EN", 1}}; + configure_extra_cell(config, ctx, cell.second.get(), hfosc_params, true, std::string("IpConfig.")); + + } else if (cell.second->type == ctx->id("ICESTORM_PLL")) { + const std::vector> pll_params = {{"DELAY_ADJMODE_FB", 1}, + {"DELAY_ADJMODE_REL", 1}, + {"DIVF", 7}, + {"DIVQ", 3}, + {"DIVR", 4}, + {"FDA_FEEDBACK", 4}, + {"FDA_RELATIVE", 4}, + {"FEEDBACK_PATH", 3}, + {"FILTER_RANGE", 3}, + {"PLLOUT_SELECT_A", 2}, + {"PLLOUT_SELECT_B", 2}, + {"PLLTYPE", 3}, + {"SHIFTREG_DIV_MODE", 1}, + {"TEST_MODE", 1}}; + configure_extra_cell(config, ctx, cell.second.get(), pll_params, false, std::string("PLL.")); + + // Configure the SB_IOs that the clock outputs are going through. + for (auto &port : cell.second->ports) { + // If this port is not a PLLOUT port, ignore it. + if (port.second.name != ctx->id("PLLOUT_A") && port.second.name != ctx->id("PLLOUT_B")) + continue; + + // If the output is not driving any net, ignore it. + if (port.second.net == nullptr) + continue; + + // Get IO Bel that this PLL port goes through by finding sibling + // Bel driving the same wire via PIN_D_IN_0. + auto wire = ctx->getBelPinWire(cell.second->bel, port.second.name); + BelId io_bel; + for (auto pin : ctx->getWireBelPins(wire)) { + if (pin.pin == id_D_IN_0) { + io_bel = pin.bel; + break; + } + } + NPNR_ASSERT(io_bel.index != -1); + auto io_bel_loc = ctx->getBelLocation(io_bel); + + // Check that this SB_IO is either unused or just used as an output. + if (sb_io_used_by_io.count(io_bel_loc)) { + log_error("SB_IO '%s' already in use, cannot route PLL through\n", ctx->getBelName(bel).c_str(ctx)); + } + sb_io_used_by_pll.insert(io_bel_loc); + + // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) + auto ieren = get_ieren(bi, io_bel_loc.x, io_bel_loc.y, io_bel_loc.z); + int iex, iey, iez; + std::tie(iex, iey, iez) = ieren; + NPNR_ASSERT(iez != -1); + + // Write config. + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + // Enable input buffer and disable pull-up resistor in block + // (this is used by the PLL). + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); + // PINTYPE[0] passes the PLL through to the fabric. + set_config(ti, config.at(io_bel_loc.y).at(io_bel_loc.x), + "IOB_" + std::to_string(io_bel_loc.z) + ".PINTYPE_0", true); + } + + } else { + NPNR_ASSERT(false); + } + } + // Set config bits in unused IO and RAM + for (auto bel : ctx->getBels()) { + if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == id_SB_IO) { + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + if (sb_io_used_by_pll.count(Loc(x, y, z))) { + continue; + } + + auto ieren = get_ieren(bi, x, y, z); + int iex, iey, iez; + std::tie(iex, iey, iez) = ieren; + if (iez != -1) { + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); + set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); + } + } else if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == id_ICESTORM_RAM) { + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y; + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; + if ((ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) { + set_config(ti, config.at(y).at(x), "RamConfig.PowerUp", true); + } + } + } + + // Set other config bits + for (int y = 0; y < ci.height; y++) { + for (int x = 0; x < ci.width; x++) { + TileType tile = tile_at(ctx, x, y); + const TileInfoPOD &ti = bi.tiles_nonrouting[tile]; + + // set all ColBufCtrl bits (FIXME) + bool setColBufCtrl = true; + if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { + if (tile == TILE_RAMB || tile == TILE_RAMT) { + setColBufCtrl = (y == 3 || y == 5 || y == 11 || y == 13); + } else { + setColBufCtrl = (y == 4 || y == 5 || y == 12 || y == 13); + } + } else if (ctx->args.type == ArchArgs::LP8K || ctx->args.type == ArchArgs::HX8K) { + setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25); + } else if (ctx->args.type == ArchArgs::UP5K) { + setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || y == 26 || y == 27); + } + if (setColBufCtrl) { + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_1", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_2", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_3", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_4", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_5", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_6", true); + set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_7", true); + } + + // Weird UltraPlus bits + if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 || tile == TILE_DSP3 || + tile == TILE_IPCON) { + if (ctx->args.type == ArchArgs::UP5K && x == 25 && y == 14) { + // Mystery bits not set in this one tile + } else { + for (int lc_idx = 0; lc_idx < 8; lc_idx++) { + static const std::vector ip_dsp_lut_perm = { + 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, + }; + for (int i = 0; i < 16; i++) + set_config(ti, config.at(y).at(x), "LC_" + std::to_string(lc_idx), ((i % 8) >= 4), + ip_dsp_lut_perm.at(i)); + if (tile == TILE_IPCON) + set_config(ti, config.at(y).at(x), + "Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true); + else + set_config(ti, config.at(y).at(x), + "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" + + std::to_string(lc_idx) + "_inmux02_5", + true); + } + } + } + } + } + + // Write config out + for (int y = 0; y < ci.height; y++) { + for (int x = 0; x < ci.width; x++) { + TileType tile = tile_at(ctx, x, y); + if (tile == TILE_NONE) + continue; + out << tagTileType(tile); + out << " " << x << " " << y << std::endl; + for (auto row : config.at(y).at(x)) { + for (auto col : row) { + if (col == 1) + out << "1"; + else + out << "0"; + } + out << std::endl; + } + out << std::endl; + } + } + + // Write RAM init data + for (auto &cell : ctx->cells) { + if (cell.second->bel != BelId()) { + if (cell.second->type == ctx->id("ICESTORM_RAM")) { + const BelInfoPOD &beli = ci.bel_data[cell.second->bel.index]; + int x = beli.x, y = beli.y; + out << ".ram_data " << x << " " << y << std::endl; + for (int w = 0; w < 16; w++) { + std::vector bits(256); + std::string init = + get_param_str_or_def(cell.second.get(), ctx->id(std::string("INIT_") + get_hexdigit(w))); + NPNR_ASSERT(init != ""); + for (size_t i = 0; i < init.size(); i++) { + bool val = (init.at((init.size() - 1) - i) == '1'); + bits.at(i) = val; + } + for (int i = bits.size() - 4; i >= 0; i -= 4) { + int c = bits.at(i) + (bits.at(i + 1) << 1) + (bits.at(i + 2) << 2) + (bits.at(i + 3) << 3); + out << char(std::tolower(get_hexdigit(c))); + } + out << std::endl; + } + out << std::endl; + } + } + } + + // Write symbols + // const bool write_symbols = 1; + for (auto wire : ctx->getWires()) { + NetInfo *net = ctx->getBoundWireNet(wire); + if (net != nullptr) + out << ".sym " << wire.index << " " << net->name.str(ctx) << std::endl; + } +} + +void read_config(Context *ctx, std::istream &in, chipconfig_t &config) +{ + constexpr size_t line_buf_size = 65536; + char buffer[line_buf_size]; + int tile_x = -1, tile_y = -1, line_nr = -1; + + while (1) { + in.getline(buffer, line_buf_size); + if (buffer[0] == '.') { + line_nr = -1; + const char *tok = strtok(buffer, " \t\r\n"); + + if (!strcmp(tok, ".device")) { + std::string config_device = strtok(nullptr, " \t\r\n"); + std::string expected; + switch (ctx->args.type) { + case ArchArgs::LP384: + expected = "384"; + break; + case ArchArgs::HX1K: + case ArchArgs::LP1K: + expected = "1k"; + break; + case ArchArgs::HX8K: + case ArchArgs::LP8K: + expected = "8k"; + break; + case ArchArgs::UP5K: + expected = "5k"; + break; + default: + log_error("unsupported device type\n"); + } + if (expected != config_device) + log_error("device type does not match\n"); + } else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") || + !strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") || + !strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) { + line_nr = 0; + tile_x = atoi(strtok(nullptr, " \t\r\n")); + tile_y = atoi(strtok(nullptr, " \t\r\n")); + + TileType tile = tile_at(ctx, tile_x, tile_y); + if (tok != tagTileType(tile)) + log_error("Wrong tile type for specified position\n"); + + } else if (!strcmp(tok, ".extra_bit")) { + /* + int b = atoi(strtok(nullptr, " \t\r\n")); + int x = atoi(strtok(nullptr, " \t\r\n")); + int y = atoi(strtok(nullptr, " \t\r\n")); + std::tuple key(b, x, y); + extra_bits.insert(key); + */ + } else if (!strcmp(tok, ".sym")) { + int wireIndex = atoi(strtok(nullptr, " \t\r\n")); + const char *name = strtok(nullptr, " \t\r\n"); + + IdString netName = ctx->id(name); + + if (ctx->nets.find(netName) == ctx->nets.end()) { + std::unique_ptr created_net = std::unique_ptr(new NetInfo); + created_net->name = netName; + ctx->nets[netName] = std::move(created_net); + } + + WireId wire; + wire.index = wireIndex; + ctx->bindWire(wire, ctx->nets.at(netName).get(), STRENGTH_WEAK); + } + } else if (line_nr >= 0 && strlen(buffer) > 0) { + if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1)) + log_error("Invalid data in input asc file"); + for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++) + config.at(tile_y).at(tile_x).at(line_nr).at(i) = (buffer[i] == '1') ? 1 : 0; + line_nr++; + } + if (in.eof()) + break; + } +} + +bool read_asc(Context *ctx, std::istream &in) +{ + try { + // [y][x][row][col] + const ChipInfoPOD &ci = *ctx->chip_info; + const BitstreamInfoPOD &bi = *ci.bits_info; + chipconfig_t config; + config.resize(ci.height); + for (int y = 0; y < ci.height; y++) { + config.at(y).resize(ci.width); + for (int x = 0; x < ci.width; x++) { + TileType tile = tile_at(ctx, x, y); + int rows = bi.tiles_nonrouting[tile].rows; + int cols = bi.tiles_nonrouting[tile].cols; + config.at(y).at(x).resize(rows, std::vector(cols)); + } + } + read_config(ctx, in, config); + + // Set pips + for (auto pip : ctx->getPips()) { + const PipInfoPOD &pi = ci.pip_data[pip.index]; + const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; + bool isUsed = true; + for (int i = 0; i < swi.num_bits; i++) { + bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; + int8_t cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); + isUsed &= !(bool(cbit) ^ val); + } + if (isUsed) { + NetInfo *net = ctx->wire_to_net[pi.dst]; + WireId wire; + wire.index = pi.dst; + ctx->unbindWire(wire); + ctx->bindPip(pip, net, STRENGTH_WEAK); + } + } + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) == id_ICESTORM_LC) { + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + std::vector lc(20, false); + bool isUsed = false; + for (int i = 0; i < 20; i++) { + lc.at(i) = get_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), i); + isUsed |= lc.at(i); + } + bool neg_clk = get_config(ti, config.at(y).at(x), "NegClk"); + isUsed |= neg_clk; + bool carry_set = get_config(ti, config.at(y).at(x), "CarryInSet"); + isUsed |= carry_set; + + if (isUsed) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets and assign values of properties + } + } + if (ctx->getBelType(bel) == id_SB_IO) { + const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; + const BelInfoPOD &beli = ci.bel_data[bel.index]; + int x = beli.x, y = beli.y, z = beli.z; + bool isUsed = false; + for (int i = 0; i < 6; i++) { + isUsed |= get_config(ti, config.at(y).at(x), + "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i)); + } + bool neg_trigger = get_config(ti, config.at(y).at(x), "NegClk"); + isUsed |= neg_trigger; + + if (isUsed) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_IO")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets and assign values of properties + } + } + } + // Add cells that are without change in initial state of configuration + for (auto &net : ctx->nets) { + for (auto w : net.second->wires) { + if (w.second.pip == PipId()) { + WireId wire = w.first; + for (auto belpin : ctx->getWireBelPins(wire)) { + + if (ctx->checkBelAvail(belpin.bel)) { + if (ctx->getBelType(belpin.bel) == id_ICESTORM_LC) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets + } + if (ctx->getBelType(belpin.bel) == id_SB_IO) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_IO")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets + } + if (ctx->getBelType(belpin.bel) == id_SB_GB) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_GB")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets + } + if (ctx->getBelType(belpin.bel) == id_SB_WARMBOOT) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets + } + if (ctx->getBelType(belpin.bel) == id_ICESTORM_LFOSC) { + std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC")); + IdString name = created->name; + ctx->cells[name] = std::move(created); + ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); + // TODO: Add port mapping to nets + } + } + } + } + } + } + for (auto &cell : ctx->cells) { + if (cell.second->bel != BelId()) { + for (auto &port : cell.second->ports) { + IdString pin = port.first; + WireId wire = ctx->getBelPinWire(cell.second->bel, pin); + if (wire != WireId()) { + NetInfo *net = ctx->getBoundWireNet(wire); + if (net != nullptr) { + port.second.net = net; + PortRef ref; + ref.cell = cell.second.get(); + ref.port = port.second.name; + + if (port.second.type == PORT_OUT) + net->driver = ref; + else + net->users.push_back(ref); + } + } + } + } + } + return true; + } catch (log_execution_error_exception) { + return false; + } +} +NEXTPNR_NAMESPACE_END diff --git a/xc7/bitstream.h b/xc7/bitstream.h new file mode 100644 index 00000000..41a2ae68 --- /dev/null +++ b/xc7/bitstream.h @@ -0,0 +1,34 @@ +/* + * 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. + * + */ + +#ifndef ICE40_BITSTREAM_H +#define ICE40_BITSTREAM_H + +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_asc(const Context *ctx, std::ostream &out); +bool read_asc(Context *ctx, std::istream &in); + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf new file mode 100644 index 00000000..141dfcc8 --- /dev/null +++ b/xc7/blinky.pcf @@ -0,0 +1,6 @@ +set_io led1 99 +set_io led2 98 +set_io led3 97 +set_io led4 96 +set_io led5 95 +set_io clki 21 diff --git a/xc7/blinky.proj b/xc7/blinky.proj new file mode 100644 index 00000000..f5bb9f88 --- /dev/null +++ b/xc7/blinky.proj @@ -0,0 +1,15 @@ +{ + "project": { + "version": "1", + "name": "blinky", + "arch": { + "name": "ice40", + "type": "hx1k", + "package": "tq144" + }, + "input": { + "json": "blinky.json", + "pcf": "blinky.pcf" + } + } +} diff --git a/xc7/blinky.sh b/xc7/blinky.sh new file mode 100755 index 00000000..a2326fc3 --- /dev/null +++ b/xc7/blinky.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ex +yosys blinky.ys +../nextpnr-ice40 --json blinky.json --pcf blinky.pcf --asc blinky.asc +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/xc7/blinky.v b/xc7/blinky.v new file mode 100644 index 00000000..36eaee86 --- /dev/null +++ b/xc7/blinky.v @@ -0,0 +1,27 @@ +module blinky ( + input clki, + output led1, + output led2, + output led3, + output led4, + output led5 +); + + SB_GB clk_gb ( + .USER_SIGNAL_TO_GLOBAL_BUFFER(clki), + .GLOBAL_BUFFER_OUTPUT(clk) + ); + + localparam BITS = 5; + localparam LOG2DELAY = 21; + + reg [BITS+LOG2DELAY-1:0] counter = 0; + reg [BITS-1:0] outcnt; + + always @(posedge clk) begin + counter <= counter + 1; + outcnt <= counter >> LOG2DELAY; + end + + assign {led1, led2, led3, led4, led5} = outcnt ^ (outcnt >> 1); +endmodule diff --git a/xc7/blinky.ys b/xc7/blinky.ys new file mode 100644 index 00000000..a5dd2c85 --- /dev/null +++ b/xc7/blinky.ys @@ -0,0 +1,3 @@ +read_verilog blinky.v +synth_ice40 -top blinky +write_json blinky.json diff --git a/xc7/blinky_tb.v b/xc7/blinky_tb.v new file mode 100644 index 00000000..f80b5e64 --- /dev/null +++ b/xc7/blinky_tb.v @@ -0,0 +1,25 @@ +module blinky_tb; + reg clk; + always #5 clk = (clk === 1'b0); + + wire led1, led2, led3, led4, led5; + + chip uut ( + .io_0_8_1(clk), + .io_13_12_1(led1), + .io_13_12_0(led2), + .io_13_11_1(led3), + .io_13_11_0(led4), + .io_13_9_1(led5) + ); + + initial begin + // $dumpfile("blinky_tb.vcd"); + // $dumpvars(0, blinky_tb); + repeat (10) begin + repeat (900000) @(posedge clk); + $display(led1, led2, led3, led4, led5); + end + $finish; + end +endmodule diff --git a/xc7/carry_tests/.gitignore b/xc7/carry_tests/.gitignore new file mode 100644 index 00000000..427dd825 --- /dev/null +++ b/xc7/carry_tests/.gitignore @@ -0,0 +1,4 @@ +*.vcd +*_out.v +*.out + diff --git a/xc7/carry_tests/counter.v b/xc7/carry_tests/counter.v new file mode 100644 index 00000000..1379a330 --- /dev/null +++ b/xc7/carry_tests/counter.v @@ -0,0 +1,9 @@ +module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); + + reg [15:0] ctr = 0; + + always @(posedge clk) + ctr <= ctr + 1'b1; + + assign {outa, outb, outc, outd} = ctr[15:12]; +endmodule diff --git a/xc7/carry_tests/counter_tb.v b/xc7/carry_tests/counter_tb.v new file mode 100644 index 00000000..ede133a7 --- /dev/null +++ b/xc7/carry_tests/counter_tb.v @@ -0,0 +1,23 @@ +module counter_tb; + reg clk; + always #5 clk = (clk === 1'b0); + + wire outa, outb, outc, outd; + + chip uut ( + .clk(clk), + .cen(1'b1), + .rst(1'b0), + .outa(outa), + .outb(outb), + .outc(outc), + .outd(outd) + ); + + initial begin + $dumpfile("counter_tb.vcd"); + $dumpvars(0, counter_tb); + repeat (100000) @(posedge clk); + $finish; + end +endmodule diff --git a/xc7/carry_tests/test.pcf b/xc7/carry_tests/test.pcf new file mode 100644 index 00000000..8cd488bf --- /dev/null +++ b/xc7/carry_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/xc7/carry_tests/test.sh b/xc7/carry_tests/test.sh new file mode 100755 index 00000000..0ba63365 --- /dev/null +++ b/xc7/carry_tests/test.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +set -ex +NAME=${1%.v} +yosys -p "synth_ice40 -top top; write_json ${NAME}.json" $1 +../../nextpnr-ice40 --json ${NAME}.json --pcf test.pcf --asc ${NAME}.asc --verbose +icebox_vlog -p test.pcf -L ${NAME}.asc > ${NAME}_out.v +iverilog -o ${NAME}_sim.out ${NAME}_tb.v ${NAME}_out.v +vvp ${NAME}_sim.out + diff --git a/xc7/cells.cc b/xc7/cells.cc new file mode 100644 index 00000000..5bdc7990 --- /dev/null +++ b/xc7/cells.cc @@ -0,0 +1,409 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski + * + * 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 "cells.h" +#include "design_utils.h" +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir) +{ + IdString id = ctx->id(name); + cell->ports[id] = PortInfo{id, nullptr, dir}; +} + +std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::string name) +{ + static int auto_idx = 0; + std::unique_ptr new_cell = std::unique_ptr(new CellInfo()); + if (name.empty()) { + new_cell->name = ctx->id("$nextpnr_" + type.str(ctx) + "_" + std::to_string(auto_idx++)); + } else { + new_cell->name = ctx->id(name); + } + new_cell->type = type; + if (type == ctx->id("ICESTORM_LC")) { + new_cell->params[ctx->id("LUT_INIT")] = "0"; + new_cell->params[ctx->id("NEG_CLK")] = "0"; + new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; + new_cell->params[ctx->id("DFF_ENABLE")] = "0"; + new_cell->params[ctx->id("SET_NORESET")] = "0"; + new_cell->params[ctx->id("ASYNC_SR")] = "0"; + new_cell->params[ctx->id("CIN_CONST")] = "0"; + new_cell->params[ctx->id("CIN_SET")] = "0"; + + add_port(ctx, new_cell.get(), "I0", PORT_IN); + add_port(ctx, new_cell.get(), "I1", PORT_IN); + add_port(ctx, new_cell.get(), "I2", PORT_IN); + add_port(ctx, new_cell.get(), "I3", PORT_IN); + add_port(ctx, new_cell.get(), "CIN", PORT_IN); + + add_port(ctx, new_cell.get(), "CLK", PORT_IN); + add_port(ctx, new_cell.get(), "CEN", PORT_IN); + add_port(ctx, new_cell.get(), "SR", PORT_IN); + + add_port(ctx, new_cell.get(), "LO", PORT_OUT); + add_port(ctx, new_cell.get(), "O", PORT_OUT); + add_port(ctx, new_cell.get(), "COUT", PORT_OUT); + } else if (type == ctx->id("SB_IO")) { + new_cell->params[ctx->id("PIN_TYPE")] = "0"; + new_cell->params[ctx->id("PULLUP")] = "0"; + new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; + + add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); + + add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); + add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); + add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); + add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); + + add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); + add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); + add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); + + add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); + add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); + } else if (type == ctx->id("ICESTORM_RAM")) { + new_cell->params[ctx->id("NEG_CLK_W")] = "0"; + new_cell->params[ctx->id("NEG_CLK_R")] = "0"; + new_cell->params[ctx->id("WRITE_MODE")] = "0"; + new_cell->params[ctx->id("READ_MODE")] = "0"; + + add_port(ctx, new_cell.get(), "RCLK", PORT_IN); + add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); + add_port(ctx, new_cell.get(), "RE", PORT_IN); + + add_port(ctx, new_cell.get(), "WCLK", PORT_IN); + add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); + add_port(ctx, new_cell.get(), "WE", PORT_IN); + + for (int i = 0; i < 16; i++) { + add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); + } + + for (int i = 0; i < 11; i++) { + add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); + } + } else if (type == ctx->id("ICESTORM_LFOSC")) { + add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); + add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); + add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); + add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); + } else if (type == ctx->id("ICESTORM_HFOSC")) { + new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; + new_cell->params[ctx->id("TRIM_EN")] = "0b0"; + + add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); + add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); + add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); + add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); + for (int i = 0; i < 10; i++) + add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); + } else if (type == ctx->id("SB_GB")) { + add_port(ctx, new_cell.get(), "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN); + add_port(ctx, new_cell.get(), "GLOBAL_BUFFER_OUTPUT", PORT_OUT); + } else if (type == ctx->id("ICESTORM_SPRAM")) { + add_port(ctx, new_cell.get(), "WREN", PORT_IN); + add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); + add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); + add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); + add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); + add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); + + for (int i = 0; i < 16; i++) { + add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); + } + for (int i = 0; i < 14; i++) { + add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); + } + for (int i = 0; i < 4; i++) { + add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); + } + } else if (type == ctx->id("ICESTORM_DSP")) { + new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + + new_cell->params[ctx->id("C_REG")] = "0"; + new_cell->params[ctx->id("A_REG")] = "0"; + new_cell->params[ctx->id("B_REG")] = "0"; + new_cell->params[ctx->id("D_REG")] = "0"; + new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; + new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; + new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; + + new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; + new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; + + new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; + new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; + + new_cell->params[ctx->id("MODE_8x8")] = "0"; + new_cell->params[ctx->id("A_SIGNED")] = "0"; + new_cell->params[ctx->id("B_SIGNED")] = "0"; + + add_port(ctx, new_cell.get(), "CLK", PORT_IN); + add_port(ctx, new_cell.get(), "CE", PORT_IN); + for (int i = 0; i < 16; i++) { + add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); + add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); + } + add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); + add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); + + add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); + add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); + add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); + add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); + add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); + add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); + add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); + + add_port(ctx, new_cell.get(), "CI", PORT_IN); + add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); + add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); + + for (int i = 0; i < 32; i++) { + add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); + } + + add_port(ctx, new_cell.get(), "CO", PORT_OUT); + add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); + add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); + + } else if (type == ctx->id("ICESTORM_PLL")) { + new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; + new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; + + new_cell->params[ctx->id("DIVF")] = "0"; + new_cell->params[ctx->id("DIVQ")] = "0"; + new_cell->params[ctx->id("DIVR")] = "0"; + + new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; + new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; + new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; + new_cell->params[ctx->id("FILTER_RANGE")] = "0"; + + new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; + new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; + + new_cell->params[ctx->id("PLLTYPE")] = "0"; + new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; + new_cell->params[ctx->id("TEST_MODE")] = "0"; + + add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); + add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); + add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); + add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); + add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); + add_port(ctx, new_cell.get(), "RESETB", PORT_IN); + + add_port(ctx, new_cell.get(), "SCLK", PORT_IN); + add_port(ctx, new_cell.get(), "SDI", PORT_IN); + add_port(ctx, new_cell.get(), "SDI", PORT_OUT); + + add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); + add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); + add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); + } else { + log_error("unable to create iCE40 cell of type %s", type.c_str(ctx)); + } + return new_cell; +} + +void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) +{ + lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; + replace_port(lut, ctx->id("I0"), lc, ctx->id("I0")); + replace_port(lut, ctx->id("I1"), lc, ctx->id("I1")); + replace_port(lut, ctx->id("I2"), lc, ctx->id("I2")); + replace_port(lut, ctx->id("I3"), lc, ctx->id("I3")); + if (no_dff) { + replace_port(lut, ctx->id("O"), lc, ctx->id("O")); + lc->params[ctx->id("DFF_ENABLE")] = "0"; + } +} + +void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) +{ + lc->params[ctx->id("DFF_ENABLE")] = "1"; + std::string config = dff->type.str(ctx).substr(6); + auto citer = config.begin(); + replace_port(dff, ctx->id("C"), lc, ctx->id("CLK")); + + if (citer != config.end() && *citer == 'N') { + lc->params[ctx->id("NEG_CLK")] = "1"; + ++citer; + } else { + lc->params[ctx->id("NEG_CLK")] = "0"; + } + + if (citer != config.end() && *citer == 'E') { + replace_port(dff, ctx->id("E"), lc, ctx->id("CEN")); + ++citer; + } + + if (citer != config.end()) { + if ((config.end() - citer) >= 2) { + char c = *(citer++); + NPNR_ASSERT(c == 'S'); + lc->params[ctx->id("ASYNC_SR")] = "0"; + } else { + lc->params[ctx->id("ASYNC_SR")] = "1"; + } + + if (*citer == 'S') { + citer++; + replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); + lc->params[ctx->id("SET_NORESET")] = "1"; + } else { + NPNR_ASSERT(*citer == 'R'); + citer++; + replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); + lc->params[ctx->id("SET_NORESET")] = "0"; + } + } + + NPNR_ASSERT(citer == config.end()); + + if (pass_thru_lut) { + lc->params[ctx->id("LUT_INIT")] = "2"; + replace_port(dff, ctx->id("D"), lc, ctx->id("I0")); + } + + replace_port(dff, ctx->id("Q"), lc, ctx->id("O")); +} + +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) +{ + if (nxio->type == ctx->id("$nextpnr_ibuf")) { + sbio->params[ctx->id("PIN_TYPE")] = "1"; + auto pu_attr = nxio->attrs.find(ctx->id("PULLUP")); + if (pu_attr != nxio->attrs.end()) + sbio->params[ctx->id("PULLUP")] = pu_attr->second; + replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); + } else if (nxio->type == ctx->id("$nextpnr_obuf")) { + sbio->params[ctx->id("PIN_TYPE")] = "25"; + replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); + } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { + // N.B. tristate will be dealt with below + sbio->params[ctx->id("PIN_TYPE")] = "25"; + replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); + replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); + } else { + NPNR_ASSERT(false); + } + NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net; + CellInfo *tbuf = net_driven_by( + ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, + ctx->id("Y")); + if (tbuf) { + sbio->params[ctx->id("PIN_TYPE")] = "41"; + replace_port(tbuf, ctx->id("A"), sbio, ctx->id("D_OUT_0")); + replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE")); + ctx->nets.erase(donet->name); + if (!donet->users.empty()) + log_error("unsupported tristate IO pattern for IO buffer '%s', " + "instantiate SB_IO manually to ensure correct behaviour\n", + nxio->name.c_str(ctx)); + ctx->cells.erase(tbuf->name); + } +} + +uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell) +{ + if (cell->type == ctx->id("SB_PLL40_PAD")) + return 2; + if (cell->type == ctx->id("SB_PLL40_2_PAD")) + return 4; + if (cell->type == ctx->id("SB_PLL40_2F_PAD")) + return 5; + if (cell->type == ctx->id("SB_PLL40_CORE")) + return 3; + if (cell->type == ctx->id("SB_PLL40_2F_CORE")) + return 7; + NPNR_ASSERT(0); +} + +bool is_clock_port(const BaseCtx *ctx, const PortRef &port) +{ + if (port.cell == nullptr) + return false; + if (is_ff(ctx, port.cell)) + return port.port == ctx->id("C"); + if (port.cell->type == ctx->id("ICESTORM_LC")) + return port.port == ctx->id("CLK"); + if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) + return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") || + port.port == ctx->id("WCLKN"); + if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + return port.port == ctx->id("CLK"); + return false; +} + +bool is_reset_port(const BaseCtx *ctx, const PortRef &port) +{ + if (port.cell == nullptr) + return false; + if (is_ff(ctx, port.cell)) + return port.port == ctx->id("R") || port.port == ctx->id("S"); + if (port.cell->type == ctx->id("ICESTORM_LC")) + return port.port == ctx->id("SR"); + if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + return port.port == ctx->id("IRSTTOP") || port.port == ctx->id("IRSTBOT") || port.port == ctx->id("ORSTTOP") || + port.port == ctx->id("ORSTBOT"); + return false; +} + +bool is_enable_port(const BaseCtx *ctx, const PortRef &port) +{ + if (port.cell == nullptr) + return false; + if (is_ff(ctx, port.cell)) + return port.port == ctx->id("E"); + if (port.cell->type == ctx->id("ICESTORM_LC")) + return port.port == ctx->id("CEN"); + // FIXME + // if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) + // return port.port == ctx->id("CE"); + return false; +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/cells.h b/xc7/cells.h new file mode 100644 index 00000000..16135448 --- /dev/null +++ b/xc7/cells.h @@ -0,0 +1,114 @@ +/* + * 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 "nextpnr.h" + +#ifndef ICE40_CELLS_H +#define ICE40_CELLS_H + +NEXTPNR_NAMESPACE_BEGIN + +// Create a standard iCE40 cell and return it +// Name will be automatically assigned if not specified +std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::string name = ""); + +// Return true if a cell is a LUT +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); } + +// Return true if a cell is a flipflop +inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") || + cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") || + cell->type == ctx->id("SB_DFFESR") || cell->type == ctx->id("SB_DFFER") || + cell->type == ctx->id("SB_DFFESS") || cell->type == ctx->id("SB_DFFES") || + cell->type == ctx->id("SB_DFFN") || cell->type == ctx->id("SB_DFFNE") || + cell->type == ctx->id("SB_DFFNSR") || cell->type == ctx->id("SB_DFFNR") || + cell->type == ctx->id("SB_DFFNSS") || cell->type == ctx->id("SB_DFFNS") || + cell->type == ctx->id("SB_DFFNESR") || cell->type == ctx->id("SB_DFFNER") || + cell->type == ctx->id("SB_DFFNESS") || cell->type == ctx->id("SB_DFFNES"); +} + +inline bool is_carry(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); } + +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); } + +// Return true if a cell is a SB_IO +inline bool is_sb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); } + +// Return true if a cell is a global buffer +inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); } + +// Return true if a cell is a RAM +inline bool is_ram(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_RAM40_4K") || cell->type == ctx->id("SB_RAM40_4KNR") || + cell->type == ctx->id("SB_RAM40_4KNW") || cell->type == ctx->id("SB_RAM40_4KNRNW"); +} + +inline bool is_sb_lfosc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LFOSC"); } + +inline bool is_sb_hfosc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_HFOSC"); } + +inline bool is_sb_spram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_SPRAM256KA"); } + +inline bool is_sb_mac16(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_MAC16"); } + +inline bool is_sb_pll40(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") || + cell->type == ctx->id("SB_PLL40_2F_PAD") || cell->type == ctx->id("SB_PLL40_CORE") || + cell->type == ctx->id("SB_PLL40_2F_CORE"); +} + +inline bool is_sb_pll40_pad(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == ctx->id("SB_PLL40_PAD") || cell->type == ctx->id("SB_PLL40_2_PAD") || + cell->type == ctx->id("SB_PLL40_2F_PAD"); +} + +uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell); + +// 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(const Context *ctx, 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 +// ignored +void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut = false); + +// Convert a nextpnr IO buffer to a SB_IO +void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio); + +// Return true if a port is a clock port +bool is_clock_port(const BaseCtx *ctx, const PortRef &port); + +// Return true if a port is a reset port +bool is_reset_port(const BaseCtx *ctx, const PortRef &port); + +// Return true if a port is a clock enable port +bool is_enable_port(const BaseCtx *ctx, const PortRef &port); + +NEXTPNR_NAMESPACE_END + +#endif diff --git a/xc7/chains.cc b/xc7/chains.cc new file mode 100644 index 00000000..bb20b60b --- /dev/null +++ b/xc7/chains.cc @@ -0,0 +1,287 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * 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 "chains.h" +#include +#include +#include "cells.h" +#include "design_utils.h" +#include "log.h" +#include "place_common.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +struct CellChain +{ + std::vector cells; +}; + +// Generic chain finder +template +std::vector find_chains(const Context *ctx, F1 cell_type_predicate, F2 get_previous, F3 get_next, + size_t min_length = 2) +{ + std::set chained; + std::vector chains; + for (auto cell : sorted(ctx->cells)) { + if (chained.find(cell.first) != chained.end()) + continue; + CellInfo *ci = cell.second; + if (cell_type_predicate(ctx, ci)) { + CellInfo *start = ci; + CellInfo *prev_start = ci; + while (prev_start != nullptr) { + start = prev_start; + prev_start = get_previous(ctx, start); + } + CellChain chain; + CellInfo *end = start; + while (end != nullptr) { + chain.cells.push_back(end); + end = get_next(ctx, end); + } + if (chain.cells.size() >= min_length) { + chains.push_back(chain); + for (auto c : chain.cells) + chained.insert(c->name); + } + } + } + return chains; +} + +class ChainConstrainer +{ + private: + Context *ctx; + // Split a carry chain into multiple legal chains + std::vector split_carry_chain(CellChain &carryc) + { + bool start_of_chain = true; + std::vector chains; + std::vector tile; + const int max_length = (ctx->chip_info->height - 2) * 8 - 2; + auto curr_cell = carryc.cells.begin(); + while (curr_cell != carryc.cells.end()) { + CellInfo *cell = *curr_cell; + if (tile.size() >= 8) { + tile.clear(); + } + if (start_of_chain) { + tile.clear(); + chains.emplace_back(); + start_of_chain = false; + if (cell->ports.at(ctx->id("CIN")).net) { + // CIN is not constant and not part of a chain. Must feed in from fabric + CellInfo *feedin = make_carry_feed_in(cell, cell->ports.at(ctx->id("CIN"))); + chains.back().cells.push_back(feedin); + tile.push_back(feedin); + } + } + tile.push_back(cell); + chains.back().cells.push_back(cell); + bool split_chain = (!ctx->logicCellsCompatible(tile.data(), tile.size())) || (int(chains.back().cells.size()) > max_length); + if (split_chain) { + CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); + tile.pop_back(); + chains.back().cells.back() = passout; + start_of_chain = true; + } else { + NetInfo *carry_net = cell->ports.at(ctx->id("COUT")).net; + bool at_end = (curr_cell == carryc.cells.end() - 1); + if (carry_net != nullptr && (carry_net->users.size() > 1 || at_end)) { + if (carry_net->users.size() > 2 || + (net_only_drives(ctx, carry_net, is_lc, ctx->id("I3"), false) != + net_only_drives(ctx, carry_net, is_lc, ctx->id("CIN"), false)) || + (at_end && !net_only_drives(ctx, carry_net, is_lc, ctx->id("I3"), true))) { + CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); + chains.back().cells.push_back(passout); + tile.push_back(passout); + start_of_chain = true; + } + } + ++curr_cell; + } + } + return chains; + } + + // Insert a logic cell to legalise a COUT->fabric connection + CellInfo *make_carry_pass_out(PortInfo &cout_port) + { + NPNR_ASSERT(cout_port.net != nullptr); + std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + lc->params[ctx->id("LUT_INIT")] = "65280"; // 0xff00: O = I3 + lc->params[ctx->id("CARRY_ENABLE")] = "1"; + lc->ports.at(ctx->id("O")).net = cout_port.net; + std::unique_ptr co_i3_net(new NetInfo()); + co_i3_net->name = ctx->id(lc->name.str(ctx) + "$I3"); + co_i3_net->driver = cout_port.net->driver; + PortRef i3_r; + i3_r.port = ctx->id("I3"); + i3_r.cell = lc.get(); + co_i3_net->users.push_back(i3_r); + PortRef o_r; + o_r.port = ctx->id("O"); + o_r.cell = lc.get(); + cout_port.net->driver = o_r; + lc->ports.at(ctx->id("I3")).net = co_i3_net.get(); + cout_port.net = co_i3_net.get(); + + IdString co_i3_name = co_i3_net->name; + NPNR_ASSERT(ctx->nets.find(co_i3_name) == ctx->nets.end()); + ctx->nets[co_i3_name] = std::move(co_i3_net); + IdString name = lc->name; + ctx->assignCellInfo(lc.get()); + ctx->cells[lc->name] = std::move(lc); + return ctx->cells[name].get(); + } + + // Insert a logic cell to legalise a CIN->fabric connection + CellInfo *make_carry_feed_in(CellInfo *cin_cell, PortInfo &cin_port) + { + NPNR_ASSERT(cin_port.net != nullptr); + std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + lc->params[ctx->id("CARRY_ENABLE")] = "1"; + lc->params[ctx->id("CIN_CONST")] = "1"; + lc->params[ctx->id("CIN_SET")] = "1"; + lc->ports.at(ctx->id("I1")).net = cin_port.net; + cin_port.net->users.erase(std::remove_if(cin_port.net->users.begin(), cin_port.net->users.end(), + [cin_cell, cin_port](const PortRef &usr) { + return usr.cell == cin_cell && usr.port == cin_port.name; + })); + + PortRef i1_ref; + i1_ref.cell = lc.get(); + i1_ref.port = ctx->id("I1"); + lc->ports.at(ctx->id("I1")).net->users.push_back(i1_ref); + + std::unique_ptr out_net(new NetInfo()); + out_net->name = ctx->id(lc->name.str(ctx) + "$O"); + + PortRef drv_ref; + drv_ref.port = ctx->id("COUT"); + drv_ref.cell = lc.get(); + out_net->driver = drv_ref; + lc->ports.at(ctx->id("COUT")).net = out_net.get(); + + PortRef usr_ref; + usr_ref.port = cin_port.name; + usr_ref.cell = cin_cell; + out_net->users.push_back(usr_ref); + cin_cell->ports.at(cin_port.name).net = out_net.get(); + + IdString out_net_name = out_net->name; + NPNR_ASSERT(ctx->nets.find(out_net_name) == ctx->nets.end()); + ctx->nets[out_net_name] = std::move(out_net); + + IdString name = lc->name; + ctx->assignCellInfo(lc.get()); + ctx->cells[lc->name] = std::move(lc); + return ctx->cells[name].get(); + } + + void process_carries() + { + std::vector carry_chains = + find_chains(ctx, [](const Context *ctx, const CellInfo *cell) { return is_lc(ctx, cell); }, + [](const Context *ctx, const + + CellInfo *cell) { + CellInfo *carry_prev = + net_driven_by(ctx, cell->ports.at(ctx->id("CIN")).net, is_lc, ctx->id("COUT")); + if (carry_prev != nullptr) + return carry_prev; + /*CellInfo *i3_prev = net_driven_by(ctx, cell->ports.at(ctx->id("I3")).net, is_lc, + ctx->id("COUT")); if (i3_prev != nullptr) return i3_prev;*/ + return (CellInfo *)nullptr; + }, + [](const Context *ctx, const CellInfo *cell) { + CellInfo *carry_next = net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_lc, + ctx->id("CIN"), false); + if (carry_next != nullptr) + return carry_next; + /*CellInfo *i3_next = + net_only_drives(ctx, cell->ports.at(ctx->id("COUT")).net, is_lc, ctx->id("I3"), + false); if (i3_next != nullptr) return i3_next;*/ + return (CellInfo *)nullptr; + }); + std::unordered_set chained; + for (auto &base_chain : carry_chains) { + for (auto c : base_chain.cells) + chained.insert(c->name); + } + // Any cells not in chains, but with carry enabled, must also be put in a single-carry chain + // for correct processing + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (chained.find(cell.first) == chained.end() && is_lc(ctx, ci) && + bool_or_default(ci->params, ctx->id("CARRY_ENABLE"))) { + CellChain sChain; + sChain.cells.push_back(ci); + chained.insert(cell.first); + carry_chains.push_back(sChain); + } + } + std::vector all_chains; + // Chain splitting + for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } + std::vector split_chains = split_carry_chain(base_chain); + for (auto &chain : split_chains) { + all_chains.push_back(chain); + } + } + // Actual chain placement + for (auto &chain : all_chains) { + if (ctx->verbose) + log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); + + // Place carry chain + chain.cells.at(0)->constr_abs_z = true; + chain.cells.at(0)->constr_z = 0; + for (int i = 1; i < int(chain.cells.size()); i++) { + chain.cells.at(i)->constr_x = 0; + chain.cells.at(i)->constr_y = (i / 8); + chain.cells.at(i)->constr_z = i % 8; + chain.cells.at(i)->constr_abs_z = true; + chain.cells.at(i)->constr_parent = chain.cells.at(0); + chain.cells.at(0)->constr_children.push_back(chain.cells.at(i)); + } + } + } + + public: + ChainConstrainer(Context *ctx) : ctx(ctx){}; + void constrain_chains() { process_carries(); } +}; + +void constrain_chains(Context *ctx) +{ + log_info("Constraining chains...\n"); + ChainConstrainer(ctx).constrain_chains(); +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/chains.h b/xc7/chains.h new file mode 100644 index 00000000..98112303 --- /dev/null +++ b/xc7/chains.h @@ -0,0 +1,27 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * 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 "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +// This finds chains, inserts LCs to legalise them as needed, and sets relative constraints as appropriate +void constrain_chains(Context *ctx); + +NEXTPNR_NAMESPACE_END diff --git a/xc7/chipdb.py b/xc7/chipdb.py new file mode 100644 index 00000000..7bdf82f0 --- /dev/null +++ b/xc7/chipdb.py @@ -0,0 +1,1280 @@ +#!/usr/bin/env python3 + +import sys +import re +import textwrap +import argparse + +parser = argparse.ArgumentParser(description="convert ICE40 chip database") +parser.add_argument("filename", type=str, help="chipdb input filename") +parser.add_argument("-p", "--constids", type=str, help="path to constids.inc") +parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h") +parser.add_argument("--fast", type=str, help="path to timing data for fast part") +parser.add_argument("--slow", type=str, help="path to timing data for slow part") +args = parser.parse_args() + +dev_name = None +dev_width = None +dev_height = None +num_wires = None + +tiles = dict() + +wire_uphill = dict() +wire_downhill = dict() +pip_xy = dict() + +bel_name = list() +bel_type = list() +bel_pos = list() +bel_wires = list() + +switches = list() + +ierens = list() + +extra_cells = dict() +extra_cell_config = dict() +packages = list() + +wire_belports = dict() + +wire_names = dict() +wire_names_r = dict() +wire_xy = dict() + +cbit_re = re.compile(r'B(\d+)\[(\d+)\]') + +constids = dict() +tiletypes = dict() +wiretypes = dict() + +gfx_wire_ids = dict() +wire_segments = dict() + +fast_timings = None +slow_timings = None + +with open(args.constids) as f: + for line in f: + if line.startswith("//"): + continue + line = line.replace("(", " ") + line = line.replace(")", " ") + line = line.split() + if len(line) == 0: + continue + assert len(line) == 2 + assert line[0] == "X" + idx = len(constids) + 1 + constids[line[1]] = idx + +constids["PLL"] = constids["ICESTORM_PLL"] +constids["WARMBOOT"] = constids["SB_WARMBOOT"] +constids["MAC16"] = constids["ICESTORM_DSP"] +constids["HFOSC"] = constids["ICESTORM_HFOSC"] +constids["LFOSC"] = constids["ICESTORM_LFOSC"] +constids["I2C"] = constids["SB_I2C"] +constids["SPI"] = constids["SB_SPI"] +constids["LEDDA_IP"] = constids["SB_LEDDA_IP"] +constids["RGBA_DRV"] = constids["SB_RGBA_DRV"] +constids["SPRAM"] = constids["ICESTORM_SPRAM"] + +with open(args.gfxh) as f: + state = 0 + for line in f: + if state == 0 and line.startswith("enum GfxTileWireId"): + state = 1 + elif state == 1 and line.startswith("};"): + state = 0 + elif state == 1 and (line.startswith("{") or line.strip() == ""): + pass + elif state == 1: + idx = len(gfx_wire_ids) + name = line.strip().rstrip(",") + gfx_wire_ids[name] = idx + +def read_timings(filename): + db = dict() + with open(filename) as f: + cell = None + for line in f: + line = line.split() + if len(line) == 0: + continue + if line[0] == "CELL": + cell = line[1] + if line[0] == "IOPATH": + key = "%s.%s.%s" % (cell, line[1], line[2]) + v1 = line[3].split(":")[2] + v2 = line[4].split(":")[2] + v1 = 0 if v1 == "*" else float(v1) + v2 = 0 if v2 == "*" else float(v2) + db[key] = max(v1, v2) + return db + +if args.fast is not None: + fast_timings = read_timings(args.fast) + +if args.slow is not None: + slow_timings = read_timings(args.slow) + +tiletypes["NONE"] = 0 +tiletypes["LOGIC"] = 1 +tiletypes["IO"] = 2 +tiletypes["RAMB"] = 3 +tiletypes["RAMT"] = 4 +tiletypes["DSP0"] = 5 +tiletypes["DSP1"] = 6 +tiletypes["DSP2"] = 7 +tiletypes["DSP3"] = 8 +tiletypes["IPCON"] = 9 + +wiretypes["NONE"] = 0 +wiretypes["GLB2LOCAL"] = 1 +wiretypes["GLB_NETWK"] = 2 +wiretypes["LOCAL"] = 3 +wiretypes["LUTFF_IN"] = 4 +wiretypes["LUTFF_IN_LUT"] = 5 +wiretypes["LUTFF_LOUT"] = 6 +wiretypes["LUTFF_OUT"] = 7 +wiretypes["LUTFF_COUT"] = 8 +wiretypes["LUTFF_GLOBAL"] = 9 +wiretypes["CARRY_IN_MUX"] = 10 +wiretypes["SP4_V"] = 11 +wiretypes["SP4_H"] = 12 +wiretypes["SP12_V"] = 13 +wiretypes["SP12_H"] = 14 + +def maj_wire_name(name): + if name[2].startswith("lutff_"): + return True + if name[2].startswith("io_"): + return True + if name[2].startswith("ram/"): + return True + if name[2].startswith("sp4_h_r_"): + return name[2] in ("sp4_h_r_0", "sp4_h_r_1", "sp4_h_r_2", "sp4_h_r_3", "sp4_h_r_4", "sp4_h_r_5", + "sp4_h_r_6", "sp4_h_r_7", "sp4_h_r_8", "sp4_h_r_9", "sp4_h_r_10", "sp4_h_r_11") + if name[2].startswith("sp4_v_b_"): + return name[2] in ("sp4_v_b_0", "sp4_v_b_1", "sp4_v_b_2", "sp4_v_b_3", "sp4_v_b_4", "sp4_v_b_5", + "sp4_v_b_6", "sp4_v_b_7", "sp4_v_b_8", "sp4_v_b_9", "sp4_v_b_10", "sp4_v_b_11") + if name[2].startswith("sp12_h_r_"): + return name[2] in ("sp12_h_r_0", "sp12_h_r_1") + if name[2].startswith("sp12_v_b_"): + return name[2] in ("sp12_v_b_0", "sp12_v_b_1") + return False + +def cmp_wire_names(newname, oldname): + if maj_wire_name(newname): + return True + if maj_wire_name(oldname): + return False + + if newname[2].startswith("sp") and oldname[2].startswith("sp"): + m1 = re.match(r".*_(\d+)$", newname[2]) + m2 = re.match(r".*_(\d+)$", oldname[2]) + if m1 and m2: + idx1 = int(m1.group(1)) + idx2 = int(m2.group(1)) + if idx1 != idx2: + return idx1 < idx2 + + return newname < oldname + +def wire_type(name): + longname = name + name = name.split('/') + + if name[0].startswith("X") and name[1].startswith("Y"): + name = name[2:] + + if name[0].startswith("sp4_v_") or name[0].startswith("sp4_r_v_") or name[0].startswith("span4_vert_"): + return "SP4_V" + + if name[0].startswith("sp4_h_") or name[0].startswith("span4_horz_"): + return "SP4_H" + + if name[0].startswith("sp12_v_") or name[0].startswith("span12_vert_"): + return "SP12_V" + + if name[0].startswith("sp12_h_") or name[0].startswith("span12_horz_"): + return "SP12_H" + + if name[0].startswith("glb2local"): + return "GLB2LOCAL" + + if name[0].startswith("glb_netwk_"): + return "GLB_NETWK" + + if name[0].startswith("local_"): + return "LOCAL" + + if name[0].startswith("lutff_"): + if name[1].startswith("in_"): + return "LUTFF_IN_LUT" if name[1].endswith("_lut") else "LUTFF_IN" + + if name[1] == "lout": + return "LUTFF_LOUT" + if name[1] == "out": + return "LUTFF_OUT" + if name[1] == "cout": + return "LUTFF_COUT" + + if name[0] == "ram": + if name[1].startswith("RADDR_"): + return "LUTFF_IN" + if name[1].startswith("WADDR_"): + return "LUTFF_IN" + if name[1].startswith("WDATA_"): + return "LUTFF_IN" + if name[1].startswith("MASK_"): + return "LUTFF_IN" + if name[1].startswith("RDATA_"): + return "LUTFF_OUT" + if name[1] in ("WCLK", "WCLKE", "WE", "RCLK", "RCLKE", "RE"): + return "LUTFF_GLOBAL" + + if name[0].startswith("io_"): + if name[1].startswith("D_IN_") or name[1] == "OUT_ENB": + return "LUTFF_IN" + if name[1].startswith("D_OUT_"): + return "LUTFF_OUT" + if name[0] == "fabout": + return "LUTFF_IN" + + if name[0] == "lutff_global" or name[0] == "io_global": + return "LUTFF_GLOBAL" + + if name[0] == "carry_in_mux": + return "CARRY_IN_MUX" + + if name[0] == "carry_in": + return "LUTFF_COUT" + + if name[0].startswith("neigh_op_"): + return "NONE" + + if name[0].startswith("padin_"): + return "NONE" + + # print("No type for wire: %s (%s)" % (longname, name), file=sys.stderr) + # assert 0 + + return "NONE" + +def pipdelay(src_idx, dst_idx, db): + if db is None: + return 0 + + src = wire_names_r[src_idx] + dst = wire_names_r[dst_idx] + src_type = wire_type(src[2]) + dst_type = wire_type(dst[2]) + + if dst[2].startswith("sp4_") or dst[2].startswith("span4_"): + if src[2].startswith("sp12_") or src[2].startswith("span12_"): + return db["Sp12to4.I.O"] + + if src[2].startswith("span4_"): + return db["IoSpan4Mux.I.O"] + + if dst[2].startswith("sp4_h_"): + return db["Span4Mux_h4.I.O"] + else: + return db["Span4Mux_v4.I.O"] + + if dst[2].startswith("sp12_") or dst[2].startswith("span12_"): + if dst[2].startswith("sp12_h_"): + return db["Span12Mux_h12.I.O"] + else: + return db["Span12Mux_v12.I.O"] + + if dst[2] in ("fabout", "clk"): + return 0 # FIXME? + + if src[2].startswith("glb_netwk_") and dst[2].startswith("glb2local_"): + return 0 # FIXME? + + if dst[2] == "carry_in_mux": + return db["ICE_CARRY_IN_MUX.carryinitin.carryinitout"] + + if dst[2] in ("lutff_global/clk", "io_global/inclk", "io_global/outclk", "ram/RCLK", "ram/WCLK"): + return db["ClkMux.I.O"] + + if dst[2] in ("lutff_global/s_r", "io_global/latch", "ram/RE", "ram/WE"): + return db["SRMux.I.O"] + + if dst[2] in ("lutff_global/cen", "io_global/cen", "ram/RCLKE", "ram/WCLKE"): + return db["CEMux.I.O"] + + if dst[2].startswith("local_"): + return db["LocalMux.I.O"] + + if src[2].startswith("local_") and dst[2] in ("io_0/D_OUT_0", "io_0/D_OUT_1", "io_0/OUT_ENB", "io_1/D_OUT_0", "io_1/D_OUT_1", "io_1/OUT_ENB"): + return db["IoInMux.I.O"] + + if re.match(r"lutff_\d+/in_\d+$", dst[2]): + return db["InMux.I.O"] + + if re.match(r"lutff_\d+/in_\d+_lut", dst[2]): + return 0 + + if re.match(r"ram/(MASK|RADDR|WADDR|WDATA)_", dst[2]): + return db["InMux.I.O"] + + if re.match(r"lutff_\d+/out", dst[2]): + if re.match(r"lutff_\d+/in_0", src[2]): + return db["LogicCell40.in0.lcout"] + if re.match(r"lutff_\d+/in_1", src[2]): + return db["LogicCell40.in1.lcout"] + if re.match(r"lutff_\d+/in_2", src[2]): + return db["LogicCell40.in2.lcout"] + if re.match(r"lutff_\d+/in_3", src[2]): + return db["LogicCell40.in3.lcout"] + + print(src, dst, src_idx, dst_idx, src_type, dst_type, file=sys.stderr) + assert 0 + +def wiredelay(wire_idx, db): + if db is None: + return 0 + + wire = wire_names_r[wire_idx] + wtype = wire_type(wire[2]) + + # FIXME + return 0 + +def init_tiletypes(device): + global num_tile_types, tile_sizes, tile_bits + if device == "5k": + num_tile_types = 10 + else: + num_tile_types = 5 + tile_sizes = {i: (0, 0) for i in range(num_tile_types)} + tile_bits = [[] for _ in range(num_tile_types)] + +with open(args.filename, "r") as f: + mode = None + + for line in f: + line = line.split() + + if len(line) == 0 or line[0] == "#": + continue + + if line[0] == ".device": + dev_name = line[1] + init_tiletypes(dev_name) + dev_width = int(line[2]) + dev_height = int(line[3]) + num_wires = int(line[4]) + continue + + if line[0] == ".net": + mode = ("net", int(line[1])) + continue + + if line[0] == ".buffer": + mode = ("buffer", int(line[3]), int(line[1]), int(line[2])) + switches.append((int(line[1]), int(line[2]), line[4:], -1)) + continue + + if line[0] == ".routing": + mode = ("routing", int(line[3]), int(line[1]), int(line[2])) + switches.append((int(line[1]), int(line[2]), line[4:], -1)) + continue + + if line[0] == ".io_tile": + tiles[(int(line[1]), int(line[2]))] = "io" + mode = None + continue + + if line[0] == ".logic_tile": + tiles[(int(line[1]), int(line[2]))] = "logic" + mode = None + continue + + if line[0] == ".ramb_tile": + tiles[(int(line[1]), int(line[2]))] = "ramb" + mode = None + continue + + if line[0] == ".ramt_tile": + tiles[(int(line[1]), int(line[2]))] = "ramt" + mode = None + continue + + if line[0] == ".dsp0_tile": + tiles[(int(line[1]), int(line[2]))] = "dsp0" + mode = None + continue + + if line[0] == ".dsp1_tile": + tiles[(int(line[1]), int(line[2]))] = "dsp1" + mode = None + continue + + if line[0] == ".dsp2_tile": + tiles[(int(line[1]), int(line[2]))] = "dsp2" + mode = None + continue + + if line[0] == ".dsp3_tile": + tiles[(int(line[1]), int(line[2]))] = "dsp3" + mode = None + continue + + if line[0] == ".ipcon_tile": + tiles[(int(line[1]), int(line[2]))] = "ipcon" + mode = None + continue + + if line[0] == ".logic_tile_bits": + mode = ("bits", 1) + tile_sizes[1] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".io_tile_bits": + mode = ("bits", 2) + tile_sizes[2] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".ramb_tile_bits": + mode = ("bits", 3) + tile_sizes[3] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".ramt_tile_bits": + mode = ("bits", 4) + tile_sizes[4] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".dsp0_tile_bits": + mode = ("bits", 5) + tile_sizes[5] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".dsp1_tile_bits": + mode = ("bits", 6) + tile_sizes[6] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".dsp2_tile_bits": + mode = ("bits", 7) + tile_sizes[7] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".dsp3_tile_bits": + mode = ("bits", 8) + tile_sizes[8] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".ipcon_tile_bits": + mode = ("bits", 9) + tile_sizes[9] = (int(line[1]), int(line[2])) + continue + + if line[0] == ".ieren": + mode = ("ieren",) + continue + + if line[0] == ".pins": + mode = ("pins", line[1]) + packages.append((line[1], [])) + continue + + if line[0] == ".extra_cell": + if len(line) >= 5: + mode = ("extra_cell", (line[4], int(line[1]), int(line[2]), int(line[3]))) + elif line[3] == "WARMBOOT": + mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 0)) + elif line[3] == "PLL": + mode = ("extra_cell", (line[3], int(line[1]), int(line[2]), 3)) + else: + assert 0 + extra_cells[mode[1]] = [] + continue + + if (line[0][0] == ".") or (mode is None): + mode = None + continue + + if mode[0] == "net": + wname = (int(line[0]), int(line[1]), line[2]) + wire_names[wname] = mode[1] + if (mode[1] not in wire_names_r) or cmp_wire_names(wname, wire_names_r[mode[1]]): + wire_names_r[mode[1]] = wname + if mode[1] not in wire_xy: + wire_xy[mode[1]] = list() + wire_xy[mode[1]].append((int(line[0]), int(line[1]))) + if mode[1] not in wire_segments: + wire_segments[mode[1]] = dict() + if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids: + wire_segments[mode[1]][(wname[0], wname[1])] = wname[2] + continue + + if mode[0] in ("buffer", "routing"): + wire_a = int(line[1]) + wire_b = mode[1] + if wire_a not in wire_downhill: + wire_downhill[wire_a] = set() + if wire_b not in wire_uphill: + wire_uphill[wire_b] = set() + wire_downhill[wire_a].add(wire_b) + wire_uphill[wire_b].add(wire_a) + pip_xy[(wire_a, wire_b)] = (mode[2], mode[3], int(line[0], 2), len(switches) - 1, 0) + continue + + if mode[0] == "bits": + name = line[0] + bits = [] + for b in line[1:]: + m = cbit_re.match(b) + 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 + + if mode[0] == "extra_cell": + if line[0] == "LOCKED": + extra_cells[mode[1]].append((("LOCKED_" + line[1]), (0, 0, "LOCKED"))) + else: + extra_cells[mode[1]].append((line[0], (int(line[1]), int(line[2]), line[3]))) + continue + +def add_wire(x, y, name): + global num_wires + wire_idx = num_wires + num_wires = num_wires + 1 + wname = (x, y, name) + wire_names[wname] = wire_idx + wire_names_r[wire_idx] = wname + wire_segments[wire_idx] = dict() + if ("TILE_WIRE_" + wname[2].upper().replace("/", "_")) in gfx_wire_ids: + wire_segments[wire_idx][(wname[0], wname[1])] = wname[2] + return wire_idx + +def add_switch(x, y, bel=-1): + switches.append((x, y, [], bel)) + +def add_pip(src, dst, flags=0): + x, y, _, _ = switches[-1] + + if src not in wire_downhill: + wire_downhill[src] = set() + wire_downhill[src].add(dst) + + if dst not in wire_uphill: + wire_uphill[dst] = set() + wire_uphill[dst].add(src) + + pip_xy[(src, dst)] = (x, y, 0, len(switches) - 1, flags) + +# Add virtual padin wires +for i in range(8): + add_wire(0, 0, "padin_%d" % i) + +def add_bel_input(bel, wire, port): + if wire not in wire_belports: + wire_belports[wire] = set() + wire_belports[wire].add((bel, port)) + bel_wires[bel].append((constids[port], 0, wire)) + +def add_bel_output(bel, wire, port): + if wire not in wire_belports: + wire_belports[wire] = set() + wire_belports[wire].add((bel, port)) + bel_wires[bel].append((constids[port], 1, wire)) + +def add_bel_lc(x, y, z): + bel = len(bel_name) + bel_name.append("X%d/Y%d/lc%d" % (x, y, z)) + bel_type.append("ICESTORM_LC") + bel_pos.append((x, y, z)) + bel_wires.append(list()) + + wire_cen = wire_names[(x, y, "lutff_global/cen")] + wire_clk = wire_names[(x, y, "lutff_global/clk")] + wire_s_r = wire_names[(x, y, "lutff_global/s_r")] + + if z == 0: + wire_cin = wire_names[(x, y, "carry_in_mux")] + else: + wire_cin = wire_names[(x, y, "lutff_%d/cout" % (z-1))] + + wire_in_0 = add_wire(x, y, "lutff_%d/in_0_lut" % z) + wire_in_1 = add_wire(x, y, "lutff_%d/in_1_lut" % z) + wire_in_2 = add_wire(x, y, "lutff_%d/in_2_lut" % z) + wire_in_3 = add_wire(x, y, "lutff_%d/in_3_lut" % z) + + wire_out = wire_names[(x, y, "lutff_%d/out" % z)] + wire_cout = wire_names[(x, y, "lutff_%d/cout" % z)] + wire_lout = wire_names[(x, y, "lutff_%d/lout" % z)] if z < 7 else None + + add_bel_input(bel, wire_cen, "CEN") + add_bel_input(bel, wire_clk, "CLK") + add_bel_input(bel, wire_s_r, "SR") + add_bel_input(bel, wire_cin, "CIN") + + add_bel_input(bel, wire_in_0, "I0") + add_bel_input(bel, wire_in_1, "I1") + add_bel_input(bel, wire_in_2, "I2") + add_bel_input(bel, wire_in_3, "I3") + + add_bel_output(bel, wire_out, "O") + add_bel_output(bel, wire_cout, "COUT") + + if wire_lout is not None: + add_bel_output(bel, wire_lout, "LO") + + # route-through LUTs + add_switch(x, y, bel) + add_pip(wire_in_0, wire_out, 1) + add_pip(wire_in_1, wire_out, 1) + add_pip(wire_in_2, wire_out, 1) + add_pip(wire_in_3, wire_out, 1) + + # LUT permutation pips + for i in range(4): + add_switch(x, y, bel) + for j in range(4): + if (i == j) or ((i, j) == (1, 2)) or ((i, j) == (2, 1)): + flags = 0 + else: + flags = 2 + add_pip(wire_names[(x, y, "lutff_%d/in_%d" % (z, i))], + wire_names[(x, y, "lutff_%d/in_%d_lut" % (z, j))], flags) + +def add_bel_io(x, y, z): + bel = len(bel_name) + bel_name.append("X%d/Y%d/io%d" % (x, y, z)) + bel_type.append("SB_IO") + bel_pos.append((x, y, z)) + bel_wires.append(list()) + + wire_cen = wire_names[(x, y, "io_global/cen")] + wire_iclk = wire_names[(x, y, "io_global/inclk")] + wire_latch = wire_names[(x, y, "io_global/latch")] + wire_oclk = wire_names[(x, y, "io_global/outclk")] + + wire_din_0 = wire_names[(x, y, "io_%d/D_IN_0" % z)] + wire_din_1 = wire_names[(x, y, "io_%d/D_IN_1" % z)] + wire_dout_0 = wire_names[(x, y, "io_%d/D_OUT_0" % z)] + wire_dout_1 = wire_names[(x, y, "io_%d/D_OUT_1" % z)] + wire_out_en = wire_names[(x, y, "io_%d/OUT_ENB" % z)] + + add_bel_input(bel, wire_cen, "CLOCK_ENABLE") + add_bel_input(bel, wire_iclk, "INPUT_CLK") + add_bel_input(bel, wire_oclk, "OUTPUT_CLK") + add_bel_input(bel, wire_latch, "LATCH_INPUT_VALUE") + + add_bel_output(bel, wire_din_0, "D_IN_0") + add_bel_output(bel, wire_din_1, "D_IN_1") + + add_bel_input(bel, wire_dout_0, "D_OUT_0") + add_bel_input(bel, wire_dout_1, "D_OUT_1") + add_bel_input(bel, wire_out_en, "OUTPUT_ENABLE") + +def add_bel_ram(x, y): + bel = len(bel_name) + bel_name.append("X%d/Y%d/ram" % (x, y)) + bel_type.append("ICESTORM_RAM") + bel_pos.append((x, y, 0)) + bel_wires.append(list()) + + if (x, y, "ram/WE") in wire_names: + # iCE40 1K-style memories + y0, y1 = y, y+1 + else: + # iCE40 8K-style memories + y1, y0 = y, y+1 + + for i in range(16): + add_bel_input (bel, wire_names[(x, y0 if i < 8 else y1, "ram/MASK_%d" % i)], "MASK_%d" % i) + add_bel_input (bel, wire_names[(x, y0 if i < 8 else y1, "ram/WDATA_%d" % i)], "WDATA_%d" % i) + add_bel_output(bel, wire_names[(x, y0 if i < 8 else y1, "ram/RDATA_%d" % i)], "RDATA_%d" % i) + + for i in range(11): + add_bel_input(bel, wire_names[(x, y0, "ram/WADDR_%d" % i)], "WADDR_%d" % i) + add_bel_input(bel, wire_names[(x, y1, "ram/RADDR_%d" % i)], "RADDR_%d" % i) + + add_bel_input(bel, wire_names[(x, y0, "ram/WCLK")], "WCLK") + add_bel_input(bel, wire_names[(x, y0, "ram/WCLKE")], "WCLKE") + add_bel_input(bel, wire_names[(x, y0, "ram/WE")], "WE") + + add_bel_input(bel, wire_names[(x, y1, "ram/RCLK")], "RCLK") + add_bel_input(bel, wire_names[(x, y1, "ram/RCLKE")], "RCLKE") + add_bel_input(bel, wire_names[(x, y1, "ram/RE")], "RE") + +def add_bel_gb(xy, x, y, g): + if xy[0] != x or xy[1] != y: + return + + bel = len(bel_name) + bel_name.append("X%d/Y%d/gb" % (x, y)) + bel_type.append("SB_GB") + bel_pos.append((x, y, 2)) + bel_wires.append(list()) + + add_bel_input(bel, wire_names[(x, y, "fabout")], "USER_SIGNAL_TO_GLOBAL_BUFFER") + add_bel_output(bel, wire_names[(x, y, "glb_netwk_%d" % g)], "GLOBAL_BUFFER_OUTPUT") + +def is_ec_wire(ec_entry): + return ec_entry[1] in wire_names + +def is_ec_output(ec_entry): + wirename = ec_entry[1][2] + if "O_" in wirename or "slf_op_" in wirename: return True + if "neigh_op_" in wirename: return True + if "glb_netwk_" in wirename: return True + return False + +def is_ec_pll_clock_output(ec, ec_entry): + return ec[0] == 'PLL' and ec_entry[0] in ('PLLOUT_A', 'PLLOUT_B') + +def add_bel_ec(ec): + ectype, x, y, z = ec + bel = len(bel_name) + extra_cell_config[bel] = [] + bel_name.append("X%d/Y%d/%s_%d" % (x, y, ectype.lower(), z)) + bel_type.append(ectype) + bel_pos.append((x, y, z)) + bel_wires.append(list()) + for entry in extra_cells[ec]: + if is_ec_wire(entry) and "glb_netwk_" not in entry[1][2]: # TODO: osc glb output conflicts with GB + if is_ec_output(entry): + add_bel_output(bel, wire_names[entry[1]], entry[0]) + else: + add_bel_input(bel, wire_names[entry[1]], entry[0]) + elif is_ec_pll_clock_output(ec, entry): + x, y, z = entry[1] + z = 'io_{}/D_IN_0'.format(z) + add_bel_output(bel, wire_names[(x, y, z)], entry[0]) + else: + extra_cell_config[bel].append(entry) + +cell_timings = {} +tmport_to_constids = { + "posedge:clk": "CLK", + "ce": "CEN", + "sr": "SR", + "in0": "I0", + "in1": "I1", + "in2": "I2", + "in3": "I3", + "carryin": "CIN", + "carryout": "COUT", + "lcout": "O", + "ltout": "LO", + "posedge:RCLK": "RCLK", + "posedge:WCLK": "WCLK", + "RCLKE": "RCLKE", + "RE": "RE", + "WCLKE": "WCLKE", + "WE": "WE", + "posedge:CLOCK": "CLOCK", + "posedge:SLEEP": "SLEEP", + "USERSIGNALTOGLOBALBUFFER": "USER_SIGNAL_TO_GLOBAL_BUFFER", + "GLOBALBUFFEROUTPUT": "GLOBAL_BUFFER_OUTPUT" +} + +for i in range(16): + tmport_to_constids["RDATA[%d]" % i] = "RDATA_%d" % i + tmport_to_constids["WDATA[%d]" % i] = "WDATA_%d" % i + tmport_to_constids["MASK[%d]" % i] = "MASK_%d" % i + tmport_to_constids["DATAOUT[%d]" % i] = "DATAOUT_%d" % i + +for i in range(11): + tmport_to_constids["RADDR[%d]" % i] = "RADDR_%d" % i + tmport_to_constids["WADDR[%d]" % i] = "WADDR_%d" % i + +def add_cell_timingdata(bel_type, timing_cell, fast_db, slow_db): + timing_entries = [] + database = slow_db if slow_db is not None else fast_db + for key in database.keys(): + skey = key.split(".") + if skey[0] == timing_cell: + if skey[1] in tmport_to_constids and skey[2] in tmport_to_constids: + iport = tmport_to_constids[skey[1]] + oport = tmport_to_constids[skey[2]] + fastdel = fast_db[key] if fast_db is not None else 0 + slowdel = slow_db[key] if slow_db is not None else 0 + timing_entries.append((iport, oport, fastdel, slowdel)) + cell_timings[bel_type] = timing_entries + +add_cell_timingdata("ICESTORM_LC", "LogicCell40", fast_timings, slow_timings) +add_cell_timingdata("SB_GB", "ICE_GB", fast_timings, slow_timings) + +if dev_name != "384": + add_cell_timingdata("ICESTORM_RAM", "SB_RAM40_4K", fast_timings, slow_timings) +if dev_name == "5k": + add_cell_timingdata("SPRAM", "SB_SPRAM256KA", fast_timings, slow_timings) + + +for tile_xy, tile_type in sorted(tiles.items()): + if tile_type == "logic": + for i in range(8): + add_bel_lc(tile_xy[0], tile_xy[1], i) + + if tile_type == "io": + for i in range(2): + add_bel_io(tile_xy[0], tile_xy[1], i) + + if dev_name == "1k": + add_bel_gb(tile_xy, 7, 0, 0) + add_bel_gb(tile_xy, 7, 17, 1) + add_bel_gb(tile_xy, 13, 9, 2) + add_bel_gb(tile_xy, 0, 9, 3) + add_bel_gb(tile_xy, 6, 17, 4) + add_bel_gb(tile_xy, 6, 0, 5) + add_bel_gb(tile_xy, 0, 8, 6) + add_bel_gb(tile_xy, 13, 8, 7) + elif dev_name == "5k": + add_bel_gb(tile_xy, 13, 0, 0) + add_bel_gb(tile_xy, 13, 31, 1) + add_bel_gb(tile_xy, 19, 31, 2) + add_bel_gb(tile_xy, 6, 31, 3) + add_bel_gb(tile_xy, 12, 31, 4) + add_bel_gb(tile_xy, 12, 0, 5) + add_bel_gb(tile_xy, 6, 0, 6) + add_bel_gb(tile_xy, 19, 0, 7) + elif dev_name == "8k": + add_bel_gb(tile_xy, 33, 16, 7) + add_bel_gb(tile_xy, 0, 16, 6) + add_bel_gb(tile_xy, 17, 33, 1) + add_bel_gb(tile_xy, 17, 0, 0) + add_bel_gb(tile_xy, 0, 17, 3) + add_bel_gb(tile_xy, 33, 17, 2) + add_bel_gb(tile_xy, 16, 0, 5) + add_bel_gb(tile_xy, 16, 33, 4) + elif dev_name == "384": + add_bel_gb(tile_xy, 7, 4, 7) + add_bel_gb(tile_xy, 0, 4, 6) + add_bel_gb(tile_xy, 4, 9, 1) + add_bel_gb(tile_xy, 4, 0, 0) + add_bel_gb(tile_xy, 0, 5, 3) + add_bel_gb(tile_xy, 7, 5, 2) + add_bel_gb(tile_xy, 3, 0, 5) + add_bel_gb(tile_xy, 3, 9, 4) + + if tile_type == "ramb": + add_bel_ram(tile_xy[0], tile_xy[1]) + + for ec in sorted(extra_cells.keys()): + if ec[1] == tile_xy[0] and ec[2] == tile_xy[1]: + add_bel_ec(ec) + +for ec in sorted(extra_cells.keys()): + if ec[1] in (0, dev_width - 1) and ec[2] in (0, dev_height - 1): + add_bel_ec(ec) + +class BinaryBlobAssembler: + def l(self, name, ltype = None, export = False): + if ltype is None: + print("label %s" % (name,)) + else: + print("label %s %s" % (name, ltype)) + + def r(self, name, comment): + if comment is None: + print("ref %s" % (name,)) + else: + print("ref %s %s" % (name, comment)) + + def s(self, s, comment): + assert "|" not in s + print("str |%s| %s" % (s, comment)) + + def u8(self, v, comment): + if comment is None: + print("u8 %d" % (v,)) + else: + print("u8 %d %s" % (v, comment)) + + def u16(self, v, comment): + if comment is None: + print("u16 %d" % (v,)) + else: + print("u16 %d %s" % (v, comment)) + + def u32(self, v, comment): + if comment is None: + print("u32 %d" % (v,)) + else: + print("u32 %d %s" % (v, comment)) + + def pre(self, s): + print("pre %s" % s) + + def post(self, s): + print("post %s" % s) + + def push(self, name): + print("push %s" % name) + + def pop(self): + print("pop") + +bba = BinaryBlobAssembler() +bba.pre('#include "nextpnr.h"') +bba.pre('NEXTPNR_NAMESPACE_BEGIN') +bba.post('NEXTPNR_NAMESPACE_END') +bba.push("chipdb_blob_%s" % dev_name) +bba.r("chip_info_%s" % dev_name, "chip_info") + +for bel in range(len(bel_name)): + bba.l("bel_wires_%d" % bel, "BelWirePOD") + for data in sorted(bel_wires[bel]): + bba.u32(data[0], "port") + bba.u32(data[1], "type") + bba.u32(data[2], "wire_index") + +bba.l("bel_data_%s" % dev_name, "BelInfoPOD") +for bel in range(len(bel_name)): + bba.s(bel_name[bel], "name") + bba.u32(constids[bel_type[bel]], "type") + bba.u32(len(bel_wires[bel]), "num_bel_wires") + bba.r("bel_wires_%d" % bel, "bel_wires") + bba.u8(bel_pos[bel][0], "x") + bba.u8(bel_pos[bel][1], "y") + bba.u8(bel_pos[bel][2], "z") + bba.u8(0, "padding") + +wireinfo = list() +pipinfo = list() +pipcache = dict() + +for wire in range(num_wires): + if wire in wire_uphill: + pips = list() + for src in wire_uphill[wire]: + if (src, wire) not in pipcache: + pipcache[(src, wire)] = len(pipinfo) + pi = dict() + pi["src"] = src + pi["dst"] = wire + pi["fast_delay"] = pipdelay(src, wire, fast_timings) + pi["slow_delay"] = pipdelay(src, wire, slow_timings) + pi["x"] = pip_xy[(src, wire)][0] + pi["y"] = pip_xy[(src, wire)][1] + pi["switch_mask"] = pip_xy[(src, wire)][2] + pi["switch_index"] = pip_xy[(src, wire)][3] + pi["flags"] = pip_xy[(src, wire)][4] + pipinfo.append(pi) + pips.append(pipcache[(src, wire)]) + num_uphill = len(pips) + list_uphill = "wire%d_uppips" % wire + bba.l(list_uphill, "int32_t") + for p in pips: + bba.u32(p, None) + else: + num_uphill = 0 + list_uphill = None + + if wire in wire_downhill: + pips = list() + for dst in wire_downhill[wire]: + if (wire, dst) not in pipcache: + pipcache[(wire, dst)] = len(pipinfo) + pi = dict() + pi["src"] = wire + pi["dst"] = dst + pi["fast_delay"] = pipdelay(wire, dst, fast_timings) + pi["slow_delay"] = pipdelay(wire, dst, slow_timings) + pi["x"] = pip_xy[(wire, dst)][0] + pi["y"] = pip_xy[(wire, dst)][1] + pi["switch_mask"] = pip_xy[(wire, dst)][2] + pi["switch_index"] = pip_xy[(wire, dst)][3] + pi["flags"] = pip_xy[(wire, dst)][4] + pipinfo.append(pi) + pips.append(pipcache[(wire, dst)]) + num_downhill = len(pips) + list_downhill = "wire%d_downpips" % wire + bba.l(list_downhill, "int32_t") + for p in pips: + bba.u32(p, None) + else: + num_downhill = 0 + list_downhill = None + + if wire in wire_belports: + num_bel_pins = len(wire_belports[wire]) + bba.l("wire%d_bels" % wire, "BelPortPOD") + for belport in sorted(wire_belports[wire]): + bba.u32(belport[0], "bel_index") + bba.u32(constids[belport[1]], "port") + else: + num_bel_pins = 0 + + info = dict() + info["name"] = "X%d/Y%d/%s" % wire_names_r[wire] + + info["num_uphill"] = num_uphill + info["list_uphill"] = list_uphill + + info["num_downhill"] = num_downhill + info["list_downhill"] = list_downhill + + info["num_bel_pins"] = num_bel_pins + info["list_bel_pins"] = ("wire%d_bels" % wire) if num_bel_pins > 0 else None + + if wire in wire_xy: + avg_x, avg_y = 0, 0 + + for x, y in wire_xy[wire]: + avg_x += x + avg_y += y + avg_x /= len(wire_xy[wire]) + avg_y /= len(wire_xy[wire]) + + info["x"] = int(round(avg_x)) + info["y"] = int(round(avg_y)) + else: + info["x"] = wire_names_r[wire][0] + info["y"] = wire_names_r[wire][1] + + wireinfo.append(info) + +packageinfo = [] + +for package in packages: + name, pins = package + safename = re.sub("[^A-Za-z0-9]", "_", name) + pins_info = [] + for pin in pins: + pinname, x, y, z = pin + pin_bel = "X%d/Y%d/io%d" % (x, y, z) + bel_idx = bel_name.index(pin_bel) + pins_info.append((pinname, bel_idx)) + bba.l("package_%s_pins" % safename, "PackagePinPOD") + for pi in pins_info: + bba.s(pi[0], "name") + bba.u32(pi[1], "bel_index") + packageinfo.append((name, len(pins_info), "package_%s_pins" % safename)) + +tilegrid = [] +for y in range(dev_height): + for x in range(dev_width): + if (x, y) in tiles: + tilegrid.append(tiles[x, y].upper()) + else: + tilegrid.append("NONE") + +tileinfo = [] +for t in range(num_tile_types): + centries_info = [] + for cb in tile_bits[t]: + name, bits = cb + safename = re.sub("[^A-Za-z0-9]", "_", name) + bba.l("tile%d_%s_bits" % (t, safename), "ConfigBitPOD") + for row, col in bits: + bba.u8(row, "row") + bba.u8(col, "col") + if len(bits) == 0: + bba.u32(0, "padding") + elif len(bits) % 2 == 1: + bba.u16(0, "padding") + centries_info.append((name, len(bits), t, safename)) + bba.l("tile%d_config" % t, "ConfigEntryPOD") + for name, num_bits, t, safename in centries_info: + bba.s(name, "name") + bba.u32(num_bits, "num_bits") + bba.r("tile%d_%s_bits" % (t, safename), "num_bits") + if len(centries_info) == 0: + bba.u32(0, "padding") + ti = dict() + ti["cols"] = tile_sizes[t][0] + ti["rows"] = tile_sizes[t][1] + ti["num_entries"] = len(centries_info) + ti["entries"] = "tile%d_config" % t + tileinfo.append(ti) + +bba.l("wire_data_%s" % dev_name, "WireInfoPOD") +for wire, info in enumerate(wireinfo): + bba.s(info["name"], "name") + bba.u32(info["num_uphill"], "num_uphill") + bba.u32(info["num_downhill"], "num_downhill") + bba.r(info["list_uphill"], "pips_uphill") + bba.r(info["list_downhill"], "pips_downhill") + bba.u32(info["num_bel_pins"], "num_bel_pins") + bba.r(info["list_bel_pins"], "bel_pins") + bba.u32(len(wire_segments[wire]), "num_segments") + if len(wire_segments[wire]): + bba.r("wire_segments_%d" % wire, "segments") + else: + bba.u32(0, "segments") + + bba.u32(wiredelay(wire, fast_timings), "fast_delay") + bba.u32(wiredelay(wire, slow_timings), "slow_delay") + + bba.u8(info["x"], "x") + bba.u8(info["y"], "y") + bba.u8(0, "z") # FIXME + bba.u8(wiretypes[wire_type(info["name"])], "type") + +for wire in range(num_wires): + if len(wire_segments[wire]): + bba.l("wire_segments_%d" % wire, "WireSegmentPOD") + for xy, seg in sorted(wire_segments[wire].items()): + bba.u8(xy[0], "x") + bba.u8(xy[1], "y") + bba.u16(gfx_wire_ids["TILE_WIRE_" + seg.upper().replace("/", "_")], "index") + +bba.l("pip_data_%s" % dev_name, "PipInfoPOD") +for info in pipinfo: + src_seg = -1 + src_segname = wire_names_r[info["src"]] + if (info["x"], info["y"]) in wire_segments[info["src"]]: + src_segname = wire_segments[info["src"]][(info["x"], info["y"])] + src_seg = gfx_wire_ids["TILE_WIRE_" + src_segname.upper().replace("/", "_")] + src_segname = src_segname.replace("/", ".") + + dst_seg = -1 + dst_segname = wire_names_r[info["dst"]] + if (info["x"], info["y"]) in wire_segments[info["dst"]]: + dst_segname = wire_segments[info["dst"]][(info["x"], info["y"])] + dst_seg = gfx_wire_ids["TILE_WIRE_" + dst_segname.upper().replace("/", "_")] + dst_segname = dst_segname.replace("/", ".") + + # bba.s("X%d/Y%d/%s->%s" % (info["x"], info["y"], src_segname, dst_segname), "name") + bba.u32(info["src"], "src") + bba.u32(info["dst"], "dst") + bba.u32(info["fast_delay"], "fast_delay") + bba.u32(info["slow_delay"], "slow_delay") + bba.u8(info["x"], "x") + bba.u8(info["y"], "y") + bba.u16(src_seg, "src_seg") + bba.u16(dst_seg, "dst_seg") + bba.u16(info["switch_mask"], "switch_mask") + bba.u32(info["switch_index"], "switch_index") + bba.u32(info["flags"], "flags") + +switchinfo = [] +for switch in switches: + x, y, bits, bel = switch + bitlist = [] + for b in bits: + m = cbit_re.match(b) + assert m + bitlist.append((int(m.group(1)), int(m.group(2)))) + si = dict() + si["x"] = x + si["y"] = y + si["bits"] = bitlist + si["bel"] = bel + switchinfo.append(si) + +bba.l("switch_data_%s" % dev_name, "SwitchInfoPOD") +for info in switchinfo: + bba.u32(len(info["bits"]), "num_bits") + bba.u32(info["bel"], "bel") + bba.u8(info["x"], "x") + bba.u8(info["y"], "y") + for i in range(5): + if i < len(info["bits"]): + bba.u8(info["bits"][i][0], "row<%d>" % i) + bba.u8(info["bits"][i][1], "col<%d>" % i) + else: + bba.u8(0, "row<%d> (unused)" % i) + bba.u8(0, "col<%d> (unused)" % i) + +bba.l("tile_data_%s" % dev_name, "TileInfoPOD") +for info in tileinfo: + bba.u8(info["cols"], "cols") + bba.u8(info["rows"], "rows") + bba.u16(info["num_entries"], "num_entries") + bba.r(info["entries"], "entries") + +bba.l("ieren_data_%s" % dev_name, "IerenInfoPOD") +for ieren in ierens: + bba.u8(ieren[0], "iox") + bba.u8(ieren[1], "ioy") + bba.u8(ieren[2], "ioz") + bba.u8(ieren[3], "ierx") + bba.u8(ieren[4], "iery") + bba.u8(ieren[5], "ierz") + +if len(ierens) % 2 == 1: + bba.u16(0, "padding") + +bba.l("bits_info_%s" % dev_name, "BitstreamInfoPOD") +bba.u32(len(switchinfo), "num_switches") +bba.u32(len(ierens), "num_ierens") +bba.r("tile_data_%s" % dev_name, "tiles_nonrouting") +bba.r("switch_data_%s" % dev_name, "switches") +bba.r("ieren_data_%s" % dev_name, "ierens") + +bba.l("tile_grid_%s" % dev_name, "TileType") +for t in tilegrid: + bba.u32(tiletypes[t], "tiletype") + +for bel_idx, entries in sorted(extra_cell_config.items()): + if len(entries) > 0: + bba.l("bel%d_config_entries" % bel_idx, "BelConfigEntryPOD") + for entry in entries: + bba.s(entry[0], "entry_name") + bba.s(entry[1][2], "cbit_name") + bba.u8(entry[1][0], "x") + bba.u8(entry[1][1], "y") + bba.u16(0, "padding") + +if len(extra_cell_config) > 0: + bba.l("bel_config_%s" % dev_name, "BelConfigPOD") + for bel_idx, entries in sorted(extra_cell_config.items()): + bba.u32(bel_idx, "bel_index") + bba.u32(len(entries), "num_entries") + bba.r("bel%d_config_entries" % bel_idx if len(entries) > 0 else None, "entries") + +bba.l("package_info_%s" % dev_name, "PackageInfoPOD") +for info in packageinfo: + bba.s(info[0], "name") + bba.u32(info[1], "num_pins") + bba.r(info[2], "pins") + +for cell, timings in sorted(cell_timings.items()): + beltype = constids[cell] + bba.l("cell_paths_%d" % beltype, "CellPathDelayPOD") + for entry in timings: + fromport, toport, fast, slow = entry + bba.u32(constids[fromport], "from_port") + bba.u32(constids[toport], "to_port") + bba.u32(fast, "fast_delay") + bba.u32(slow, "slow_delay") + +bba.l("cell_timings_%s" % dev_name, "CellTimingPOD") +for cell, timings in sorted(cell_timings.items()): + beltype = constids[cell] + bba.u32(beltype, "type") + bba.u32(len(timings), "num_paths") + bba.r("cell_paths_%d" % beltype, "path_delays") + +bba.l("chip_info_%s" % dev_name) +bba.u32(dev_width, "dev_width") +bba.u32(dev_height, "dev_height") +bba.u32(len(bel_name), "num_bels") +bba.u32(num_wires, "num_wires") +bba.u32(len(pipinfo), "num_pips") +bba.u32(len(switchinfo), "num_switches") +bba.u32(len(extra_cell_config), "num_belcfgs") +bba.u32(len(packageinfo), "num_packages") +bba.u32(len(cell_timings), "num_timing_cells") +bba.r("bel_data_%s" % dev_name, "bel_data") +bba.r("wire_data_%s" % dev_name, "wire_data") +bba.r("pip_data_%s" % dev_name, "pip_data") +bba.r("tile_grid_%s" % dev_name, "tile_grid") +bba.r("bits_info_%s" % dev_name, "bits_info") +bba.r("bel_config_%s" % dev_name if len(extra_cell_config) > 0 else None, "bel_config") +bba.r("package_info_%s" % dev_name, "packages_data") +bba.r("cell_timings_%s" % dev_name, "cell_timing") + +bba.pop() diff --git a/xc7/constids.inc b/xc7/constids.inc new file mode 100644 index 00000000..adcea7ad --- /dev/null +++ b/xc7/constids.inc @@ -0,0 +1,437 @@ +// pin and port names +X(I0) +X(I1) +X(I2) +X(I3) +X(O) +X(LO) +X(CIN) +X(COUT) +X(CEN) +X(CLK) +X(SR) + +X(MASK_0) +X(MASK_1) +X(MASK_2) +X(MASK_3) +X(MASK_4) +X(MASK_5) +X(MASK_6) +X(MASK_7) +X(MASK_8) +X(MASK_9) +X(MASK_10) +X(MASK_11) +X(MASK_12) +X(MASK_13) +X(MASK_14) +X(MASK_15) + +X(RDATA_0) +X(RDATA_1) +X(RDATA_2) +X(RDATA_3) +X(RDATA_4) +X(RDATA_5) +X(RDATA_6) +X(RDATA_7) +X(RDATA_8) +X(RDATA_9) +X(RDATA_10) +X(RDATA_11) +X(RDATA_12) +X(RDATA_13) +X(RDATA_14) +X(RDATA_15) + +X(WDATA_0) +X(WDATA_1) +X(WDATA_2) +X(WDATA_3) +X(WDATA_4) +X(WDATA_5) +X(WDATA_6) +X(WDATA_7) +X(WDATA_8) +X(WDATA_9) +X(WDATA_10) +X(WDATA_11) +X(WDATA_12) +X(WDATA_13) +X(WDATA_14) +X(WDATA_15) + +X(WADDR_0) +X(WADDR_1) +X(WADDR_2) +X(WADDR_3) +X(WADDR_4) +X(WADDR_5) +X(WADDR_6) +X(WADDR_7) +X(WADDR_8) +X(WADDR_9) +X(WADDR_10) + +X(RADDR_0) +X(RADDR_1) +X(RADDR_2) +X(RADDR_3) +X(RADDR_4) +X(RADDR_5) +X(RADDR_6) +X(RADDR_7) +X(RADDR_8) +X(RADDR_9) +X(RADDR_10) + +X(WCLK) +X(WCLKE) +X(WE) + +X(RCLK) +X(RCLKE) +X(RE) + +X(PACKAGE_PIN) +X(LATCH_INPUT_VALUE) +X(CLOCK_ENABLE) +X(INPUT_CLK) +X(OUTPUT_CLK) +X(OUTPUT_ENABLE) +X(D_OUT_0) +X(D_OUT_1) +X(D_IN_0) +X(D_IN_1) + +X(USER_SIGNAL_TO_GLOBAL_BUFFER) +X(GLOBAL_BUFFER_OUTPUT) + +X(REFERENCECLK) +X(EXTFEEDBACK) +X(DYNAMICDELAY_0) +X(DYNAMICDELAY_1) +X(DYNAMICDELAY_2) +X(DYNAMICDELAY_3) +X(DYNAMICDELAY_4) +X(DYNAMICDELAY_5) +X(DYNAMICDELAY_6) +X(DYNAMICDELAY_7) +X(LOCK) +X(PLLOUT_A) +X(PLLOUT_B) +X(BYPASS) +X(RESETB) +X(LATCHINPUTVALUE) +X(SDO) +X(SDI) +X(SCLK) + +X(BOOT) +X(S0) +X(S1) + +X(ADDSUBBOT) +X(ADDSUBTOP) +X(AHOLD) +X(A_0) +X(A_1) +X(A_10) +X(A_11) +X(A_12) +X(A_13) +X(A_14) +X(A_15) +X(A_2) +X(A_3) +X(A_4) +X(A_5) +X(A_6) +X(A_7) +X(A_8) +X(A_9) +X(BHOLD) +X(B_0) +X(B_1) +X(B_10) +X(B_11) +X(B_12) +X(B_13) +X(B_14) +X(B_15) +X(B_2) +X(B_3) +X(B_4) +X(B_5) +X(B_6) +X(B_7) +X(B_8) +X(B_9) +X(CE) +X(CHOLD) +X(CI) +X(CO) +X(C_0) +X(C_1) +X(C_10) +X(C_11) +X(C_12) +X(C_13) +X(C_14) +X(C_15) +X(C_2) +X(C_3) +X(C_4) +X(C_5) +X(C_6) +X(C_7) +X(C_8) +X(C_9) +X(DHOLD) +X(D_0) +X(D_1) +X(D_10) +X(D_11) +X(D_12) +X(D_13) +X(D_14) +X(D_15) +X(D_2) +X(D_3) +X(D_4) +X(D_5) +X(D_6) +X(D_7) +X(D_8) +X(D_9) +X(IRSTBOT) +X(IRSTTOP) +X(OHOLDBOT) +X(OHOLDTOP) +X(OLOADBOT) +X(OLOADTOP) +X(ORSTBOT) +X(ORSTTOP) +X(O_0) +X(O_1) +X(O_10) +X(O_11) +X(O_12) +X(O_13) +X(O_14) +X(O_15) +X(O_16) +X(O_17) +X(O_18) +X(O_19) +X(O_2) +X(O_20) +X(O_21) +X(O_22) +X(O_23) +X(O_24) +X(O_25) +X(O_26) +X(O_27) +X(O_28) +X(O_29) +X(O_3) +X(O_30) +X(O_31) +X(O_4) +X(O_5) +X(O_6) +X(O_7) +X(O_8) +X(O_9) + +X(CLKHF) +X(CLKHFEN) +X(CLKHFPU) +X(CLKHF_FABRIC) +X(TRIM0) +X(TRIM1) +X(TRIM2) +X(TRIM3) +X(TRIM4) +X(TRIM5) +X(TRIM6) +X(TRIM7) +X(TRIM8) +X(TRIM9) + +X(CLKLF) +X(CLKLFEN) +X(CLKLFPU) +X(CLKLF_FABRIC) + +X(I2CIRQ) +X(I2CWKUP) +X(SBACKO) +X(SBADRI0) +X(SBADRI1) +X(SBADRI2) +X(SBADRI3) +X(SBADRI4) +X(SBADRI5) +X(SBADRI6) +X(SBADRI7) +X(SBCLKI) +X(SBDATI0) +X(SBDATI1) +X(SBDATI2) +X(SBDATI3) +X(SBDATI4) +X(SBDATI5) +X(SBDATI6) +X(SBDATI7) +X(SBDATO0) +X(SBDATO1) +X(SBDATO2) +X(SBDATO3) +X(SBDATO4) +X(SBDATO5) +X(SBDATO6) +X(SBDATO7) +X(SBRWI) +X(SBSTBI) +X(SCLI) +X(SCLO) +X(SCLOE) +X(SDAI) +X(SDAO) +X(SDAOE) + +X(MCSNO0) +X(MCSNO1) +X(MCSNO2) +X(MCSNO3) +X(MCSNOE0) +X(MCSNOE1) +X(MCSNOE2) +X(MCSNOE3) +X(MI) +X(MO) +X(MOE) +X(SCKI) +X(SCKO) +X(SCKOE) +X(SCSNI) +X(SI) +X(SO) +X(SOE) +X(SPIIRQ) +X(SPIWKUP) + +X(PU_ENB) +X(WEAK_PU_ENB) + +X(LEDDADDR0) +X(LEDDADDR1) +X(LEDDADDR2) +X(LEDDADDR3) +X(LEDDCLK) +X(LEDDCS) +X(LEDDDAT0) +X(LEDDDAT1) +X(LEDDDAT2) +X(LEDDDAT3) +X(LEDDDAT4) +X(LEDDDAT5) +X(LEDDDAT6) +X(LEDDDAT7) +X(LEDDDEN) +X(LEDDEXE) +X(LEDDON) +X(PWMOUT0) +X(PWMOUT1) +X(PWMOUT2) + +X(CURREN) +X(RGB0PWM) +X(RGB1PWM) +X(RGB2PWM) +X(RGBLEDEN) +X(RGB0) +X(RGB1) +X(RGB2) + +X(ADDRESS_0) +X(ADDRESS_1) +X(ADDRESS_10) +X(ADDRESS_11) +X(ADDRESS_12) +X(ADDRESS_13) +X(ADDRESS_2) +X(ADDRESS_3) +X(ADDRESS_4) +X(ADDRESS_5) +X(ADDRESS_6) +X(ADDRESS_7) +X(ADDRESS_8) +X(ADDRESS_9) +X(CHIPSELECT) +X(CLOCK) +X(DATAIN_0) +X(DATAIN_1) +X(DATAIN_10) +X(DATAIN_11) +X(DATAIN_12) +X(DATAIN_13) +X(DATAIN_14) +X(DATAIN_15) +X(DATAIN_2) +X(DATAIN_3) +X(DATAIN_4) +X(DATAIN_5) +X(DATAIN_6) +X(DATAIN_7) +X(DATAIN_8) +X(DATAIN_9) +X(DATAOUT_0) +X(DATAOUT_1) +X(DATAOUT_10) +X(DATAOUT_11) +X(DATAOUT_12) +X(DATAOUT_13) +X(DATAOUT_14) +X(DATAOUT_15) +X(DATAOUT_2) +X(DATAOUT_3) +X(DATAOUT_4) +X(DATAOUT_5) +X(DATAOUT_6) +X(DATAOUT_7) +X(DATAOUT_8) +X(DATAOUT_9) +X(MASKWREN_0) +X(MASKWREN_1) +X(MASKWREN_2) +X(MASKWREN_3) +X(POWEROFF) +X(SLEEP) +X(STANDBY) +X(WREN) + +// cell and bel types +X(ICESTORM_LC) +X(ICESTORM_RAM) +X(SB_IO) +X(SB_GB) +X(ICESTORM_PLL) +X(SB_WARMBOOT) +X(ICESTORM_DSP) +X(ICESTORM_HFOSC) +X(ICESTORM_LFOSC) +X(SB_I2C) +X(SB_SPI) +X(IO_I3C) +X(SB_LEDDA_IP) +X(SB_RGBA_DRV) +X(ICESTORM_SPRAM) + +// cell parameters +X(DFF_ENABLE) +X(CARRY_ENABLE) +X(NEG_CLK) diff --git a/xc7/delay.cc b/xc7/delay.cc new file mode 100644 index 00000000..d76aaefb --- /dev/null +++ b/xc7/delay.cc @@ -0,0 +1,238 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Serge Bazanski + * + * 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 "nextpnr.h" +#include "router1.h" + +NEXTPNR_NAMESPACE_BEGIN + +#define NUM_FUZZ_ROUTES 100000 + +void ice40DelayFuzzerMain(Context *ctx) +{ + std::vector srcWires, dstWires; + + for (int i = 0; i < ctx->chip_info->num_wires; i++) { + WireId wire; + wire.index = i; + + switch (ctx->chip_info->wire_data[i].type) { + case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: + srcWires.push_back(wire); + break; + + case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: + dstWires.push_back(wire); + break; + + default: + break; + } + } + + ctx->shuffle(srcWires); + ctx->shuffle(dstWires); + + int index = 0; + int cnt = 0; + + while (cnt < NUM_FUZZ_ROUTES) { + if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { + index = 0; + ctx->shuffle(srcWires); + ctx->shuffle(dstWires); + } + + WireId src = srcWires[index]; + WireId dst = dstWires[index++]; + std::unordered_map route; + +#if NUM_FUZZ_ROUTES <= 1000 + if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) + continue; +#else + if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) + continue; +#endif + + WireId cursor = dst; + delay_t delay = 0; + + while (1) { + delay += ctx->getWireDelay(cursor).maxDelay(); + + printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", + int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), + ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), + int(ctx->estimateDelay(cursor, dst))); + + if (cursor == src) + break; + + PipId pip = route.at(cursor); + delay += ctx->getPipDelay(pip).maxDelay(); + cursor = ctx->getPipSrcWire(pip); + } + + cnt++; + + if (cnt % 100 == 0) + fprintf(stderr, "Fuzzed %d arcs.\n", cnt); + } +} + +namespace { + +struct model_params_t +{ + int neighbourhood; + + int model0_offset; + int model0_norm1; + + int model1_offset; + int model1_norm1; + int model1_norm2; + int model1_norm3; + + int model2_offset; + int model2_linear; + int model2_sqrt; + + int delta_local; + int delta_lutffin; + int delta_sp4; + int delta_sp12; + + static const model_params_t &get(const ArchArgs& args) + { + static const model_params_t model_hx8k = {588, 129253, 8658, 118333, 23915, -73105, 57696, + -86797, 89, 3706, -316, -575, -158, -296}; + + static const model_params_t model_lp8k = {867, 206236, 11043, 191910, 31074, -95972, 75739, + -309793, 30, 11056, -474, -856, -363, -536}; + + static const model_params_t model_up5k = {1761, 305798, 16705, 296830, 24430, -40369, 33038, + -162662, 94, 4705, -1099, -1761, -418, -838}; + + if (args.type == ArchArgs::HX1K || args.type == ArchArgs::HX8K) + return model_hx8k; + + if (args.type == ArchArgs::LP384 || args.type == ArchArgs::LP1K || args.type == ArchArgs::LP8K) + return model_lp8k; + + if (args.type == ArchArgs::UP5K) + return model_up5k; + + NPNR_ASSERT(0); + } +}; + +} // namespace + +delay_t Arch::estimateDelay(WireId src, WireId dst) const +{ + NPNR_ASSERT(src != WireId()); + int x1 = chip_info->wire_data[src.index].x; + int y1 = chip_info->wire_data[src.index].y; + int z1 = chip_info->wire_data[src.index].z; + int type = chip_info->wire_data[src.index].type; + + NPNR_ASSERT(dst != WireId()); + int x2 = chip_info->wire_data[dst.index].x; + int y2 = chip_info->wire_data[dst.index].y; + int z2 = chip_info->wire_data[dst.index].z; + + int dx = abs(x2 - x1); + int dy = abs(y2 - y1); + + const model_params_t &p = model_params_t::get(args); + delay_t v = p.neighbourhood; + + if (dx > 1 || dy > 1) + v = (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128; + + if (dx == 0 && dy == 0) { + if (type == WireInfoPOD::WIRE_TYPE_LOCAL) + v += p.delta_local; + + if (type == WireInfoPOD::WIRE_TYPE_LUTFF_IN || type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT) + v += (z1 == z2) ? p.delta_lutffin : 0; + } + + if (type == WireInfoPOD::WIRE_TYPE_SP4_V || type == WireInfoPOD::WIRE_TYPE_SP4_H) + v += p.delta_sp4; + + if (type == WireInfoPOD::WIRE_TYPE_SP12_V || type == WireInfoPOD::WIRE_TYPE_SP12_H) + v += p.delta_sp12; + + return v; +} + +delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const +{ + const auto &driver = net_info->driver; + auto driver_loc = getBelLocation(driver.cell->bel); + auto sink_loc = getBelLocation(sink.cell->bel); + + if (driver.port == id_COUT) { + if (driver_loc.y == sink_loc.y) + return 0; + return 250; + } + + int dx = abs(sink_loc.x - driver_loc.x); + int dy = abs(sink_loc.y - driver_loc.y); + + const model_params_t &p = model_params_t::get(args); + + if (dx <= 1 && dy <= 1) + return p.neighbourhood; + +#if 1 + // Model #0 + return (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128; +#else + float norm1 = dx + dy; + + float dx2 = dx * dx; + float dy2 = dy * dy; + float norm2 = sqrtf(dx2 + dy2); + + float dx3 = dx2 * dx; + float dy3 = dy2 * dy; + float norm3 = powf(dx3 + dy3, 1.0 / 3.0); + + // Model #1 + float v = p.model1_offset; + v += p.model1_norm1 * norm1; + v += p.model1_norm2 * norm2; + v += p.model1_norm3 * norm3; + v /= 128; + + // Model #2 + v = p.model2_offset + p.model2_linear * v + p.model2_sqrt * sqrtf(v); + v /= 128; + + return v; +#endif +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/family.cmake b/xc7/family.cmake new file mode 100644 index 00000000..f558a14d --- /dev/null +++ b/xc7/family.cmake @@ -0,0 +1,84 @@ +if(ICE40_HX1K_ONLY) + set(devices 1k) + foreach (target ${family_targets}) + target_compile_definitions(${target} PRIVATE ICE40_HX1K_ONLY=1) + endforeach (target) +else() + set(devices 384 1k 5k 8k) +endif() + +set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdb.py) + +set(ICEBOX_ROOT "/usr/local/share/icebox" CACHE STRING "icebox location root") +file(MAKE_DIRECTORY ice40/chipdbs/) +add_library(ice40_chipdb OBJECT ice40/chipdbs/) +target_compile_definitions(ice40_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) +target_include_directories(ice40_chipdb PRIVATE ${family}/) + +if (MSVC) + target_sources(ice40_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ice40/resource/embed.cc) + set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ice40/resources/chipdb.rc PROPERTIES LANGUAGE RC) + foreach (dev ${devices}) + if (dev EQUAL "5k") + set(OPT_FAST "") + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_up5k.txt) + elseif(dev EQUAL "384") + set(OPT_FAST "") + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp384.txt) + else() + set(OPT_FAST --fast ${ICEBOX_ROOT}/timings_hx${dev}.txt) + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp${dev}.txt) + endif() + set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) + set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bin) + set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/constids.inc) + set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} + DEPENDS ${DEV_TXT_DB} ${DB_PY} + ) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) + target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) + set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $ ${CMAKE_CURRENT_SOURCE_DIR}/ice40/resource/chipdb.rc) + endforeach (target) + endforeach (dev) +else() + target_compile_options(ice40_chipdb PRIVATE -g0 -O0 -w) + foreach (dev ${devices}) + if (dev EQUAL "5k") + set(OPT_FAST "") + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_up5k.txt) + elseif(dev EQUAL "384") + set(OPT_FAST "") + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp384.txt) + else() + set(OPT_FAST --fast ${ICEBOX_ROOT}/timings_hx${dev}.txt) + set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp${dev}.txt) + endif() + set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) + set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) + set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.cc) + set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/constids.inc) + set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) + add_custom_command(OUTPUT ${DEV_CC_BBA_DB} + COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new + COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} + DEPENDS ${DEV_TXT_DB} ${DB_PY} + ) + add_custom_command(OUTPUT ${DEV_CC_DB} + COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new + COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} + DEPENDS bbasm ${DEV_CC_BBA_DB} + ) + target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) + foreach (target ${family_targets}) + target_sources(${target} PRIVATE $) + endforeach (target) + endforeach (dev) +endif() diff --git a/xc7/gfx.cc b/xc7/gfx.cc new file mode 100644 index 00000000..1ab2fb3c --- /dev/null +++ b/xc7/gfx.cc @@ -0,0 +1,766 @@ +/* + * 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 "gfx.h" + +NEXTPNR_NAMESPACE_BEGIN + +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style) +{ + GraphicElement el; + el.type = GraphicElement::TYPE_LINE; + el.style = style; + + // Horizontal Span-4 Wires + + if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { + int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1))); + float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); + + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.02; + el.x2 = x + 0.9; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 35); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y2; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) { + int idx = id - TILE_WIRE_SP4_H_R_0; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (60 - idx)); + float y2 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1))); + float y3 = y + 1.0 - (0.03 + 0.0025 * (60 - (idx ^ 1) - 12)); + + if (idx >= 12) { + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + } + + el.x1 = x + 0.02; + el.x2 = x + 0.9; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.9; + el.x2 = x + 1.0; + el.y1 = y2; + el.y2 = y3; + g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y2; + g.push_back(el); + } + + // Vertical Span-4 Wires + + if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) { + int idx = (id - TILE_WIRE_SP4_V_T_36) + 48; + + float x1 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x2 = x + 0.03 + 0.0025 * (60 - idx); + + el.y1 = y + 1.00; + el.y2 = y + 0.99; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.98; + el.y2 = y + 0.10; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - idx)); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { + int idx = id - TILE_WIRE_SP4_V_B_0; + + float x1 = x + 0.03 + 0.0025 * (60 - idx); + float x2 = x + 0.03 + 0.0025 * (60 - (idx ^ 1)); + float x3 = x + 0.03 + 0.0025 * (60 - (idx ^ 1) - 12); + + if (idx >= 12) { + el.y1 = y + 1.00; + el.y2 = y + 0.99; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + } + + el.y1 = y + 0.98; + el.y2 = y + 0.10; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.10; + el.y2 = y; + el.x1 = x2; + el.x2 = x3; + g.push_back(el); + + el.y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1))); + el.y2 = el.y1; + el.x1 = x; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1))); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + // Horizontal Span-12 Wires + + if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) { + int idx = (id - TILE_WIRE_SP12_H_L_22) + 24; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); + float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); + + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.02; + el.x2 = x + 0.98333; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * (idx + 5); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y2; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { + int idx = id - TILE_WIRE_SP12_H_R_0; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (90 - idx)); + float y2 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1))); + float y3 = y + 1.0 - (0.03 + 0.0025 * (90 - (idx ^ 1) - 2)); + + if (idx >= 2) { + el.x1 = x; + el.x2 = x + 0.01; + el.y1 = y1; + el.y2 = y1; + g.push_back(el); + + el.x1 = x + 0.01; + el.x2 = x + 0.02; + el.y1 = y1; + el.y2 = y2; + g.push_back(el); + } + + el.x1 = x + 0.02; + el.x2 = x + 0.98333; + el.y1 = y2; + el.y2 = y2; + g.push_back(el); + + el.x1 = x + 0.98333; + el.x2 = x + 1.0; + el.y1 = y2; + el.y2 = y3; + g.push_back(el); + + el.x1 = x + main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5); + el.x2 = el.x1; + el.y1 = y2; + el.y2 = y + main_swbox_y2; + g.push_back(el); + } + + // Vertical Right Span-4 + + if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { + int idx = id - TILE_WIRE_SP4_R_V_B_0; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1))); + + el.y1 = y1; + el.y2 = y1; + el.x1 = x + main_swbox_x2; + el.x2 = x + 1.0; + g.push_back(el); + } + + // Vertical Span-12 Wires + + if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { + int idx = (id - TILE_WIRE_SP12_V_T_22) + 24; + + float x1 = x + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float x2 = x + 0.03 + 0.0025 * (90 - idx); + + el.y1 = y + 1.00; + el.y2 = y + 0.99; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.98; + el.y2 = y + 0.01667; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - idx)); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) { + int idx = id - TILE_WIRE_SP12_V_B_0; + + float x1 = x + 0.03 + 0.0025 * (90 - idx); + float x2 = x + 0.03 + 0.0025 * (90 - (idx ^ 1)); + float x3 = x + 0.03 + 0.0025 * (90 - (idx ^ 1) - 2); + + if (idx >= 2) { + el.y1 = y + 1.00; + el.y2 = y + 0.99; + el.x1 = x1; + el.x2 = x1; + g.push_back(el); + + el.y1 = y + 0.99; + el.y2 = y + 0.98; + el.x1 = x1; + el.x2 = x2; + g.push_back(el); + } + + el.y1 = y + 0.98; + el.y2 = y + 0.01667; + el.x1 = x2; + el.x2 = x2; + g.push_back(el); + + el.y1 = y + 0.01667; + el.y2 = y; + el.x1 = x2; + el.x2 = x3; + g.push_back(el); + + el.y1 = y + 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1))); + el.y2 = el.y1; + el.x1 = x2; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + // Global2Local + + if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { + int idx = id - TILE_WIRE_GLB2LOCAL_0; + el.x1 = x + main_swbox_x1 + 0.005 * (idx + 5); + el.x2 = el.x1; + el.y1 = y + main_swbox_y1; + el.y2 = el.y1 - 0.02; + g.push_back(el); + } + + // GlobalNets + + if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) { + int idx = id - TILE_WIRE_GLB_NETWK_0; + el.x1 = x + main_swbox_x1 - 0.05; + el.x2 = x + main_swbox_x1; + el.y1 = y + main_swbox_y1 + 0.005 * (13 - idx); + el.y2 = el.y1; + g.push_back(el); + } + + // Neighbours + + if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) { + int idx = id - TILE_WIRE_NEIGH_OP_BNL_0; + el.y1 = y + main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8)); + el.y2 = el.y1; + el.x1 = x + main_swbox_x1 - 0.05; + el.x2 = x + main_swbox_x1; + g.push_back(el); + } + + // Local Tracks + + if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) { + int idx = id - TILE_WIRE_LOCAL_G0_0; + el.x1 = x + main_swbox_x2; + el.x2 = x + local_swbox_x1; + float yoff = y + (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075; + el.y1 = yoff + 0.005 * idx + 0.05 * (idx / 8); + el.y2 = el.y1; + g.push_back(el); + } + + // LC Inputs + + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { + int idx = id - TILE_WIRE_LUTFF_0_IN_0; + int z = idx / 4; + int input = idx % 4; + el.x1 = x + local_swbox_x2; + el.x2 = x + lut_swbox_x1; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; + el.y2 = el.y1; + g.push_back(el); + } + + if (id >= TILE_WIRE_LUTFF_0_IN_0_LUT && id <= TILE_WIRE_LUTFF_7_IN_3_LUT) { + int idx = id - TILE_WIRE_LUTFF_0_IN_0_LUT; + int z = idx / 4; + int input = idx % 4; + el.x1 = x + lut_swbox_x2; + el.x2 = x + logic_cell_x1; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; + el.y2 = el.y1; + g.push_back(el); + } + + // LC Outputs + + if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) { + int idx = id - TILE_WIRE_LUTFF_0_OUT; + + float y1 = y + 1.0 - (0.03 + 0.0025 * (152 + idx)); + + el.y1 = y1; + el.y2 = y1; + el.x1 = x + main_swbox_x2; + el.x2 = x + 0.97 + 0.0025 * (7 - idx); + g.push_back(el); + + el.y1 = y1; + el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + idx * logic_cell_pitch; + el.x1 = el.x2; + g.push_back(el); + + el.y1 = el.y2; + el.x1 = x + logic_cell_x2; + g.push_back(el); + } + + // LC Control + + if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) { + int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN; + + el.x1 = x + main_swbox_x2 - 0.005 * (idx + 5); + el.x2 = el.x1; + el.y1 = y + main_swbox_y1; + el.y2 = el.y1 - 0.005 * (idx + 2); + g.push_back(el); + + el.y1 = el.y2; + el.x2 = x + logic_cell_x2 - 0.005 * (2 - idx + 5); + g.push_back(el); + + el.y2 = y + logic_cell_y1; + el.x1 = el.x2; + g.push_back(el); + + for (int i = 0; i < 7; i++) { + el.y1 = y + logic_cell_y2 + i * logic_cell_pitch; + el.y2 = y + logic_cell_y1 + (i + 1) * logic_cell_pitch; + g.push_back(el); + } + } + + // LC Cascade + + if (id >= TILE_WIRE_LUTFF_0_LOUT && id <= TILE_WIRE_LUTFF_6_LOUT) { + int idx = id - TILE_WIRE_LUTFF_0_LOUT; + el.x1 = x + logic_cell_x1 + 0.005 * 5; + el.x2 = el.x1; + el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; + el.y2 = y + logic_cell_y1 + (idx + 1) * logic_cell_pitch; + g.push_back(el); + } + + // Carry Chain + + if (id >= TILE_WIRE_LUTFF_0_COUT && id <= TILE_WIRE_LUTFF_7_COUT) { + int idx = id - TILE_WIRE_LUTFF_0_COUT; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + logic_cell_y2 + idx * logic_cell_pitch; + el.y2 = y + (idx < 7 ? logic_cell_y1 + (idx + 1) * logic_cell_pitch : 1.0); + g.push_back(el); + } + + if (id == TILE_WIRE_CARRY_IN) { + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y; + el.y2 = y + 0.01; + g.push_back(el); + } + + if (id == TILE_WIRE_CARRY_IN_MUX) { + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + 0.02; + el.y2 = y + logic_cell_y1; + g.push_back(el); + } +} + +static bool getWireXY_main(GfxTileWireId id, float &x, float &y) +{ + // Horizontal Span-4 Wires + + if (id >= TILE_WIRE_SP4_H_L_36 && id <= TILE_WIRE_SP4_H_L_47) { + int idx = (id - TILE_WIRE_SP4_H_L_36) + 48; + x = main_swbox_x1 + 0.0025 * (idx + 35); + y = main_swbox_y2; + return true; + } + + if (id >= TILE_WIRE_SP4_H_R_0 && id <= TILE_WIRE_SP4_H_R_47) { + int idx = id - TILE_WIRE_SP4_H_R_0; + x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 35); + y = main_swbox_y2; + return true; + } + + // Vertical Span-4 Wires + + if (id >= TILE_WIRE_SP4_V_T_36 && id <= TILE_WIRE_SP4_V_T_47) { + int idx = (id - TILE_WIRE_SP4_V_T_36) + 48; + y = 1.0 - (0.03 + 0.0025 * (270 - idx)); + x = main_swbox_x1; + return true; + } + + if (id >= TILE_WIRE_SP4_V_B_0 && id <= TILE_WIRE_SP4_V_B_47) { + int idx = id - TILE_WIRE_SP4_V_B_0; + y = 1.0 - (0.03 + 0.0025 * (270 - (idx ^ 1))); + x = main_swbox_x1; + return true; + } + + // Horizontal Span-12 Wires + + if (id >= TILE_WIRE_SP12_H_L_22 && id <= TILE_WIRE_SP12_H_L_23) { + int idx = (id - TILE_WIRE_SP12_H_L_22) + 24; + x = main_swbox_x1 + 0.0025 * (idx + 5); + y = main_swbox_y2; + return true; + } + + if (id >= TILE_WIRE_SP12_H_R_0 && id <= TILE_WIRE_SP12_H_R_23) { + int idx = id - TILE_WIRE_SP12_H_R_0; + x = main_swbox_x1 + 0.0025 * ((idx ^ 1) + 5); + y = main_swbox_y2; + return true; + } + + // Vertical Right Span-4 + + if (id >= TILE_WIRE_SP4_R_V_B_0 && id <= TILE_WIRE_SP4_R_V_B_47) { + int idx = id - TILE_WIRE_SP4_R_V_B_0; + y = 1.0 - (0.03 + 0.0025 * (145 - (idx ^ 1))); + x = main_swbox_x2; + return true; + } + + // Vertical Span-12 Wires + + if (id >= TILE_WIRE_SP12_V_T_22 && id <= TILE_WIRE_SP12_V_T_23) { + int idx = (id - TILE_WIRE_SP12_V_T_22) + 24; + y = 1.0 - (0.03 + 0.0025 * (300 - idx)); + x = main_swbox_x1; + return true; + } + + if (id >= TILE_WIRE_SP12_V_B_0 && id <= TILE_WIRE_SP12_V_B_23) { + int idx = id - TILE_WIRE_SP12_V_B_0; + y = 1.0 - (0.03 + 0.0025 * (300 - (idx ^ 1))); + x = main_swbox_x1; + return true; + } + + // Global2Local + + if (id >= TILE_WIRE_GLB2LOCAL_0 && id <= TILE_WIRE_GLB2LOCAL_3) { + int idx = id - TILE_WIRE_GLB2LOCAL_0; + x = main_swbox_x1 + 0.005 * (idx + 5); + y = main_swbox_y1; + return true; + } + + // GlobalNets + + if (id >= TILE_WIRE_GLB_NETWK_0 && id <= TILE_WIRE_GLB_NETWK_7) { + int idx = id - TILE_WIRE_GLB_NETWK_0; + x = main_swbox_x1; + y = main_swbox_y1 + 0.005 * (13 - idx); + return true; + } + + // Neighbours + + if (id >= TILE_WIRE_NEIGH_OP_BNL_0 && id <= TILE_WIRE_NEIGH_OP_TOP_7) { + int idx = id - TILE_WIRE_NEIGH_OP_BNL_0; + y = main_swbox_y2 - (0.0025 * (idx + 10) + 0.01 * (idx / 8)); + x = main_swbox_x1; + return true; + } + + // Local Tracks + + if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) { + int idx = id - TILE_WIRE_LOCAL_G0_0; + float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075; + x = main_swbox_x2; + y = yoff + 0.005 * idx + 0.05 * (idx / 8); + return true; + } + + // LC Outputs + + if (id >= TILE_WIRE_LUTFF_0_OUT && id <= TILE_WIRE_LUTFF_7_OUT) { + int idx = id - TILE_WIRE_LUTFF_0_OUT; + y = 1.0 - (0.03 + 0.0025 * (152 + idx)); + x = main_swbox_x2; + return true; + } + + // LC Control + + if (id >= TILE_WIRE_LUTFF_GLOBAL_CEN && id <= TILE_WIRE_LUTFF_GLOBAL_S_R) { + int idx = id - TILE_WIRE_LUTFF_GLOBAL_CEN; + x = main_swbox_x2 - 0.005 * (idx + 5); + y = main_swbox_y1; + return true; + } + + return false; +} + +static bool getWireXY_local(GfxTileWireId id, float &x, float &y) +{ + if (id >= TILE_WIRE_LOCAL_G0_0 && id <= TILE_WIRE_LOCAL_G3_7) { + int idx = id - TILE_WIRE_LOCAL_G0_0; + float yoff = (local_swbox_y1 + local_swbox_y2) / 2 - 0.005 * 16 - 0.075; + x = local_swbox_x1; + y = yoff + 0.005 * idx + 0.05 * (idx / 8); + return true; + } + + if (id >= TILE_WIRE_LUTFF_0_IN_0 && id <= TILE_WIRE_LUTFF_7_IN_3) { + int idx = id - TILE_WIRE_LUTFF_0_IN_0; + int z = idx / 4; + int input = idx % 4; + x = local_swbox_x2; + y = (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * input) + z * logic_cell_pitch; + return true; + } + + return false; +} + +void pipGfx(std::vector &g, int x, int y, float x1, float y1, float x2, float y2, float swx1, + float swy1, float swx2, float swy2, GraphicElement::style_t style) +{ + float tx = 0.5 * (x1 + x2); + float ty = 0.5 * (y1 + y2); + + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + + if (fabsf(x1 - swx1) < 0.001 && fabsf(x2 - swx1) < 0.001) { + tx = x1 + 0.25 * fabsf(y1 - y2); + goto edge_pip; + } + + if (fabsf(x1 - swx2) < 0.001 && fabsf(x2 - swx2) < 0.001) { + tx = x1 - 0.25 * fabsf(y1 - y2); + goto edge_pip; + } + + if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) { + ty = y1 + 0.25 * fabsf(x1 - x2); + goto edge_pip; + } + + if (fabsf(y1 - swy1) < 0.001 && fabsf(y2 - swy1) < 0.001) { + ty = y1 + 0.25 * fabsf(x1 - x2); + goto edge_pip; + } + + el.x1 = x + x1; + el.y1 = y + y1; + el.x2 = x + x2; + el.y2 = y + y2; + g.push_back(el); + return; + +edge_pip: + el.x1 = x + x1; + el.y1 = y + y1; + el.x2 = x + tx; + el.y2 = y + ty; + g.push_back(el); + + el.x1 = x + tx; + el.y1 = y + ty; + el.x2 = x + x2; + el.y2 = y + y2; + g.push_back(el); +} + +void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, + GraphicElement::style_t style) +{ + float x1, y1, x2, y2; + + if (getWireXY_main(src, x1, y1) && getWireXY_main(dst, x2, y2)) { + pipGfx(g, x, y, x1, y1, x2, y2, main_swbox_x1, main_swbox_y1, main_swbox_x2, main_swbox_y2, style); + return; + } + + if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2)) { + pipGfx(g, x, y, x1, y1, x2, y2, local_swbox_x1, local_swbox_y1, local_swbox_x2, local_swbox_y2, style); + return; + } + + if (TILE_WIRE_LUTFF_0_IN_0_LUT <= src && src <= TILE_WIRE_LUTFF_7_IN_3_LUT && TILE_WIRE_LUTFF_0_OUT <= dst && + dst <= TILE_WIRE_LUTFF_7_OUT) { + int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0_LUT) / 4; + int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0_LUT) % 4; + + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + el.x1 = x + logic_cell_x1; + el.x2 = x + logic_cell_x2; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch; + el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 + lut_idx * logic_cell_pitch; + g.push_back(el); + return; + } + + if (TILE_WIRE_LUTFF_0_IN_0 <= src && src <= TILE_WIRE_LUTFF_7_IN_3 && TILE_WIRE_LUTFF_0_IN_0_LUT <= dst && + dst <= TILE_WIRE_LUTFF_7_IN_3_LUT) { + int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0) / 4; + int in_idx = (src - TILE_WIRE_LUTFF_0_IN_0) % 4; + int out_idx = (dst - TILE_WIRE_LUTFF_0_IN_0_LUT) % 4; + + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + el.x1 = x + lut_swbox_x1; + el.x2 = x + lut_swbox_x2; + el.y1 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * in_idx) + lut_idx * logic_cell_pitch; + el.y2 = y + (logic_cell_y1 + logic_cell_y2) / 2 - 0.0075 + (0.005 * out_idx) + lut_idx * logic_cell_pitch; + g.push_back(el); + return; + } + + if (src == TILE_WIRE_CARRY_IN && dst == TILE_WIRE_CARRY_IN_MUX) { + GraphicElement el; + el.type = GraphicElement::TYPE_ARROW; + el.style = style; + el.x1 = x + logic_cell_x1 + 0.005 * 3; + el.x2 = el.x1; + el.y1 = y + 0.01; + el.y2 = y + 0.02; + g.push_back(el); + return; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/gfx.h b/xc7/gfx.h new file mode 100644 index 00000000..8ee7b0b6 --- /dev/null +++ b/xc7/gfx.h @@ -0,0 +1,523 @@ +/* + * 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 GFX_H +#define GFX_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +const float main_swbox_x1 = 0.35; +const float main_swbox_x2 = 0.60; +const float main_swbox_y1 = 0.05; +const float main_swbox_y2 = 0.73; + +const float local_swbox_x1 = 0.63; +const float local_swbox_x2 = 0.73; +const float local_swbox_y1 = 0.05; +const float local_swbox_y2 = 0.55; + +const float lut_swbox_x1 = 0.76; +const float lut_swbox_x2 = 0.80; + +const float logic_cell_x1 = 0.83; +const float logic_cell_x2 = 0.95; +const float logic_cell_y1 = 0.05; +const float logic_cell_y2 = 0.10; +const float logic_cell_pitch = 0.0625; + +enum GfxTileWireId +{ + TILE_WIRE_GLB2LOCAL_0, + TILE_WIRE_GLB2LOCAL_1, + TILE_WIRE_GLB2LOCAL_2, + TILE_WIRE_GLB2LOCAL_3, + + TILE_WIRE_GLB_NETWK_0, + TILE_WIRE_GLB_NETWK_1, + TILE_WIRE_GLB_NETWK_2, + TILE_WIRE_GLB_NETWK_3, + TILE_WIRE_GLB_NETWK_4, + TILE_WIRE_GLB_NETWK_5, + TILE_WIRE_GLB_NETWK_6, + TILE_WIRE_GLB_NETWK_7, + + TILE_WIRE_LOCAL_G0_0, + TILE_WIRE_LOCAL_G0_1, + TILE_WIRE_LOCAL_G0_2, + TILE_WIRE_LOCAL_G0_3, + TILE_WIRE_LOCAL_G0_4, + TILE_WIRE_LOCAL_G0_5, + TILE_WIRE_LOCAL_G0_6, + TILE_WIRE_LOCAL_G0_7, + + TILE_WIRE_LOCAL_G1_0, + TILE_WIRE_LOCAL_G1_1, + TILE_WIRE_LOCAL_G1_2, + TILE_WIRE_LOCAL_G1_3, + TILE_WIRE_LOCAL_G1_4, + TILE_WIRE_LOCAL_G1_5, + TILE_WIRE_LOCAL_G1_6, + TILE_WIRE_LOCAL_G1_7, + + TILE_WIRE_LOCAL_G2_0, + TILE_WIRE_LOCAL_G2_1, + TILE_WIRE_LOCAL_G2_2, + TILE_WIRE_LOCAL_G2_3, + TILE_WIRE_LOCAL_G2_4, + TILE_WIRE_LOCAL_G2_5, + TILE_WIRE_LOCAL_G2_6, + TILE_WIRE_LOCAL_G2_7, + + TILE_WIRE_LOCAL_G3_0, + TILE_WIRE_LOCAL_G3_1, + TILE_WIRE_LOCAL_G3_2, + TILE_WIRE_LOCAL_G3_3, + TILE_WIRE_LOCAL_G3_4, + TILE_WIRE_LOCAL_G3_5, + TILE_WIRE_LOCAL_G3_6, + TILE_WIRE_LOCAL_G3_7, + + TILE_WIRE_LUTFF_0_IN_0, + TILE_WIRE_LUTFF_0_IN_1, + TILE_WIRE_LUTFF_0_IN_2, + TILE_WIRE_LUTFF_0_IN_3, + + TILE_WIRE_LUTFF_1_IN_0, + TILE_WIRE_LUTFF_1_IN_1, + TILE_WIRE_LUTFF_1_IN_2, + TILE_WIRE_LUTFF_1_IN_3, + + TILE_WIRE_LUTFF_2_IN_0, + TILE_WIRE_LUTFF_2_IN_1, + TILE_WIRE_LUTFF_2_IN_2, + TILE_WIRE_LUTFF_2_IN_3, + + TILE_WIRE_LUTFF_3_IN_0, + TILE_WIRE_LUTFF_3_IN_1, + TILE_WIRE_LUTFF_3_IN_2, + TILE_WIRE_LUTFF_3_IN_3, + + TILE_WIRE_LUTFF_4_IN_0, + TILE_WIRE_LUTFF_4_IN_1, + TILE_WIRE_LUTFF_4_IN_2, + TILE_WIRE_LUTFF_4_IN_3, + + TILE_WIRE_LUTFF_5_IN_0, + TILE_WIRE_LUTFF_5_IN_1, + TILE_WIRE_LUTFF_5_IN_2, + TILE_WIRE_LUTFF_5_IN_3, + + TILE_WIRE_LUTFF_6_IN_0, + TILE_WIRE_LUTFF_6_IN_1, + TILE_WIRE_LUTFF_6_IN_2, + TILE_WIRE_LUTFF_6_IN_3, + + TILE_WIRE_LUTFF_7_IN_0, + TILE_WIRE_LUTFF_7_IN_1, + TILE_WIRE_LUTFF_7_IN_2, + TILE_WIRE_LUTFF_7_IN_3, + + TILE_WIRE_LUTFF_0_IN_0_LUT, + TILE_WIRE_LUTFF_0_IN_1_LUT, + TILE_WIRE_LUTFF_0_IN_2_LUT, + TILE_WIRE_LUTFF_0_IN_3_LUT, + + TILE_WIRE_LUTFF_1_IN_0_LUT, + TILE_WIRE_LUTFF_1_IN_1_LUT, + TILE_WIRE_LUTFF_1_IN_2_LUT, + TILE_WIRE_LUTFF_1_IN_3_LUT, + + TILE_WIRE_LUTFF_2_IN_0_LUT, + TILE_WIRE_LUTFF_2_IN_1_LUT, + TILE_WIRE_LUTFF_2_IN_2_LUT, + TILE_WIRE_LUTFF_2_IN_3_LUT, + + TILE_WIRE_LUTFF_3_IN_0_LUT, + TILE_WIRE_LUTFF_3_IN_1_LUT, + TILE_WIRE_LUTFF_3_IN_2_LUT, + TILE_WIRE_LUTFF_3_IN_3_LUT, + + TILE_WIRE_LUTFF_4_IN_0_LUT, + TILE_WIRE_LUTFF_4_IN_1_LUT, + TILE_WIRE_LUTFF_4_IN_2_LUT, + TILE_WIRE_LUTFF_4_IN_3_LUT, + + TILE_WIRE_LUTFF_5_IN_0_LUT, + TILE_WIRE_LUTFF_5_IN_1_LUT, + TILE_WIRE_LUTFF_5_IN_2_LUT, + TILE_WIRE_LUTFF_5_IN_3_LUT, + + TILE_WIRE_LUTFF_6_IN_0_LUT, + TILE_WIRE_LUTFF_6_IN_1_LUT, + TILE_WIRE_LUTFF_6_IN_2_LUT, + TILE_WIRE_LUTFF_6_IN_3_LUT, + + TILE_WIRE_LUTFF_7_IN_0_LUT, + TILE_WIRE_LUTFF_7_IN_1_LUT, + TILE_WIRE_LUTFF_7_IN_2_LUT, + TILE_WIRE_LUTFF_7_IN_3_LUT, + + TILE_WIRE_LUTFF_0_LOUT, + TILE_WIRE_LUTFF_1_LOUT, + TILE_WIRE_LUTFF_2_LOUT, + TILE_WIRE_LUTFF_3_LOUT, + TILE_WIRE_LUTFF_4_LOUT, + TILE_WIRE_LUTFF_5_LOUT, + TILE_WIRE_LUTFF_6_LOUT, + + TILE_WIRE_LUTFF_0_OUT, + TILE_WIRE_LUTFF_1_OUT, + TILE_WIRE_LUTFF_2_OUT, + TILE_WIRE_LUTFF_3_OUT, + TILE_WIRE_LUTFF_4_OUT, + TILE_WIRE_LUTFF_5_OUT, + TILE_WIRE_LUTFF_6_OUT, + TILE_WIRE_LUTFF_7_OUT, + + TILE_WIRE_LUTFF_0_COUT, + TILE_WIRE_LUTFF_1_COUT, + TILE_WIRE_LUTFF_2_COUT, + TILE_WIRE_LUTFF_3_COUT, + TILE_WIRE_LUTFF_4_COUT, + TILE_WIRE_LUTFF_5_COUT, + TILE_WIRE_LUTFF_6_COUT, + TILE_WIRE_LUTFF_7_COUT, + + TILE_WIRE_LUTFF_GLOBAL_CEN, + TILE_WIRE_LUTFF_GLOBAL_CLK, + TILE_WIRE_LUTFF_GLOBAL_S_R, + + TILE_WIRE_CARRY_IN, + TILE_WIRE_CARRY_IN_MUX, + + TILE_WIRE_NEIGH_OP_BNL_0, + TILE_WIRE_NEIGH_OP_BNL_1, + TILE_WIRE_NEIGH_OP_BNL_2, + TILE_WIRE_NEIGH_OP_BNL_3, + TILE_WIRE_NEIGH_OP_BNL_4, + TILE_WIRE_NEIGH_OP_BNL_5, + TILE_WIRE_NEIGH_OP_BNL_6, + TILE_WIRE_NEIGH_OP_BNL_7, + + TILE_WIRE_NEIGH_OP_BNR_0, + TILE_WIRE_NEIGH_OP_BNR_1, + TILE_WIRE_NEIGH_OP_BNR_2, + TILE_WIRE_NEIGH_OP_BNR_3, + TILE_WIRE_NEIGH_OP_BNR_4, + TILE_WIRE_NEIGH_OP_BNR_5, + TILE_WIRE_NEIGH_OP_BNR_6, + TILE_WIRE_NEIGH_OP_BNR_7, + + TILE_WIRE_NEIGH_OP_BOT_0, + TILE_WIRE_NEIGH_OP_BOT_1, + TILE_WIRE_NEIGH_OP_BOT_2, + TILE_WIRE_NEIGH_OP_BOT_3, + TILE_WIRE_NEIGH_OP_BOT_4, + TILE_WIRE_NEIGH_OP_BOT_5, + TILE_WIRE_NEIGH_OP_BOT_6, + TILE_WIRE_NEIGH_OP_BOT_7, + + TILE_WIRE_NEIGH_OP_LFT_0, + TILE_WIRE_NEIGH_OP_LFT_1, + TILE_WIRE_NEIGH_OP_LFT_2, + TILE_WIRE_NEIGH_OP_LFT_3, + TILE_WIRE_NEIGH_OP_LFT_4, + TILE_WIRE_NEIGH_OP_LFT_5, + TILE_WIRE_NEIGH_OP_LFT_6, + TILE_WIRE_NEIGH_OP_LFT_7, + + TILE_WIRE_NEIGH_OP_RGT_0, + TILE_WIRE_NEIGH_OP_RGT_1, + TILE_WIRE_NEIGH_OP_RGT_2, + TILE_WIRE_NEIGH_OP_RGT_3, + TILE_WIRE_NEIGH_OP_RGT_4, + TILE_WIRE_NEIGH_OP_RGT_5, + TILE_WIRE_NEIGH_OP_RGT_6, + TILE_WIRE_NEIGH_OP_RGT_7, + + TILE_WIRE_NEIGH_OP_TNL_0, + TILE_WIRE_NEIGH_OP_TNL_1, + TILE_WIRE_NEIGH_OP_TNL_2, + TILE_WIRE_NEIGH_OP_TNL_3, + TILE_WIRE_NEIGH_OP_TNL_4, + TILE_WIRE_NEIGH_OP_TNL_5, + TILE_WIRE_NEIGH_OP_TNL_6, + TILE_WIRE_NEIGH_OP_TNL_7, + + TILE_WIRE_NEIGH_OP_TNR_0, + TILE_WIRE_NEIGH_OP_TNR_1, + TILE_WIRE_NEIGH_OP_TNR_2, + TILE_WIRE_NEIGH_OP_TNR_3, + TILE_WIRE_NEIGH_OP_TNR_4, + TILE_WIRE_NEIGH_OP_TNR_5, + TILE_WIRE_NEIGH_OP_TNR_6, + TILE_WIRE_NEIGH_OP_TNR_7, + + TILE_WIRE_NEIGH_OP_TOP_0, + TILE_WIRE_NEIGH_OP_TOP_1, + TILE_WIRE_NEIGH_OP_TOP_2, + TILE_WIRE_NEIGH_OP_TOP_3, + TILE_WIRE_NEIGH_OP_TOP_4, + TILE_WIRE_NEIGH_OP_TOP_5, + TILE_WIRE_NEIGH_OP_TOP_6, + TILE_WIRE_NEIGH_OP_TOP_7, + + TILE_WIRE_SP4_V_B_0, + TILE_WIRE_SP4_V_B_1, + TILE_WIRE_SP4_V_B_2, + TILE_WIRE_SP4_V_B_3, + TILE_WIRE_SP4_V_B_4, + TILE_WIRE_SP4_V_B_5, + TILE_WIRE_SP4_V_B_6, + TILE_WIRE_SP4_V_B_7, + TILE_WIRE_SP4_V_B_8, + TILE_WIRE_SP4_V_B_9, + TILE_WIRE_SP4_V_B_10, + TILE_WIRE_SP4_V_B_11, + TILE_WIRE_SP4_V_B_12, + TILE_WIRE_SP4_V_B_13, + TILE_WIRE_SP4_V_B_14, + TILE_WIRE_SP4_V_B_15, + TILE_WIRE_SP4_V_B_16, + TILE_WIRE_SP4_V_B_17, + TILE_WIRE_SP4_V_B_18, + TILE_WIRE_SP4_V_B_19, + TILE_WIRE_SP4_V_B_20, + TILE_WIRE_SP4_V_B_21, + TILE_WIRE_SP4_V_B_22, + TILE_WIRE_SP4_V_B_23, + TILE_WIRE_SP4_V_B_24, + TILE_WIRE_SP4_V_B_25, + TILE_WIRE_SP4_V_B_26, + TILE_WIRE_SP4_V_B_27, + TILE_WIRE_SP4_V_B_28, + TILE_WIRE_SP4_V_B_29, + TILE_WIRE_SP4_V_B_30, + TILE_WIRE_SP4_V_B_31, + TILE_WIRE_SP4_V_B_32, + TILE_WIRE_SP4_V_B_33, + TILE_WIRE_SP4_V_B_34, + TILE_WIRE_SP4_V_B_35, + TILE_WIRE_SP4_V_B_36, + TILE_WIRE_SP4_V_B_37, + TILE_WIRE_SP4_V_B_38, + TILE_WIRE_SP4_V_B_39, + TILE_WIRE_SP4_V_B_40, + TILE_WIRE_SP4_V_B_41, + TILE_WIRE_SP4_V_B_42, + TILE_WIRE_SP4_V_B_43, + TILE_WIRE_SP4_V_B_44, + TILE_WIRE_SP4_V_B_45, + TILE_WIRE_SP4_V_B_46, + TILE_WIRE_SP4_V_B_47, + + TILE_WIRE_SP4_V_T_36, + TILE_WIRE_SP4_V_T_37, + TILE_WIRE_SP4_V_T_38, + TILE_WIRE_SP4_V_T_39, + TILE_WIRE_SP4_V_T_40, + TILE_WIRE_SP4_V_T_41, + TILE_WIRE_SP4_V_T_42, + TILE_WIRE_SP4_V_T_43, + TILE_WIRE_SP4_V_T_44, + TILE_WIRE_SP4_V_T_45, + TILE_WIRE_SP4_V_T_46, + TILE_WIRE_SP4_V_T_47, + + TILE_WIRE_SP4_R_V_B_0, + TILE_WIRE_SP4_R_V_B_1, + TILE_WIRE_SP4_R_V_B_2, + TILE_WIRE_SP4_R_V_B_3, + TILE_WIRE_SP4_R_V_B_4, + TILE_WIRE_SP4_R_V_B_5, + TILE_WIRE_SP4_R_V_B_6, + TILE_WIRE_SP4_R_V_B_7, + TILE_WIRE_SP4_R_V_B_8, + TILE_WIRE_SP4_R_V_B_9, + TILE_WIRE_SP4_R_V_B_10, + TILE_WIRE_SP4_R_V_B_11, + TILE_WIRE_SP4_R_V_B_12, + TILE_WIRE_SP4_R_V_B_13, + TILE_WIRE_SP4_R_V_B_14, + TILE_WIRE_SP4_R_V_B_15, + TILE_WIRE_SP4_R_V_B_16, + TILE_WIRE_SP4_R_V_B_17, + TILE_WIRE_SP4_R_V_B_18, + TILE_WIRE_SP4_R_V_B_19, + TILE_WIRE_SP4_R_V_B_20, + TILE_WIRE_SP4_R_V_B_21, + TILE_WIRE_SP4_R_V_B_22, + TILE_WIRE_SP4_R_V_B_23, + TILE_WIRE_SP4_R_V_B_24, + TILE_WIRE_SP4_R_V_B_25, + TILE_WIRE_SP4_R_V_B_26, + TILE_WIRE_SP4_R_V_B_27, + TILE_WIRE_SP4_R_V_B_28, + TILE_WIRE_SP4_R_V_B_29, + TILE_WIRE_SP4_R_V_B_30, + TILE_WIRE_SP4_R_V_B_31, + TILE_WIRE_SP4_R_V_B_32, + TILE_WIRE_SP4_R_V_B_33, + TILE_WIRE_SP4_R_V_B_34, + TILE_WIRE_SP4_R_V_B_35, + TILE_WIRE_SP4_R_V_B_36, + TILE_WIRE_SP4_R_V_B_37, + TILE_WIRE_SP4_R_V_B_38, + TILE_WIRE_SP4_R_V_B_39, + TILE_WIRE_SP4_R_V_B_40, + TILE_WIRE_SP4_R_V_B_41, + TILE_WIRE_SP4_R_V_B_42, + TILE_WIRE_SP4_R_V_B_43, + TILE_WIRE_SP4_R_V_B_44, + TILE_WIRE_SP4_R_V_B_45, + TILE_WIRE_SP4_R_V_B_46, + TILE_WIRE_SP4_R_V_B_47, + + TILE_WIRE_SP4_H_L_36, + TILE_WIRE_SP4_H_L_37, + TILE_WIRE_SP4_H_L_38, + TILE_WIRE_SP4_H_L_39, + TILE_WIRE_SP4_H_L_40, + TILE_WIRE_SP4_H_L_41, + TILE_WIRE_SP4_H_L_42, + TILE_WIRE_SP4_H_L_43, + TILE_WIRE_SP4_H_L_44, + TILE_WIRE_SP4_H_L_45, + TILE_WIRE_SP4_H_L_46, + TILE_WIRE_SP4_H_L_47, + + TILE_WIRE_SP4_H_R_0, + TILE_WIRE_SP4_H_R_1, + TILE_WIRE_SP4_H_R_2, + TILE_WIRE_SP4_H_R_3, + TILE_WIRE_SP4_H_R_4, + TILE_WIRE_SP4_H_R_5, + TILE_WIRE_SP4_H_R_6, + TILE_WIRE_SP4_H_R_7, + TILE_WIRE_SP4_H_R_8, + TILE_WIRE_SP4_H_R_9, + TILE_WIRE_SP4_H_R_10, + TILE_WIRE_SP4_H_R_11, + TILE_WIRE_SP4_H_R_12, + TILE_WIRE_SP4_H_R_13, + TILE_WIRE_SP4_H_R_14, + TILE_WIRE_SP4_H_R_15, + TILE_WIRE_SP4_H_R_16, + TILE_WIRE_SP4_H_R_17, + TILE_WIRE_SP4_H_R_18, + TILE_WIRE_SP4_H_R_19, + TILE_WIRE_SP4_H_R_20, + TILE_WIRE_SP4_H_R_21, + TILE_WIRE_SP4_H_R_22, + TILE_WIRE_SP4_H_R_23, + TILE_WIRE_SP4_H_R_24, + TILE_WIRE_SP4_H_R_25, + TILE_WIRE_SP4_H_R_26, + TILE_WIRE_SP4_H_R_27, + TILE_WIRE_SP4_H_R_28, + TILE_WIRE_SP4_H_R_29, + TILE_WIRE_SP4_H_R_30, + TILE_WIRE_SP4_H_R_31, + TILE_WIRE_SP4_H_R_32, + TILE_WIRE_SP4_H_R_33, + TILE_WIRE_SP4_H_R_34, + TILE_WIRE_SP4_H_R_35, + TILE_WIRE_SP4_H_R_36, + TILE_WIRE_SP4_H_R_37, + TILE_WIRE_SP4_H_R_38, + TILE_WIRE_SP4_H_R_39, + TILE_WIRE_SP4_H_R_40, + TILE_WIRE_SP4_H_R_41, + TILE_WIRE_SP4_H_R_42, + TILE_WIRE_SP4_H_R_43, + TILE_WIRE_SP4_H_R_44, + TILE_WIRE_SP4_H_R_45, + TILE_WIRE_SP4_H_R_46, + TILE_WIRE_SP4_H_R_47, + + TILE_WIRE_SP12_V_B_0, + TILE_WIRE_SP12_V_B_1, + TILE_WIRE_SP12_V_B_2, + TILE_WIRE_SP12_V_B_3, + TILE_WIRE_SP12_V_B_4, + TILE_WIRE_SP12_V_B_5, + TILE_WIRE_SP12_V_B_6, + TILE_WIRE_SP12_V_B_7, + TILE_WIRE_SP12_V_B_8, + TILE_WIRE_SP12_V_B_9, + TILE_WIRE_SP12_V_B_10, + TILE_WIRE_SP12_V_B_11, + TILE_WIRE_SP12_V_B_12, + TILE_WIRE_SP12_V_B_13, + TILE_WIRE_SP12_V_B_14, + TILE_WIRE_SP12_V_B_15, + TILE_WIRE_SP12_V_B_16, + TILE_WIRE_SP12_V_B_17, + TILE_WIRE_SP12_V_B_18, + TILE_WIRE_SP12_V_B_19, + TILE_WIRE_SP12_V_B_20, + TILE_WIRE_SP12_V_B_21, + TILE_WIRE_SP12_V_B_22, + TILE_WIRE_SP12_V_B_23, + + TILE_WIRE_SP12_V_T_22, + TILE_WIRE_SP12_V_T_23, + + TILE_WIRE_SP12_H_R_0, + TILE_WIRE_SP12_H_R_1, + TILE_WIRE_SP12_H_R_2, + TILE_WIRE_SP12_H_R_3, + TILE_WIRE_SP12_H_R_4, + TILE_WIRE_SP12_H_R_5, + TILE_WIRE_SP12_H_R_6, + TILE_WIRE_SP12_H_R_7, + TILE_WIRE_SP12_H_R_8, + TILE_WIRE_SP12_H_R_9, + TILE_WIRE_SP12_H_R_10, + TILE_WIRE_SP12_H_R_11, + TILE_WIRE_SP12_H_R_12, + TILE_WIRE_SP12_H_R_13, + TILE_WIRE_SP12_H_R_14, + TILE_WIRE_SP12_H_R_15, + TILE_WIRE_SP12_H_R_16, + TILE_WIRE_SP12_H_R_17, + TILE_WIRE_SP12_H_R_18, + TILE_WIRE_SP12_H_R_19, + TILE_WIRE_SP12_H_R_20, + TILE_WIRE_SP12_H_R_21, + TILE_WIRE_SP12_H_R_22, + TILE_WIRE_SP12_H_R_23, + + TILE_WIRE_SP12_H_L_22, + TILE_WIRE_SP12_H_L_23, + + TILE_WIRE_PLLIN, + TILE_WIRE_PLLOUT_A, + TILE_WIRE_PLLOUT_B +}; + +void gfxTileWire(std::vector &g, int x, int y, GfxTileWireId id, GraphicElement::style_t style); +void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, GfxTileWireId dst, + GraphicElement::style_t style); + +NEXTPNR_NAMESPACE_END + +#endif // GFX_H diff --git a/xc7/icebreaker.pcf b/xc7/icebreaker.pcf new file mode 100644 index 00000000..bc4a2974 --- /dev/null +++ b/xc7/icebreaker.pcf @@ -0,0 +1,14 @@ +set_io led1 27 +set_io led2 25 +set_io led3 21 +set_io led4 23 +set_io led5 26 +set_io ledr 11 +set_io ledg 37 + +set_io clki 35 +set_io btn1 20 +set_io btn2 19 +set_io btn3 18 +set_io btn_n 10 + diff --git a/xc7/icebreaker.v b/xc7/icebreaker.v new file mode 100644 index 00000000..1c8c0863 --- /dev/null +++ b/xc7/icebreaker.v @@ -0,0 +1,31 @@ +module icebreaker ( + input clki, + input btn1, + input btn2, + input btn3, + input btn_n, + + output led1, + output led2, + output led3, + output led4, + output led5, + output ledr, + output ledg, +); + wire clk; + SB_GB clk_gb(.USER_SIGNAL_TO_GLOBAL_BUFFER(clki), .GLOBAL_BUFFER_OUTPUT(clk)); + localparam BITS = 5; + localparam LOG2DELAY = 22; + + reg [BITS+LOG2DELAY-1:0] counter = 0; + reg [BITS-1:0] outcnt; + + always @(posedge clk) begin + counter <= counter + 1; + outcnt <= counter >> LOG2DELAY; + end + assign {led1, led2, led3, led4, led5} = outcnt ^ (outcnt >> 1); + + assign {ledr, ledg} = ~(!btn_n + btn1 + btn2 + btn3); +endmodule diff --git a/xc7/icebreaker.ys b/xc7/icebreaker.ys new file mode 100644 index 00000000..878914aa --- /dev/null +++ b/xc7/icebreaker.ys @@ -0,0 +1,3 @@ +read_verilog icebreaker.v +synth_ice40 -nocarry -top icebreaker +write_json icebreaker.json diff --git a/xc7/main.cc b/xc7/main.cc new file mode 100644 index 00000000..8bab360d --- /dev/null +++ b/xc7/main.cc @@ -0,0 +1,164 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 Miodrag Milanovic + * + * 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. + * + */ + +#ifdef MAIN_EXECUTABLE + +#include +#include "bitstream.h" +#include "command.h" +#include "design_utils.h" +#include "jsonparse.h" +#include "log.h" +#include "pcf.h" +#include "timing.h" + +USING_NEXTPNR_NAMESPACE + +class Ice40CommandHandler : public CommandHandler +{ + public: + Ice40CommandHandler(int argc, char **argv); + virtual ~Ice40CommandHandler(){}; + std::unique_ptr createContext() override; + void setupArchContext(Context *ctx) override; + void validate() override; + void customAfterLoad(Context *ctx) override; + void customBitstream(Context *ctx) override; + + protected: + po::options_description getArchOptions(); +}; + +Ice40CommandHandler::Ice40CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} + +po::options_description Ice40CommandHandler::getArchOptions() +{ + po::options_description specific("Architecture specific options"); +#ifdef ICE40_HX1K_ONLY + specific.add_options()("hx1k", "set device type to iCE40HX1K"); +#else + specific.add_options()("lp384", "set device type to iCE40LP384"); + specific.add_options()("lp1k", "set device type to iCE40LP1K"); + specific.add_options()("lp8k", "set device type to iCE40LP8K"); + specific.add_options()("hx1k", "set device type to iCE40HX1K"); + specific.add_options()("hx8k", "set device type to iCE40HX8K"); + specific.add_options()("up5k", "set device type to iCE40UP5K"); +#endif + specific.add_options()("package", po::value(), "set device package"); + specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); + specific.add_options()("asc", po::value(), "asc bitstream file to write"); + specific.add_options()("read", po::value(), "asc bitstream file to read"); + specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); + return specific; +} +void Ice40CommandHandler::validate() +{ + conflicting_options(vm, "read", "json"); + if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + + vm.count("up5k")) > 1) + log_error("Only one device type can be set\n"); +} + +void Ice40CommandHandler::customAfterLoad(Context *ctx) +{ + if (vm.count("pcf")) { + std::string filename = vm["pcf"].as(); + std::ifstream pcf(filename); + if (!apply_pcf(ctx, filename, pcf)) + log_error("Loading PCF failed.\n"); + } +} +void Ice40CommandHandler::customBitstream(Context *ctx) +{ + if (vm.count("asc")) { + std::string filename = vm["asc"].as(); + std::ofstream f(filename); + write_asc(ctx, f); + } +} + +void Ice40CommandHandler::setupArchContext(Context *ctx) +{ + if (vm.count("tmfuzz")) + ice40DelayFuzzerMain(ctx); + + if (vm.count("read")) { + std::string filename = vm["read"].as(); + std::ifstream f(filename); + if (!read_asc(ctx, f)) + log_error("Loading ASC failed.\n"); + } +} + +std::unique_ptr Ice40CommandHandler::createContext() +{ + if (vm.count("lp384")) { + chipArgs.type = ArchArgs::LP384; + chipArgs.package = "qn32"; + } + + if (vm.count("lp1k")) { + chipArgs.type = ArchArgs::LP1K; + chipArgs.package = "tq144"; + } + + if (vm.count("lp8k")) { + chipArgs.type = ArchArgs::LP8K; + chipArgs.package = "ct256"; + } + + if (vm.count("hx1k")) { + chipArgs.type = ArchArgs::HX1K; + chipArgs.package = "tq144"; + } + + if (vm.count("hx8k")) { + chipArgs.type = ArchArgs::HX8K; + chipArgs.package = "ct256"; + } + + if (vm.count("up5k")) { + chipArgs.type = ArchArgs::UP5K; + chipArgs.package = "sg48"; + } + + if (chipArgs.type == ArchArgs::NONE) { + chipArgs.type = ArchArgs::HX1K; + chipArgs.package = "tq144"; + } +#ifdef ICE40_HX1K_ONLY + if (chipArgs.type != ArchArgs::HX1K) { + log_error("This version of nextpnr-ice40 is built with HX1K-support only.\n"); + } +#endif + + if (vm.count("package")) + chipArgs.package = vm["package"].as(); + + return std::unique_ptr(new Context(chipArgs)); +} + +int main(int argc, char *argv[]) +{ + Ice40CommandHandler handler(argc, argv); + return handler.exec(); +} + +#endif diff --git a/xc7/pack.cc b/xc7/pack.cc new file mode 100644 index 00000000..05338713 --- /dev/null +++ b/xc7/pack.cc @@ -0,0 +1,907 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski + * + * 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 +#include +#include +#include "cells.h" +#include "chains.h" +#include "design_utils.h" +#include "log.h" +#include "util.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Pack LUTs and LUT-FF pairs +static void pack_lut_lutffs(Context *ctx) +{ + log_info("Packing LUT-FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (ctx->verbose) + log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); + if (is_lut(ctx, ci)) { + std::unique_ptr packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_LC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + packed_cells.insert(ci->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + // See if we can pack into a DFF + // TODO: LUT cascade + NetInfo *o = ci->ports.at(ctx->id("O")).net; + CellInfo *dff = net_only_drives(ctx, o, is_ff, ctx->id("D"), true); + auto lut_bel = ci->attrs.find(ctx->id("BEL")); + bool packed_dff = false; + if (dff) { + if (ctx->verbose) + log_info("found attached dff %s\n", dff->name.c_str(ctx)); + auto dff_bel = dff->attrs.find(ctx->id("BEL")); + if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) { + // Locations don't match, can't pack + } else { + lut_to_lc(ctx, ci, packed.get(), false); + dff_to_lc(ctx, dff, packed.get(), false); + ctx->nets.erase(o->name); + if (dff_bel != dff->attrs.end()) + packed->attrs[ctx->id("BEL")] = dff_bel->second; + packed_cells.insert(dff->name); + if (ctx->verbose) + log_info("packed cell %s into %s\n", dff->name.c_str(ctx), packed->name.c_str(ctx)); + packed_dff = true; + } + } + if (!packed_dff) { + lut_to_lc(ctx, ci, packed.get(), true); + } + new_cells.push_back(std::move(packed)); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Pack FFs not packed as LUTFFs +static void pack_nonlut_ffs(Context *ctx) +{ + log_info("Packing non-LUT FFs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_ff(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_DFFLC"); + std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); + packed_cells.insert(ci->name); + dff_to_lc(ctx, ci, packed.get(), true); + new_cells.push_back(std::move(packed)); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value) +{ + if (net == nullptr) + return false; + if (net->name == ctx->id("$PACKER_GND_NET") || net->name == ctx->id("$PACKER_VCC_NET")) { + value = (net->name == ctx->id("$PACKER_VCC_NET")); + return true; + } else { + return false; + } +} + +// Pack carry logic +static void pack_carries(Context *ctx) +{ + log_info("Packing carries..\n"); + std::unordered_set exhausted_cells; + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_carry(ctx, ci)) { + packed_cells.insert(cell.first); + + CellInfo *carry_ci_lc; + bool ci_value; + bool ci_const = net_is_constant(ctx, ci->ports.at(ctx->id("CI")).net, ci_value); + if (ci_const) { + carry_ci_lc = nullptr; + } else { + carry_ci_lc = net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc, ctx->id("I3"), false); + } + + std::set i0_matches, i1_matches; + NetInfo *i0_net = ci->ports.at(ctx->id("I0")).net; + NetInfo *i1_net = ci->ports.at(ctx->id("I1")).net; + // Find logic cells connected to both I0 and I1 + if (i0_net) { + for (auto usr : i0_net->users) { + if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I1")) { + if (ctx->cells.find(usr.cell->name) != ctx->cells.end() && + exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) { + // This clause stops us double-packing cells + i0_matches.insert(usr.cell->name); + if (!i1_net) { + // I1 is don't care when disconnected, duplicate I0 + i1_matches.insert(usr.cell->name); + } + } + } + } + } + if (i1_net) { + for (auto usr : i1_net->users) { + if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I2")) { + if (ctx->cells.find(usr.cell->name) != ctx->cells.end() && + exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) { + // This clause stops us double-packing cells + i1_matches.insert(usr.cell->name); + if (!i0_net) { + // I0 is don't care when disconnected, duplicate I1 + i0_matches.insert(usr.cell->name); + } + } + } + } + } + + std::set carry_lcs; + std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(), + std::inserter(carry_lcs, carry_lcs.end())); + CellInfo *carry_lc = nullptr; + if (carry_ci_lc && carry_lcs.find(carry_ci_lc->name) != carry_lcs.end()) { + carry_lc = carry_ci_lc; + } else { + // No LC to pack into matching I0/I1, insert a new one + std::unique_ptr created_lc = + create_ice_cell(ctx, ctx->id("ICESTORM_LC"), cell.first.str(ctx) + "$CARRY"); + carry_lc = created_lc.get(); + created_lc->ports.at(ctx->id("I1")).net = i0_net; + if (i0_net) { + PortRef pr; + pr.cell = created_lc.get(); + pr.port = ctx->id("I1"); + i0_net->users.push_back(pr); + } + created_lc->ports.at(ctx->id("I2")).net = i1_net; + if (i1_net) { + PortRef pr; + pr.cell = created_lc.get(); + pr.port = ctx->id("I2"); + i1_net->users.push_back(pr); + } + new_cells.push_back(std::move(created_lc)); + } + carry_lc->params[ctx->id("CARRY_ENABLE")] = "1"; + replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN")); + replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT")); + if (i0_net) { + auto &i0_usrs = i0_net->users; + i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) { + return pr.cell == ci && pr.port == ctx->id("I0"); + })); + } + if (i1_net) { + auto &i1_usrs = i1_net->users; + i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx](const PortRef &pr) { + return pr.cell == ci && pr.port == ctx->id("I1"); + })); + } + + // Check for constant driver on CIN + if (carry_lc->ports.at(ctx->id("CIN")).net != nullptr) { + IdString cin_net = carry_lc->ports.at(ctx->id("CIN")).net->name; + if (cin_net == ctx->id("$PACKER_GND_NET") || cin_net == ctx->id("$PACKER_VCC_NET")) { + carry_lc->params[ctx->id("CIN_CONST")] = "1"; + carry_lc->params[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0"; + carry_lc->ports.at(ctx->id("CIN")).net = nullptr; + auto &cin_users = ctx->nets.at(cin_net)->users; + cin_users.erase( + std::remove_if(cin_users.begin(), cin_users.end(), [carry_lc, ctx](const PortRef &pr) { + return pr.cell == carry_lc && pr.port == ctx->id("CIN"); + })); + } + } + exhausted_cells.insert(carry_lc->name); + } + } + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// "Pack" RAMs +static void pack_ram(Context *ctx) +{ + log_info("Packing RAMs..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_ram(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM"); + packed_cells.insert(ci->name); + for (auto param : ci->params) + packed->params[param.first] = param.second; + packed->params[ctx->id("NEG_CLK_W")] = + std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW")); + packed->params[ctx->id("NEG_CLK_R")] = + std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW")); + packed->type = ctx->id("ICESTORM_RAM"); + for (auto port : ci->ports) { + PortInfo &pi = port.second; + std::string newname = pi.name.str(ctx); + size_t bpos = newname.find('['); + if (bpos != std::string::npos) { + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); + } + if (pi.name == ctx->id("RCLKN")) + newname = "RCLK"; + else if (pi.name == ctx->id("WCLKN")) + newname = "WCLK"; + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + new_cells.push_back(std::move(packed)); + } + } + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Merge a net into a constant net +static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constnet, bool constval) +{ + orig->driver.cell = nullptr; + for (auto user : orig->users) { + if (user.cell != nullptr) { + CellInfo *uc = user.cell; + if (ctx->verbose) + log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); + if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && + !constval) { + uc->ports[user.port].net = nullptr; + } else if ((is_sb_mac16(ctx, uc) || uc->type == ctx->id("ICESTORM_DSP")) && + (user.port != ctx->id("CLK") && + ((constval && user.port == ctx->id("CE")) || (!constval && user.port != ctx->id("CE"))))) { + uc->ports[user.port].net = nullptr; + } else if (is_ram(ctx, uc) && !constval && user.port != ctx->id("RCLK") && user.port != ctx->id("RCLKN") && + user.port != ctx->id("WCLK") && user.port != ctx->id("WCLKN") && user.port != ctx->id("RCLKE") && + user.port != ctx->id("WCLKE")) { + uc->ports[user.port].net = nullptr; + } else { + uc->ports[user.port].net = constnet; + constnet->users.push_back(user); + } + } + } + orig->users.clear(); +} + +// Pack constants (simple implementation) +static void pack_constants(Context *ctx) +{ + log_info("Packing constants..\n"); + + std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND"); + gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); + gnd_net->name = ctx->id("$PACKER_GND_NET"); + gnd_net->driver.cell = gnd_cell.get(); + gnd_net->driver.port = ctx->id("O"); + gnd_cell->ports.at(ctx->id("O")).net = gnd_net.get(); + + std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC"); + vcc_cell->params[ctx->id("LUT_INIT")] = "1"; + std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); + vcc_net->name = ctx->id("$PACKER_VCC_NET"); + vcc_net->driver.cell = vcc_cell.get(); + vcc_net->driver.port = ctx->id("O"); + vcc_cell->ports.at(ctx->id("O")).net = vcc_net.get(); + + std::vector dead_nets; + + bool gnd_used = false; + + for (auto net : sorted(ctx->nets)) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, gnd_net.get(), false); + gnd_used = true; + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { + IdString drv_cell = ni->driver.cell->name; + set_net_constant(ctx, ni, vcc_net.get(), true); + dead_nets.push_back(net.first); + ctx->cells.erase(drv_cell); + } + } + + if (gnd_used) { + ctx->cells[gnd_cell->name] = std::move(gnd_cell); + ctx->nets[gnd_net->name] = std::move(gnd_net); + } + // Vcc cell always inserted for now, as it may be needed during carry legalisation (TODO: trim later if actually + // never used?) + ctx->cells[vcc_cell->name] = std::move(vcc_cell); + ctx->nets[vcc_net->name] = std::move(vcc_net); + + for (auto dn : dead_nets) { + ctx->nets.erase(dn); + } +} + +static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) +{ + return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || + cell->type == ctx->id("$nextpnr_iobuf"); +} + +// Pack IO buffers +static void pack_io(Context *ctx) +{ + std::unordered_set packed_cells; + std::vector> new_cells; + log_info("Packing IOs..\n"); + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_nextpnr_iob(ctx, ci)) { + CellInfo *sb = nullptr; + if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + sb = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci); + + } else if (ci->type == ctx->id("$nextpnr_obuf")) { + sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_sb_io, ctx->id("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(ctx), sb->name.c_str(ctx), + ci->type.c_str(ctx), ci->name.c_str(ctx)); + NetInfo *net = sb->ports.at(ctx->id("PACKAGE_PIN")).net; + if (net != nullptr) { + ctx->nets.erase(net->name); + sb->ports.at(ctx->id("PACKAGE_PIN")).net = nullptr; + } + if (ci->type == ctx->id("$nextpnr_iobuf")) { + NetInfo *net2 = ci->ports.at(ctx->id("I")).net; + if (net2 != nullptr) { + ctx->nets.erase(net2->name); + } + } + } else { + // Create a SB_IO buffer + std::unique_ptr ice_cell = + create_ice_cell(ctx, ctx->id("SB_IO"), ci->name.str(ctx) + "$sb_io"); + nxio_to_sb(ctx, ci, ice_cell.get()); + new_cells.push_back(std::move(ice_cell)); + sb = new_cells.back().get(); + } + 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) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Return true if a port counts as "logic" for global promotion +static bool is_logic_port(BaseCtx *ctx, const PortRef &port) +{ + if (is_clock_port(ctx, port) || is_reset_port(ctx, port) || is_enable_port(ctx, port)) + return false; + return !is_sb_io(ctx, port.cell) && !is_sb_pll40(ctx, port.cell) && !is_sb_pll40_pad(ctx, port.cell) && + port.cell->type != ctx->id("SB_GB"); +} + +static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) +{ + std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); + std::unique_ptr gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name); + gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net; + PortRef pr; + pr.cell = gb.get(); + pr.port = ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER"); + net->users.push_back(pr); + + pr.cell = gb.get(); + pr.port = ctx->id("GLOBAL_BUFFER_OUTPUT"); + std::unique_ptr glbnet = std::unique_ptr(new NetInfo()); + glbnet->name = ctx->id(glb_name); + glbnet->driver = pr; + gb->ports[ctx->id("GLOBAL_BUFFER_OUTPUT")].net = glbnet.get(); + std::vector keep_users; + for (auto user : net->users) { + if (is_clock_port(ctx, user) || (is_reset && is_reset_port(ctx, user)) || + (is_cen && is_enable_port(ctx, user)) || (is_logic && is_logic_port(ctx, user))) { + user.cell->ports[user.port].net = glbnet.get(); + glbnet->users.push_back(user); + } else { + keep_users.push_back(user); + } + } + net->users = keep_users; + ctx->nets[glbnet->name] = std::move(glbnet); + ctx->cells[gb->name] = std::move(gb); +} + +// Simple global promoter (clock only) +static void promote_globals(Context *ctx) +{ + log_info("Promoting globals..\n"); + const int logic_fanout_thresh = 15; + const int enable_fanout_thresh = 5; + std::map clock_count, reset_count, cen_count, logic_count; + for (auto net : sorted(ctx->nets)) { + NetInfo *ni = net.second; + if (ni->driver.cell != nullptr && !ctx->isGlobalNet(ni)) { + clock_count[net.first] = 0; + reset_count[net.first] = 0; + cen_count[net.first] = 0; + + for (auto user : ni->users) { + if (is_clock_port(ctx, user)) + clock_count[net.first]++; + if (is_reset_port(ctx, user)) + reset_count[net.first]++; + if (is_enable_port(ctx, user)) + cen_count[net.first]++; + if (is_logic_port(ctx, user)) + logic_count[net.first]++; + } + } + } + int prom_globals = 0, prom_resets = 0, prom_cens = 0, prom_logics = 0; + int gbs_available = 8; + for (auto &cell : ctx->cells) + if (is_gbuf(ctx, cell.second.get())) + --gbs_available; + while (prom_globals < gbs_available) { + auto global_clock = std::max_element(clock_count.begin(), clock_count.end(), + [](const std::pair &a, const std::pair &b) { + return a.second < b.second; + }); + + auto global_reset = std::max_element(reset_count.begin(), reset_count.end(), + [](const std::pair &a, const std::pair &b) { + return a.second < b.second; + }); + auto global_cen = std::max_element(cen_count.begin(), cen_count.end(), + [](const std::pair &a, const std::pair &b) { + return a.second < b.second; + }); + auto global_logic = std::max_element(logic_count.begin(), logic_count.end(), + [](const std::pair &a, const std::pair &b) { + return a.second < b.second; + }); + if (global_clock->second == 0 && prom_logics < 4 && global_logic->second > logic_fanout_thresh && + (global_logic->second > global_cen->second || prom_cens >= 4) && + (global_logic->second > global_reset->second || prom_resets >= 4)) { + NetInfo *logicnet = ctx->nets[global_logic->first].get(); + insert_global(ctx, logicnet, false, false, true); + ++prom_globals; + ++prom_logics; + clock_count.erase(logicnet->name); + reset_count.erase(logicnet->name); + cen_count.erase(logicnet->name); + logic_count.erase(logicnet->name); + } else if (global_reset->second > global_clock->second && prom_resets < 4) { + NetInfo *rstnet = ctx->nets[global_reset->first].get(); + insert_global(ctx, rstnet, true, false, false); + ++prom_globals; + ++prom_resets; + clock_count.erase(rstnet->name); + reset_count.erase(rstnet->name); + cen_count.erase(rstnet->name); + logic_count.erase(rstnet->name); + } else if (global_cen->second > global_clock->second && prom_cens < 4 && + global_cen->second > enable_fanout_thresh) { + NetInfo *cennet = ctx->nets[global_cen->first].get(); + insert_global(ctx, cennet, false, true, false); + ++prom_globals; + ++prom_cens; + clock_count.erase(cennet->name); + reset_count.erase(cennet->name); + cen_count.erase(cennet->name); + logic_count.erase(cennet->name); + } else if (global_clock->second != 0) { + NetInfo *clknet = ctx->nets[global_clock->first].get(); + insert_global(ctx, clknet, false, false, false); + ++prom_globals; + clock_count.erase(clknet->name); + reset_count.erase(clknet->name); + cen_count.erase(clknet->name); + logic_count.erase(clknet->name); + } else { + break; + } + } +} + +// spliceLUT adds a pass-through LUT LC between the given cell's output port +// and either all users or only non_LUT users. +static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString portId, bool onlyNonLUTs) +{ + auto port = ci->ports[portId]; + + NPNR_ASSERT(port.net != nullptr); + + // Create pass-through LUT. + std::unique_ptr pt = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), + ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); + pt->params[ctx->id("LUT_INIT")] = "65280"; // output is always I3 + + // Create LUT output net. + std::unique_ptr out_net = std::unique_ptr(new NetInfo); + out_net->name = ctx->id(ci->name.str(ctx) + "$nextnr_" + portId.str(ctx) + "_lut_through_net"); + out_net->driver.cell = pt.get(); + out_net->driver.port = ctx->id("O"); + pt->ports.at(ctx->id("O")).net = out_net.get(); + + // New users of the original cell's port + std::vector new_users; + for (const auto &user : port.net->users) { + if (onlyNonLUTs && user.cell->type == ctx->id("ICESTORM_LC")) { + new_users.push_back(user); + continue; + } + // Rewrite pointer into net in user. + user.cell->ports[user.port].net = out_net.get(); + // Add user to net. + PortRef pr; + pr.cell = user.cell; + pr.port = user.port; + out_net->users.push_back(pr); + } + + // Add LUT to new users. + PortRef pr; + pr.cell = pt.get(); + pr.port = ctx->id("I3"); + new_users.push_back(pr); + pt->ports.at(ctx->id("I3")).net = port.net; + + // Replace users of the original net. + port.net->users = new_users; + + ctx->nets[out_net->name] = std::move(out_net); + return pt; +} + +// Pack special functions +static void pack_special(Context *ctx) +{ + log_info("Packing special functions..\n"); + + std::unordered_set packed_cells; + std::vector> new_cells; + + for (auto cell : sorted(ctx->cells)) { + CellInfo *ci = cell.second; + if (is_sb_lfosc(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); + packed_cells.insert(ci->name); + replace_port(ci, ctx->id("CLKLFEN"), packed.get(), ctx->id("CLKLFEN")); + replace_port(ci, ctx->id("CLKLFPU"), packed.get(), ctx->id("CLKLFPU")); + if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME + replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF_FABRIC")); + } else { + replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF")); + } + new_cells.push_back(std::move(packed)); + } else if (is_sb_hfosc(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_HFOSC"), ci->name.str(ctx) + "_OSC"); + packed_cells.insert(ci->name); + packed->params[ctx->id("CLKHF_DIV")] = str_or_default(ci->params, ctx->id("CLKHF_DIV"), "0b00"); + replace_port(ci, ctx->id("CLKHFEN"), packed.get(), ctx->id("CLKHFEN")); + replace_port(ci, ctx->id("CLKHFPU"), packed.get(), ctx->id("CLKHFPU")); + if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME + replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF_FABRIC")); + } else { + replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF")); + } + new_cells.push_back(std::move(packed)); + } else if (is_sb_spram(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_SPRAM"), ci->name.str(ctx) + "_RAM"); + packed_cells.insert(ci->name); + for (auto port : ci->ports) { + PortInfo &pi = port.second; + std::string newname = pi.name.str(ctx); + size_t bpos = newname.find('['); + if (bpos != std::string::npos) { + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); + } + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + new_cells.push_back(std::move(packed)); + } else if (is_sb_mac16(ctx, ci)) { + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP"); + packed_cells.insert(ci->name); + for (auto attr : ci->attrs) + packed->attrs[attr.first] = attr.second; + for (auto param : ci->params) + packed->params[param.first] = param.second; + + for (auto port : ci->ports) { + PortInfo &pi = port.second; + std::string newname = pi.name.str(ctx); + size_t bpos = newname.find('['); + if (bpos != std::string::npos) { + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); + } + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + new_cells.push_back(std::move(packed)); + } else if (is_sb_pll40(ctx, ci)) { + bool is_pad = is_sb_pll40_pad(ctx, ci); + bool is_core = !is_pad; + + std::unique_ptr packed = + create_ice_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); + packed->attrs[ctx->id("TYPE")] = ci->type.str(ctx); + packed_cells.insert(ci->name); + + for (auto attr : ci->attrs) + packed->attrs[attr.first] = attr.second; + for (auto param : ci->params) + packed->params[param.first] = param.second; + + auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")]; + packed->params[ctx->id("FEEDBACK_PATH")] = + feedback_path == "DELAY" + ? "0" + : feedback_path == "SIMPLE" ? "1" + : feedback_path == "PHASE_AND_DELAY" + ? "2" + : feedback_path == "EXTERNAL" ? "6" : feedback_path; + packed->params[ctx->id("PLLTYPE")] = std::to_string(sb_pll40_type(ctx, ci)); + + NetInfo *pad_packagepin_net = nullptr; + + for (auto port : ci->ports) { + PortInfo &pi = port.second; + std::string newname = pi.name.str(ctx); + size_t bpos = newname.find('['); + if (bpos != std::string::npos) { + newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); + } + if (pi.name == ctx->id("PLLOUTCOREA")) + newname = "PLLOUT_A"; + if (pi.name == ctx->id("PLLOUTCOREB")) + newname = "PLLOUT_B"; + if (pi.name == ctx->id("PLLOUTCORE")) + newname = "PLLOUT_A"; + + if (pi.name == ctx->id("PACKAGEPIN")) { + if (!is_pad) { + log_error(" PLL '%s' has a PACKAGEPIN but is not a PAD PLL", ci->name.c_str(ctx)); + } else { + // We drop this port and instead place the PLL adequately below. + pad_packagepin_net = port.second.net; + NPNR_ASSERT(pad_packagepin_net != nullptr); + continue; + } + } + if (pi.name == ctx->id("REFERENCECLK")) { + if (!is_core) + log_error(" PLL '%s' has a REFERENCECLK but is not a CORE PLL", ci->name.c_str(ctx)); + } + + replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); + } + + // If PLL is not constrained already, do that - we need this + // information to then constrain the LOCK LUT. + BelId pll_bel; + bool constrained = false; + if (packed->attrs.find(ctx->id("BEL")) == packed->attrs.end()) { + for (auto bel : ctx->getBels()) { + if (ctx->getBelType(bel) != id_ICESTORM_PLL) + continue; + + // A PAD PLL must have its' PACKAGEPIN on the SB_IO that's shared + // with PLLOUT_A. + if (is_pad) { + auto pll_sb_io_belpin = ctx->getIOBSharingPLLPin(bel, id_PLLOUT_A); + NPNR_ASSERT(pad_packagepin_net != nullptr); + auto pll_packagepin_driver = pad_packagepin_net->driver; + NPNR_ASSERT(pll_packagepin_driver.cell != nullptr); + if (pll_packagepin_driver.cell->type != ctx->id("SB_IO")) { + log_error(" PLL '%s' has a PACKAGEPIN driven by " + "an %s, should be directly connected to an input SB_IO\n", + ci->name.c_str(ctx), pll_packagepin_driver.cell->type.c_str(ctx)); + } + + auto packagepin_cell = pll_packagepin_driver.cell; + auto packagepin_bel_name = packagepin_cell->attrs.find(ctx->id("BEL")); + if (packagepin_bel_name == packagepin_cell->attrs.end()) { + log_error(" PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx), + packagepin_cell->name.c_str(ctx)); + } + auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second)); + if (pll_sb_io_belpin.bel != packagepin_bel) { + log_error(" PLL '%s' PACKAGEPIN is connected to pin %s, can only be pin %s\n", + ci->name.c_str(ctx), ctx->getBelPackagePin(packagepin_bel).c_str(), + ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str()); + } + if (pad_packagepin_net->users.size() != 1) { + log_error(" PLL '%s' clock input '%s' can only drive PLL\n", ci->name.c_str(ctx), + pad_packagepin_net->name.c_str(ctx)); + } + // Set an attribute about this PLL's PAD SB_IO. + packed->attrs[ctx->id("BEL_PAD_INPUT")] = packagepin_bel_name->second; + // Remove the connection from the SB_IO to the PLL. + packagepin_cell->ports.erase(pll_packagepin_driver.port); + } + + log_info(" constrained '%s' to %s\n", packed->name.c_str(ctx), ctx->getBelName(bel).c_str(ctx)); + packed->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); + pll_bel = bel; + constrained = true; + } + if (!constrained) { + log_error(" could not constrain '%s' to any PLL Bel\n", packed->name.c_str(ctx)); + } + } + + // Delete the original PACKAGEPIN net if needed. + if (pad_packagepin_net != nullptr) { + for (auto user : pad_packagepin_net->users) { + user.cell->ports.erase(user.port); + } + ctx->nets.erase(pad_packagepin_net->name); + pad_packagepin_net = nullptr; + } + + // The LOCK signal on iCE40 PLLs goes through the neigh_op_bnl_1 wire. + // In practice, this means the LOCK signal can only directly reach LUT + // inputs. + // If we have a net connected to LOCK, make sure it only drives LUTs. + auto port = packed->ports[ctx->id("LOCK")]; + if (port.net != nullptr) { + bool found_lut = false; + bool all_luts = true; + unsigned int lut_count = 0; + for (const auto &user : port.net->users) { + NPNR_ASSERT(user.cell != nullptr); + if (user.cell->type == ctx->id("ICESTORM_LC")) { + found_lut = true; + lut_count++; + } else { + all_luts = false; + } + } + + if (found_lut && all_luts) { + // Every user is a LUT, carry on now. + } else if (found_lut && !all_luts && lut_count < 8) { + // Strategy: create a pass-through LUT, move all non-LUT users behind it. + log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx)); + auto pt = spliceLUT(ctx, packed.get(), port.name, true); + new_cells.push_back(std::move(pt)); + } else { + // Strategy: create a pass-through LUT, move every user behind it. + log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx)); + auto pt = spliceLUT(ctx, packed.get(), port.name, false); + new_cells.push_back(std::move(pt)); + } + + // Find wire that will be driven by this port. + const auto pll_out_wire = ctx->getBelPinWire(pll_bel, port.name); + NPNR_ASSERT(pll_out_wire.index != -1); + + // Now, constrain all LUTs on the output of the signal to be at + // the correct Bel relative to the PLL Bel. + int x = ctx->chip_info->wire_data[pll_out_wire.index].x; + int y = ctx->chip_info->wire_data[pll_out_wire.index].y; + int z = 0; + for (const auto &user : port.net->users) { + NPNR_ASSERT(user.cell != nullptr); + NPNR_ASSERT(user.cell->type == ctx->id("ICESTORM_LC")); + + // TODO(q3k): handle when the Bel might be already the + // target of another constraint. + NPNR_ASSERT(z < 8); + auto target_bel = ctx->getBelByLocation(Loc(x, y, z++)); + auto target_bel_name = ctx->getBelName(target_bel).str(ctx); + user.cell->attrs[ctx->id("BEL")] = target_bel_name; + log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str()); + } + } + + new_cells.push_back(std::move(packed)); + } + } + + for (auto pcell : packed_cells) { + ctx->cells.erase(pcell); + } + for (auto &ncell : new_cells) { + ctx->cells[ncell->name] = std::move(ncell); + } +} + +// Main pack function +bool Arch::pack() +{ + Context *ctx = getCtx(); + try { + log_break(); + pack_constants(ctx); + promote_globals(ctx); + pack_io(ctx); + pack_lut_lutffs(ctx); + pack_nonlut_ffs(ctx); + pack_carries(ctx); + pack_ram(ctx); + pack_special(ctx); + ctx->assignArchInfo(); + constrain_chains(ctx); + ctx->assignArchInfo(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/pack_tests/.gitignore b/xc7/pack_tests/.gitignore new file mode 100644 index 00000000..749cb303 --- /dev/null +++ b/xc7/pack_tests/.gitignore @@ -0,0 +1,2 @@ +*.vcd +*_out.v diff --git a/xc7/pack_tests/ffmodes.v b/xc7/pack_tests/ffmodes.v new file mode 100644 index 00000000..c09ced74 --- /dev/null +++ b/xc7/pack_tests/ffmodes.v @@ -0,0 +1,43 @@ +module top(input clk, cen, rst, ina, inb, output reg outa, outb, outc, outd); + +reg temp0 = 1'b0, temp1 = 1'b0; +initial outa = 1'b0; +initial outb = 1'b0; +initial outc = 1'b0; +initial outd = 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 posedge 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/xc7/pack_tests/locals.v b/xc7/pack_tests/locals.v new file mode 100644 index 00000000..a1c5ea9f --- /dev/null +++ b/xc7/pack_tests/locals.v @@ -0,0 +1,27 @@ +module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); + +reg [31:0] temp = 0; + +integer i; + +always @(posedge clk) +begin + if (cen) begin + if (rst) begin + temp <= 0; + end else begin + temp[0] <= ina; + temp[1] <= inb; + for (i = 2; i < 32; i++) begin + temp[i] <= temp[(i + 3) % 32] ^ temp[(i + 30) % 32] ^ temp[(i + 4) % 16] ^ temp[(i + 2) % 32]; + end + end + end +end + +assign outa = temp[3]; +assign outb = temp[5]; +assign outc = temp[9]; +assign outd = temp[15]; + +endmodule diff --git a/xc7/pack_tests/place_constr.v b/xc7/pack_tests/place_constr.v new file mode 100644 index 00000000..f915a203 --- /dev/null +++ b/xc7/pack_tests/place_constr.v @@ -0,0 +1,54 @@ +module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); + +wire temp0, temp1; + +(* BEL="1_1_lc0" *) +SB_LUT4 #( + .LUT_INIT(2'b01) +) lut0 ( + .I3(), + .I2(), + .I1(), + .I0(ina), + .O(temp0) +); + + +(* BEL="1_3_lc0" *) +SB_LUT4 #( + .LUT_INIT(2'b01) +) lut1 ( + .I3(), + .I2(), + .I1(), + .I0(inb), + .O(temp1) +); + +(* BEL="1_1_lc0" *) +SB_DFF ff0 ( + .C(clk), + .D(temp1), + .Q(outa) +); + + +(* BEL="1_1_lc7" *) +SB_DFF ff1 ( + .C(clk), + .D(inb), + .Q(outb) +); + + +(* BEL="1_6_lc7" *) +SB_DFF ff2 ( + .C(clk), + .D(temp1), + .Q(outc) +); + + +assign outd = 1'b0; + +endmodule diff --git a/xc7/pack_tests/test.pcf b/xc7/pack_tests/test.pcf new file mode 100644 index 00000000..8cd488bf --- /dev/null +++ b/xc7/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/xc7/pack_tests/test.sh b/xc7/pack_tests/test.sh new file mode 100755 index 00000000..b36c01dc --- /dev/null +++ b/xc7/pack_tests/test.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -ex +NAME=${1%.v} +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;\ + rename chip 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 60 -seq 50 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter" ${NAME}_out.v diff --git a/xc7/pcf.cc b/xc7/pcf.cc new file mode 100644 index 00000000..d9fc4e68 --- /dev/null +++ b/xc7/pcf.cc @@ -0,0 +1,76 @@ +/* + * 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 "pcf.h" +#include +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Read a w + +// Apply PCF constraints to a pre-packing design +bool apply_pcf(Context *ctx, std::string filename, std::istream &in) +{ + try { + if (!in) + log_error("failed to open PCF file\n"); + 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 = ctx->cells.find(ctx->id(cell)); + if (fnd_cell == ctx->cells.end()) { + log_warning("unmatched pcf constraint %s\n", cell.c_str()); + } else { + BelId pin_bel = ctx->getPackagePinBel(pin); + if (pin_bel == BelId()) + log_error("package does not have a pin named %s\n", pin.c_str()); + fnd_cell->second->attrs[ctx->id("BEL")] = ctx->getBelName(pin_bel).str(ctx); + log_info("constrained '%s' to bel '%s'\n", cell.c_str(), + fnd_cell->second->attrs[ctx->id("BEL")].c_str()); + } + } else { + log_error("unsupported pcf command '%s'\n", cmd.c_str()); + } + } + ctx->settings.emplace(ctx->id("project/input/pcf"), filename); + return true; + } catch (log_execution_error_exception) { + return false; + } +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/pcf.h b/xc7/pcf.h new file mode 100644 index 00000000..ecc81e59 --- /dev/null +++ b/xc7/pcf.h @@ -0,0 +1,34 @@ +/* + * 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. + * + */ + +#ifndef PCF_H +#define PCF_H + +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +// Apply PCF constraints to a pre-packing design +bool apply_pcf(Context *ctx, std::string filename, std::istream &in); + +NEXTPNR_NAMESPACE_END + +#endif // ROUTE_H diff --git a/xc7/picorv32.proj b/xc7/picorv32.proj new file mode 100644 index 00000000..a8c83bd9 --- /dev/null +++ b/xc7/picorv32.proj @@ -0,0 +1,15 @@ +{ + "project": { + "version": "1", + "name": "picorv32", + "arch": { + "name": "ice40", + "type": "hx8k", + "package": "ct256" + }, + "input": { + "json": "picorv32.json", + "pcf": "icebreaker.pcf" + } + } +} diff --git a/xc7/picorv32.sh b/xc7/picorv32.sh new file mode 100755 index 00000000..d06786c5 --- /dev/null +++ b/xc7/picorv32.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -ex +rm -f picorv32.v +wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +yosys -p 'synth_ice40 -json picorv32.json -top top' picorv32.v picorv32_top.v +../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +icetime -d hx8k -t picorv32.asc diff --git a/xc7/picorv32_benchmark.py b/xc7/picorv32_benchmark.py new file mode 100755 index 00000000..a4ec581e --- /dev/null +++ b/xc7/picorv32_benchmark.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +import os, sys, threading +from os import path +import subprocess +import re + +num_runs = 8 + +if not path.exists("picorv32.json"): + subprocess.run(["wget", "https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v"], check=True) + subprocess.run(["yosys", "-q", "-p", "synth_ice40 -json picorv32.json -top top", "picorv32.v", "picorv32_top.v"], check=True) + +fmax = {} + +if not path.exists("picorv32_work"): + os.mkdir("picorv32_work") + +threads = [] + +for i in range(num_runs): + def runner(run): + ascfile = "picorv32_work/picorv32_s{}.asc".format(run) + if path.exists(ascfile): + os.remove(ascfile) + result = subprocess.run(["../nextpnr-ice40", "--hx8k", "--seed", str(run), "--json", "picorv32.json", "--asc", ascfile, "--freq", "70"], stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL) + if result.returncode != 0: + print("Run {} failed!".format(run)) + else: + icetime_res = subprocess.check_output(["icetime", "-d", "hx8k", ascfile]) + fmax_m = re.search(r'\(([0-9.]+) MHz\)', icetime_res.decode('utf-8')) + fmax[run] = float(fmax_m.group(1)) + threads.append(threading.Thread(target=runner, args=[i+1])) + +for t in threads: t.start() +for t in threads: t.join() + +fmax_min = min(fmax.values()) +fmax_max = max(fmax.values()) +fmax_avg = sum(fmax.values()) / len(fmax) + +print("{}/{} runs passed".format(len(fmax), num_runs)) +print("icetime: min = {} MHz, avg = {} MHz, max = {} MHz".format(fmax_min, fmax_avg, fmax_max)) diff --git a/xc7/picorv32_top.v b/xc7/picorv32_top.v new file mode 100644 index 00000000..27f0ef0c --- /dev/null +++ b/xc7/picorv32_top.v @@ -0,0 +1,31 @@ +module top ( + input clk, resetn, + output trap, + + output mem_valid, + output mem_instr, + input mem_ready, + + output [31:0] mem_addr, + output [31:0] mem_wdata, + output [ 3:0] mem_wstrb, + input [31:0] mem_rdata +); + picorv32 #( + .ENABLE_COUNTERS(0), + .TWO_STAGE_SHIFT(0), + .CATCH_MISALIGN(0), + .CATCH_ILLINSN(0) + ) cpu ( + .clk (clk ), + .resetn (resetn ), + .trap (trap ), + .mem_valid(mem_valid), + .mem_instr(mem_instr), + .mem_ready(mem_ready), + .mem_addr (mem_addr ), + .mem_wdata(mem_wdata), + .mem_wstrb(mem_wstrb), + .mem_rdata(mem_rdata) + ); +endmodule diff --git a/xc7/project.cc b/xc7/project.cc new file mode 100644 index 00000000..8ca10e36 --- /dev/null +++ b/xc7/project.cc @@ -0,0 +1,73 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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 "project.h" +#include +#include +#include "log.h" +#include "pcf.h" + +NEXTPNR_NAMESPACE_BEGIN + +void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path) +{ + root.put("project.arch.package", ctx->archArgs().package); + if (ctx->settings.find(ctx->id("project/input/pcf")) != ctx->settings.end()) { + std::string fn = ctx->settings[ctx->id("project/input/pcf")]; + root.put("project.input.pcf", make_relative(fn, path).string()); + } +} + +std::unique_ptr ProjectHandler::createContext(pt::ptree &root) +{ + ArchArgs chipArgs; + std::string arch_type = root.get("project.arch.type"); + if (arch_type == "lp384") { + chipArgs.type = ArchArgs::LP384; + } + if (arch_type == "lp1k") { + chipArgs.type = ArchArgs::LP1K; + } + if (arch_type == "lp8k") { + chipArgs.type = ArchArgs::LP8K; + } + if (arch_type == "hx1k") { + chipArgs.type = ArchArgs::HX1K; + } + if (arch_type == "hx8k") { + chipArgs.type = ArchArgs::HX8K; + } + if (arch_type == "up5k") { + chipArgs.type = ArchArgs::UP5K; + } + chipArgs.package = root.get("project.arch.package"); + + return std::unique_ptr(new Context(chipArgs)); +} + +void ProjectHandler::loadArch(Context *ctx, pt::ptree &root, std::string path) +{ + auto input = root.get_child("project").get_child("input"); + boost::filesystem::path pcf = boost::filesystem::path(path) / input.get("pcf"); + std::ifstream f(pcf.string()); + if (!apply_pcf(ctx, input.get("pcf"), f)) + log_error("Loading PCF failed.\n"); +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/resource/chipdb.rc b/xc7/resource/chipdb.rc new file mode 100644 index 00000000..a6f2dbe8 --- /dev/null +++ b/xc7/resource/chipdb.rc @@ -0,0 +1,6 @@ +#include "resource.h" + +IDR_CHIPDB_384 BINARYFILE "..\chipdbs\chipdb-384.bin" +IDR_CHIPDB_1K BINARYFILE "..\chipdbs\chipdb-1k.bin" +IDR_CHIPDB_5K BINARYFILE "..\chipdbs\chipdb-5k.bin" +IDR_CHIPDB_8K BINARYFILE "..\chipdbs\chipdb-8k.bin" diff --git a/xc7/resource/embed.cc b/xc7/resource/embed.cc new file mode 100644 index 00000000..74f2eee9 --- /dev/null +++ b/xc7/resource/embed.cc @@ -0,0 +1,30 @@ +#include +#include +#include "nextpnr.h" +#include "resource.h" + +NEXTPNR_NAMESPACE_BEGIN + +const char *chipdb_blob_384; +const char *chipdb_blob_1k; +const char *chipdb_blob_5k; +const char *chipdb_blob_8k; + +const char *LoadFileInResource(int name, int type, DWORD &size) +{ + HMODULE handle = ::GetModuleHandle(NULL); + HRSRC rc = ::FindResource(handle, MAKEINTRESOURCE(name), MAKEINTRESOURCE(type)); + HGLOBAL rcData = ::LoadResource(handle, rc); + size = ::SizeofResource(handle, rc); + return static_cast(::LockResource(rcData)); +} +void load_chipdb() +{ + DWORD size = 0; + chipdb_blob_384 = LoadFileInResource(IDR_CHIPDB_384, BINARYFILE, size); + chipdb_blob_1k = LoadFileInResource(IDR_CHIPDB_1K, BINARYFILE, size); + chipdb_blob_5k = LoadFileInResource(IDR_CHIPDB_5K, BINARYFILE, size); + chipdb_blob_8k = LoadFileInResource(IDR_CHIPDB_8K, BINARYFILE, size); +} + +NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/xc7/resource/resource.h b/xc7/resource/resource.h new file mode 100644 index 00000000..46997ae5 --- /dev/null +++ b/xc7/resource/resource.h @@ -0,0 +1,5 @@ +#define BINARYFILE 256 +#define IDR_CHIPDB_384 101 +#define IDR_CHIPDB_1K 102 +#define IDR_CHIPDB_5K 103 +#define IDR_CHIPDB_8K 104 diff --git a/xc7/tmfuzz.py b/xc7/tmfuzz.py new file mode 100644 index 00000000..4ec2a546 --- /dev/null +++ b/xc7/tmfuzz.py @@ -0,0 +1,357 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# ../nextpnr-ice40 --hx8k --tmfuzz > tmfuzz_hx8k.txt +# ../nextpnr-ice40 --lp8k --tmfuzz > tmfuzz_lp8k.txt +# ../nextpnr-ice40 --up5k --tmfuzz > tmfuzz_up5k.txt + +import numpy as np +import matplotlib.pyplot as plt +from collections import defaultdict + +device = "hx8k" +# device = "lp8k" +# device = "up5k" + +sel_src_type = "LUTFF_OUT" +sel_dst_type = "LUTFF_IN_LUT" + +#%% Read fuzz data + +src_dst_pairs = defaultdict(lambda: 0) + +delay_data = list() +all_delay_data = list() + +delay_map_sum = np.zeros((41, 41)) +delay_map_sum2 = np.zeros((41, 41)) +delay_map_count = np.zeros((41, 41)) + +same_tile_delays = list() +neighbour_tile_delays = list() + +type_delta_data = dict() + +with open("tmfuzz_%s.txt" % device, "r") as f: + for line in f: + line = line.split() + + if line[0] == "dst": + dst_xy = (int(line[1]), int(line[2])) + dst_type = line[3] + dst_wire = line[4] + + src_xy = (int(line[1]), int(line[2])) + src_type = line[3] + src_wire = line[4] + + delay = int(line[5]) + estdelay = int(line[6]) + + all_delay_data.append((delay, estdelay)) + + src_dst_pairs[src_type, dst_type] += 1 + + dx = dst_xy[0] - src_xy[0] + dy = dst_xy[1] - src_xy[1] + + if src_type == sel_src_type and dst_type == sel_dst_type: + if dx == 0 and dy == 0: + same_tile_delays.append(delay) + + elif abs(dx) <= 1 and abs(dy) <= 1: + neighbour_tile_delays.append(delay) + + else: + delay_data.append((delay, estdelay, dx, dy, 0, 0, 0)) + + relx = 20 + dst_xy[0] - src_xy[0] + rely = 20 + dst_xy[1] - src_xy[1] + + if (0 <= relx <= 40) and (0 <= rely <= 40): + delay_map_sum[relx, rely] += delay + delay_map_sum2[relx, rely] += delay*delay + delay_map_count[relx, rely] += 1 + + if dst_type == sel_dst_type: + if src_type not in type_delta_data: + type_delta_data[src_type] = list() + + type_delta_data[src_type].append((dx, dy, delay)) + +delay_data = np.array(delay_data) +all_delay_data = np.array(all_delay_data) +max_delay = np.max(delay_data[:, 0:2]) + +mean_same_tile_delays = np.mean(neighbour_tile_delays) +mean_neighbour_tile_delays = np.mean(neighbour_tile_delays) + +print("Avg same tile delay: %.2f (%.2f std, N=%d)" % \ + (mean_same_tile_delays, np.std(same_tile_delays), len(same_tile_delays))) +print("Avg neighbour tile delay: %.2f (%.2f std, N=%d)" % \ + (mean_neighbour_tile_delays, np.std(neighbour_tile_delays), len(neighbour_tile_delays))) + +#%% Apply simple low-weight bluring to fill gaps + +for i in range(0): + neigh_sum = np.zeros((41, 41)) + neigh_sum2 = np.zeros((41, 41)) + neigh_count = np.zeros((41, 41)) + + for x in range(41): + for y in range(41): + for p in range(-1, 2): + for q in range(-1, 2): + if p == 0 and q == 0: + continue + if 0 <= (x+p) <= 40: + if 0 <= (y+q) <= 40: + neigh_sum[x, y] += delay_map_sum[x+p, y+q] + neigh_sum2[x, y] += delay_map_sum2[x+p, y+q] + neigh_count[x, y] += delay_map_count[x+p, y+q] + + delay_map_sum += 0.1 * neigh_sum + delay_map_sum2 += 0.1 * neigh_sum2 + delay_map_count += 0.1 * neigh_count + +delay_map = delay_map_sum / delay_map_count +delay_map_std = np.sqrt(delay_map_count*delay_map_sum2 - delay_map_sum**2) / delay_map_count + +#%% Print src-dst-pair summary + +print("Src-Dst-Type pair summary:") +for cnt, src, dst in sorted([(v, k[0], k[1]) for k, v in src_dst_pairs.items()]): + print("%20s %20s %5d%s" % (src, dst, cnt, " *" if src == sel_src_type and dst == sel_dst_type else "")) +print() + +#%% Plot estimate vs actual delay + +plt.figure(figsize=(8, 3)) +plt.title("Estimate vs Actual Delay") +plt.plot(all_delay_data[:, 0], all_delay_data[:, 1], ".") +plt.plot(delay_data[:, 0], delay_data[:, 1], ".") +plt.plot([0, max_delay], [0, max_delay], "k") +plt.ylabel("Estimated Delay") +plt.xlabel("Actual Delay") +plt.grid() +plt.show() + +#%% Plot delay heatmap and std dev heatmap + +plt.figure(figsize=(9, 3)) +plt.subplot(121) +plt.title("Actual Delay Map") +plt.imshow(delay_map) +plt.colorbar() +plt.subplot(122) +plt.title("Standard Deviation") +plt.imshow(delay_map_std) +plt.colorbar() +plt.show() + +#%% Generate Model #0 + +def nonlinearPreprocessor0(dx, dy): + dx, dy = abs(dx), abs(dy) + values = [1.0] + values.append(dx + dy) + return np.array(values) + +A = np.zeros((41*41, len(nonlinearPreprocessor0(0, 0)))) +b = np.zeros(41*41) + +index = 0 +for x in range(41): + for y in range(41): + if delay_map_count[x, y] > 0: + A[index, :] = nonlinearPreprocessor0(x-20, y-20) + b[index] = delay_map[x, y] + index += 1 + +model0_params, _, _, _ = np.linalg.lstsq(A, b) +print("Model #0 parameters:", model0_params) + +model0_map = np.zeros((41, 41)) +for x in range(41): + for y in range(41): + v = np.dot(model0_params, nonlinearPreprocessor0(x-20, y-20)) + model0_map[x, y] = v + +plt.figure(figsize=(9, 3)) +plt.subplot(121) +plt.title("Model #0 Delay Map") +plt.imshow(model0_map) +plt.colorbar() +plt.subplot(122) +plt.title("Model #0 Error Map") +plt.imshow(model0_map - delay_map) +plt.colorbar() +plt.show() + +for i in range(delay_data.shape[0]): + dx = delay_data[i, 2] + dy = delay_data[i, 3] + delay_data[i, 4] = np.dot(model0_params, nonlinearPreprocessor0(dx, dy)) + +plt.figure(figsize=(8, 3)) +plt.title("Model #0 vs Actual Delay") +plt.plot(delay_data[:, 0], delay_data[:, 4], ".") +plt.plot(delay_map.flat, model0_map.flat, ".") +plt.plot([0, max_delay], [0, max_delay], "k") +plt.ylabel("Model #0 Delay") +plt.xlabel("Actual Delay") +plt.grid() +plt.show() + +print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model0_map)**2))) +print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 4])**2))) +print() + +#%% Generate Model #1 + +def nonlinearPreprocessor1(dx, dy): + dx, dy = abs(dx), abs(dy) + values = [1.0] + values.append(dx + dy) # 1-norm + values.append((dx**2 + dy**2)**(1/2)) # 2-norm + values.append((dx**3 + dy**3)**(1/3)) # 3-norm + return np.array(values) + +A = np.zeros((41*41, len(nonlinearPreprocessor1(0, 0)))) +b = np.zeros(41*41) + +index = 0 +for x in range(41): + for y in range(41): + if delay_map_count[x, y] > 0: + A[index, :] = nonlinearPreprocessor1(x-20, y-20) + b[index] = delay_map[x, y] + index += 1 + +model1_params, _, _, _ = np.linalg.lstsq(A, b) +print("Model #1 parameters:", model1_params) + +model1_map = np.zeros((41, 41)) +for x in range(41): + for y in range(41): + v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20)) + model1_map[x, y] = v + +plt.figure(figsize=(9, 3)) +plt.subplot(121) +plt.title("Model #1 Delay Map") +plt.imshow(model1_map) +plt.colorbar() +plt.subplot(122) +plt.title("Model #1 Error Map") +plt.imshow(model1_map - delay_map) +plt.colorbar() +plt.show() + +for i in range(delay_data.shape[0]): + dx = delay_data[i, 2] + dy = delay_data[i, 3] + delay_data[i, 5] = np.dot(model1_params, nonlinearPreprocessor1(dx, dy)) + +plt.figure(figsize=(8, 3)) +plt.title("Model #1 vs Actual Delay") +plt.plot(delay_data[:, 0], delay_data[:, 5], ".") +plt.plot(delay_map.flat, model1_map.flat, ".") +plt.plot([0, max_delay], [0, max_delay], "k") +plt.ylabel("Model #1 Delay") +plt.xlabel("Actual Delay") +plt.grid() +plt.show() + +print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model1_map)**2))) +print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 5])**2))) +print() + +#%% Generate Model #2 + +def nonlinearPreprocessor2(v): + return np.array([1, v, np.sqrt(v)]) + +A = np.zeros((41*41, len(nonlinearPreprocessor2(0)))) +b = np.zeros(41*41) + +index = 0 +for x in range(41): + for y in range(41): + if delay_map_count[x, y] > 0: + A[index, :] = nonlinearPreprocessor2(model1_map[x, y]) + b[index] = delay_map[x, y] + index += 1 + +model2_params, _, _, _ = np.linalg.lstsq(A, b) +print("Model #2 parameters:", model2_params) + +model2_map = np.zeros((41, 41)) +for x in range(41): + for y in range(41): + v = np.dot(model1_params, nonlinearPreprocessor1(x-20, y-20)) + v = np.dot(model2_params, nonlinearPreprocessor2(v)) + model2_map[x, y] = v + +plt.figure(figsize=(9, 3)) +plt.subplot(121) +plt.title("Model #2 Delay Map") +plt.imshow(model2_map) +plt.colorbar() +plt.subplot(122) +plt.title("Model #2 Error Map") +plt.imshow(model2_map - delay_map) +plt.colorbar() +plt.show() + +for i in range(delay_data.shape[0]): + dx = delay_data[i, 2] + dy = delay_data[i, 3] + delay_data[i, 6] = np.dot(model2_params, nonlinearPreprocessor2(delay_data[i, 5])) + +plt.figure(figsize=(8, 3)) +plt.title("Model #2 vs Actual Delay") +plt.plot(delay_data[:, 0], delay_data[:, 6], ".") +plt.plot(delay_map.flat, model2_map.flat, ".") +plt.plot([0, max_delay], [0, max_delay], "k") +plt.ylabel("Model #2 Delay") +plt.xlabel("Actual Delay") +plt.grid() +plt.show() + +print("In-sample RMS error: %f" % np.sqrt(np.nanmean((delay_map - model2_map)**2))) +print("Out-of-sample RMS error: %f" % np.sqrt(np.nanmean((delay_data[:, 0] - delay_data[:, 6])**2))) +print() + +#%% Generate deltas for different source net types + +type_deltas = dict() + +print("Delay deltas for different src types:") +for src_type in sorted(type_delta_data.keys()): + deltas = list() + + for dx, dy, delay in type_delta_data[src_type]: + dx = abs(dx) + dy = abs(dy) + + if dx > 1 or dy > 1: + est = model0_params[0] + model0_params[1] * (dx + dy) + else: + est = mean_neighbour_tile_delays + deltas.append(delay - est) + + print("%15s: %8.2f (std %6.2f)" % (\ + src_type, np.mean(deltas), np.std(deltas))) + + type_deltas[src_type] = np.mean(deltas) + +#%% Print C defs of model parameters + +print("--snip--") +print("%d, %d, %d," % (mean_neighbour_tile_delays, 128 * model0_params[0], 128 * model0_params[1])) +print("%d, %d, %d, %d," % (128 * model1_params[0], 128 * model1_params[1], 128 * model1_params[2], 128 * model1_params[3])) +print("%d, %d, %d," % (128 * model2_params[0], 128 * model2_params[1], 128 * model2_params[2])) +print("%d, %d, %d, %d" % (type_deltas["LOCAL"], type_deltas["LUTFF_IN"], \ + (type_deltas["SP4_H"] + type_deltas["SP4_V"]) / 2, + (type_deltas["SP12_H"] + type_deltas["SP12_V"]) / 2)) +print("--snap--") From a0d72a6f8e9d4c1d2cefc4fc0e2bad25b7f5cf14 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 14:37:56 -0700 Subject: [PATCH 002/174] Add xc7 to supported arches --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c222d71..67029d5b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_TESTS "Build GUI" OFF) # List of families to build -set(FAMILIES generic ice40 ecp5) +set(FAMILIES generic ice40 ecp5 xc7) set(ARCH "" CACHE STRING "Architecture family for nextpnr build") set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) From 6425032ec4def444f8538c6c92eab13660ab13e0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 15:00:31 -0700 Subject: [PATCH 003/174] Rip out ice40 stuff, put xc7z020 in --- xc7/arch.cc | 126 +----- xc7/arch.h | 11 +- xc7/bitstream.cc | 999 ----------------------------------------------- xc7/bitstream.h | 34 -- xc7/delay.cc | 128 +----- xc7/family.cmake | 84 ---- xc7/main.cc | 125 ++---- xc7/project.cc | 19 +- 8 files changed, 59 insertions(+), 1467 deletions(-) delete mode 100644 xc7/bitstream.cc delete mode 100644 xc7/bitstream.h diff --git a/xc7/arch.cc b/xc7/arch.cc index 7e2dd7f7..9b739ba4 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -41,105 +41,42 @@ void IdString::initialize_arch(const BaseCtx *ctx) // ----------------------------------------------------------------------- -static const ChipInfoPOD *get_chip_info(const RelPtr *ptr) { return ptr->get(); } - -#if defined(_MSC_VER) -void load_chipdb(); -#endif - Arch::Arch(ArchArgs args) : args(args) { -#if defined(_MSC_VER) - load_chipdb(); -#endif - -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - fast_part = true; - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + if (args.type == ArchArgs::XC7Z020) { + //chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); } else { - log_error("Unsupported iCE40 chip type.\n"); + log_error("Unsupported XC7 chip type.\n"); } -#else - if (args.type == ArchArgs::LP384) { - fast_part = false; - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_384)); - } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { - fast_part = args.type == ArchArgs::HX1K; - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); - } else if (args.type == ArchArgs::UP5K) { - fast_part = false; - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_5k)); - } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { - fast_part = args.type == ArchArgs::HX8K; - chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_8k)); - } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#endif - package_info = nullptr; - for (int i = 0; i < chip_info->num_packages; i++) { - if (chip_info->packages_data[i].name.get() == 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_carry.resize(chip_info->num_bels); - bel_to_cell.resize(chip_info->num_bels); - wire_to_net.resize(chip_info->num_wires); - pip_to_net.resize(chip_info->num_pips); - switches_locked.resize(chip_info->num_switches); +// package_info = nullptr; +// for (int i = 0; i < chip_info->num_packages; i++) { +// if (chip_info->packages_data[i].name.get() == args.package) { +// package_info = &(chip_info->packages_data[i]); +// break; +// } +// } +// if (package_info == nullptr) +// log_error("Unsupported package '%s'.\n", args.package.c_str()); } // ----------------------------------------------------------------------- std::string Arch::getChipName() const { -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - return "Lattice LP1K"; + if (args.type == ArchArgs::XC7Z020) { + return "XC7Z020"; } else { - log_error("Unsupported iCE40 chip type.\n"); + log_error("Unsupported XC7 chip type.\n"); } -#else - if (args.type == ArchArgs::LP384) { - return "Lattice LP384"; - } else if (args.type == ArchArgs::LP1K) { - return "Lattice LP1K"; - } else if (args.type == ArchArgs::HX1K) { - return "Lattice HX1K"; - } else if (args.type == ArchArgs::UP5K) { - return "Lattice UP5K"; - } else if (args.type == ArchArgs::LP8K) { - return "Lattice LP8K"; - } else if (args.type == ArchArgs::HX8K) { - return "Lattice HX8K"; - } else { - log_error("Unknown chip\n"); - } -#endif } // ----------------------------------------------------------------------- IdString Arch::archArgsToId(ArchArgs args) const { - if (args.type == ArchArgs::LP384) - return id("lp384"); - if (args.type == ArchArgs::LP1K) - return id("lp1k"); - if (args.type == ArchArgs::HX1K) - return id("hx1k"); - if (args.type == ArchArgs::UP5K) - return id("up5k"); - if (args.type == ArchArgs::LP8K) - return id("lp8k"); - if (args.type == ArchArgs::HX8K) - return id("hx8k"); + if (args.type == ArchArgs::XC7Z020) + return id("xc7z020"); return IdString(); } @@ -531,35 +468,6 @@ std::vector Arch::getGroupGroups(GroupId group) const bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { - const auto &driver = net_info->driver; - if (driver.port == id_COUT && sink.port == id_CIN) { - auto driver_loc = getBelLocation(driver.cell->bel); - auto sink_loc = getBelLocation(sink.cell->bel); - if (driver_loc.y == sink_loc.y) - budget = 0; - else - switch (args.type) { -#ifndef ICE40_HX1K_ONLY - case ArchArgs::HX8K: -#endif - case ArchArgs::HX1K: - budget = 190; - break; -#ifndef ICE40_HX1K_ONLY - case ArchArgs::LP384: - case ArchArgs::LP1K: - case ArchArgs::LP8K: - budget = 290; - break; - case ArchArgs::UP5K: - budget = 560; - break; -#endif - default: - log_error("Unsupported iCE40 chip type.\n"); - } - return true; - } return false; } diff --git a/xc7/arch.h b/xc7/arch.h index 8fd1af23..d92ff0c1 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -378,12 +378,7 @@ struct ArchArgs enum ArchArgsTypes { NONE, - LP384, - LP1K, - LP8K, - HX1K, - HX8K, - UP5K + XC7Z020 } type = NONE; std::string package; }; @@ -410,7 +405,7 @@ struct Arch : BaseCtx std::string getChipName() const; - IdString archId() const { return id("ice40"); } + IdString archId() const { return id("xc7"); } ArchArgs archArgs() const { return args; } IdString archArgsToId(ArchArgs args) const; @@ -836,6 +831,6 @@ struct Arch : BaseCtx float placer_constraintWeight = 10; }; -void ice40DelayFuzzerMain(Context *ctx); +//void ice40DelayFuzzerMain(Context *ctx); NEXTPNR_NAMESPACE_END diff --git a/xc7/bitstream.cc b/xc7/bitstream.cc deleted file mode 100644 index ee276e49..00000000 --- a/xc7/bitstream.cc +++ /dev/null @@ -1,999 +0,0 @@ -/* - * nextpnr -- Next Generation Place and Route - * - * Copyright (C) 2018 Clifford Wolf - * Copyright (C) 2018 David Shah - * Copyright (C) 2018 Serge Bazanski - * - * 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 "bitstream.h" -#include -#include -#include "cells.h" -#include "log.h" - -NEXTPNR_NAMESPACE_BEGIN - -inline TileType tile_at(const Context *ctx, int x, int y) -{ - return ctx->chip_info->tile_grid[y * ctx->chip_info->width + x]; -} - -const ConfigEntryPOD &find_config(const TileInfoPOD &tile, const std::string &name) -{ - for (int i = 0; i < tile.num_config_entries; i++) { - if (std::string(tile.entries[i].name.get()) == name) { - return tile.entries[i]; - } - } - NPNR_ASSERT_FALSE_STR("unable to find config bit " + name); -} - -std::tuple get_ieren(const BitstreamInfoPOD &bi, int8_t x, int8_t y, int8_t z) -{ - for (int i = 0; i < bi.num_ierens; i++) { - auto ie = bi.ierens[i]; - if (ie.iox == x && ie.ioy == y && ie.ioz == z) { - return std::make_tuple(ie.ierx, ie.iery, ie.ierz); - } - } - // No pin at this location - return std::make_tuple(-1, -1, -1); -}; - -bool get_config(const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, - int index = -1) -{ - const ConfigEntryPOD &cfg = find_config(ti, name); - if (index == -1) { - for (int i = 0; i < cfg.num_bits; i++) { - return tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); - } - } else { - return tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); - } - return false; -} - -void set_config(const TileInfoPOD &ti, std::vector> &tile_cfg, const std::string &name, bool value, - int index = -1) -{ - const ConfigEntryPOD &cfg = find_config(ti, name); - if (index == -1) { - for (int i = 0; i < cfg.num_bits; i++) { - int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col); - if (cbit && !value) - log_error("clearing already set config bit %s\n", name.c_str()); - cbit = value; - } - } else { - int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col); - cbit = value; - if (cbit && !value) - log_error("clearing already set config bit %s[%d]\n", name.c_str(), index); - } -} - -// Set an IE_{EN,REN} logical bit in a tile config. Logical means enabled. -// On {HX,LP}1K devices these bits are active low, so we need to invert them. -void set_ie_bit_logical(const Context *ctx, const TileInfoPOD &ti, std::vector> &tile_cfg, - const std::string &name, bool value) -{ - if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { - set_config(ti, tile_cfg, name, !value); - } else { - set_config(ti, tile_cfg, name, value); - } -} - -int get_param_or_def(const CellInfo *cell, const IdString param, int defval = 0) -{ - auto found = cell->params.find(param); - if (found != cell->params.end()) - return std::stoi(found->second); - else - return defval; -} - -std::string get_param_str_or_def(const CellInfo *cell, const IdString param, std::string defval = "") -{ - auto found = cell->params.find(param); - if (found != cell->params.end()) - return found->second; - else - return defval; -} - -char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } - -static const BelConfigPOD &get_ec_config(const ChipInfoPOD *chip, BelId bel) -{ - for (int i = 0; i < chip->num_belcfgs; i++) { - if (chip->bel_config[i].bel_index == bel.index) - return chip->bel_config[i]; - } - NPNR_ASSERT_FALSE("failed to find bel config"); -} - -typedef std::vector>>> chipconfig_t; - -static void set_ec_cbit(chipconfig_t &config, const Context *ctx, const BelConfigPOD &cell_cbits, std::string name, - bool value, std::string prefix) -{ - const ChipInfoPOD *chip = ctx->chip_info; - - for (int i = 0; i < cell_cbits.num_entries; i++) { - const auto &cbit = cell_cbits.entries[i]; - if (cbit.entry_name.get() == name) { - const auto &ti = chip->bits_info->tiles_nonrouting[tile_at(ctx, cbit.x, cbit.y)]; - set_config(ti, config.at(cbit.y).at(cbit.x), prefix + cbit.cbit_name.get(), value); - return; - } - } - NPNR_ASSERT_FALSE_STR("failed to config extra cell config bit " + name); -} - -void configure_extra_cell(chipconfig_t &config, const Context *ctx, CellInfo *cell, - const std::vector> ¶ms, bool string_style, std::string prefix) -{ - const ChipInfoPOD *chip = ctx->chip_info; - const auto &bc = get_ec_config(chip, cell->bel); - for (auto p : params) { - std::vector value; - if (string_style) { - // Lattice's weird string style params, not sure if - // prefixes other than 0b should be supported, only 0b features in docs - std::string raw = get_param_str_or_def(cell, ctx->id(p.first), "0b0"); - assert(raw.substr(0, 2) == "0b"); - raw = raw.substr(2); - value.resize(raw.length()); - for (int i = 0; i < (int)raw.length(); i++) { - if (raw[i] == '1') { - value[(raw.length() - 1) - i] = 1; - } else { - assert(raw[i] == '0'); - value[(raw.length() - 1) - i] = 0; - } - } - } else { - int ival = get_param_or_def(cell, ctx->id(p.first), 0); - - for (int i = 0; i < p.second; i++) - value.push_back((ival >> i) & 0x1); - } - - value.resize(p.second); - if (p.second == 1) { - set_ec_cbit(config, ctx, bc, p.first, value.at(0), prefix); - } else { - for (int i = 0; i < p.second; i++) { - set_ec_cbit(config, ctx, bc, p.first + "_" + std::to_string(i), value.at(i), prefix); - } - } - } -} - -std::string tagTileType(TileType &tile) -{ - if (tile == TILE_NONE) - return ""; - switch (tile) { - case TILE_LOGIC: - return ".logic_tile"; - break; - case TILE_IO: - return ".io_tile"; - break; - case TILE_RAMB: - return ".ramb_tile"; - break; - case TILE_RAMT: - return ".ramt_tile"; - break; - case TILE_DSP0: - return ".dsp0_tile"; - break; - case TILE_DSP1: - return ".dsp1_tile"; - break; - case TILE_DSP2: - return ".dsp2_tile"; - break; - case TILE_DSP3: - return ".dsp3_tile"; - break; - case TILE_IPCON: - return ".ipcon_tile"; - break; - default: - NPNR_ASSERT(false); - } -} - -static BelPin get_one_bel_pin(const Context *ctx, WireId wire) -{ - auto pins = ctx->getWireBelPins(wire); - NPNR_ASSERT(pins.begin() != pins.end()); - return *pins.begin(); -} - -// Permute LUT init value given map (LUT input -> ext input) -unsigned permute_lut(unsigned orig_init, const std::unordered_map &input_permute) -{ - unsigned new_init = 0; - - for (int i = 0; i < 16; i++) { - int permute_address = 0; - for (int j = 0; j < 4; j++) { - if ((i >> j) & 0x1) - permute_address |= (1 << input_permute.at(j)); - } - if ((orig_init >> i) & 0x1) { - new_init |= (1 << permute_address); - } - } - - return new_init; -} - -void write_asc(const Context *ctx, std::ostream &out) -{ - - static const std::vector lut_perm = { - 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, - }; - - // [y][x][row][col] - const ChipInfoPOD &ci = *ctx->chip_info; - const BitstreamInfoPOD &bi = *ci.bits_info; - chipconfig_t config; - config.resize(ci.height); - for (int y = 0; y < ci.height; y++) { - config.at(y).resize(ci.width); - for (int x = 0; x < ci.width; x++) { - TileType tile = tile_at(ctx, x, y); - int rows = bi.tiles_nonrouting[tile].rows; - int cols = bi.tiles_nonrouting[tile].cols; - config.at(y).at(x).resize(rows, std::vector(cols)); - } - } - out << ".comment from next-pnr" << std::endl; - - switch (ctx->args.type) { - case ArchArgs::LP384: - out << ".device 384" << std::endl; - break; - case ArchArgs::HX1K: - case ArchArgs::LP1K: - out << ".device 1k" << std::endl; - break; - case ArchArgs::HX8K: - case ArchArgs::LP8K: - out << ".device 8k" << std::endl; - break; - case ArchArgs::UP5K: - out << ".device 5k" << std::endl; - break; - default: - NPNR_ASSERT_FALSE("unsupported device type\n"); - } - // Set pips - for (auto pip : ctx->getPips()) { - if (ctx->pip_to_net[pip.index] != nullptr) { - const PipInfoPOD &pi = ci.pip_data[pip.index]; - const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; - int sw_bel_idx = swi.bel; - if (sw_bel_idx >= 0) { - const BelInfoPOD &beli = ci.bel_data[sw_bel_idx]; - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; - BelId sw_bel; - sw_bel.index = sw_bel_idx; - NPNR_ASSERT(ctx->getBelType(sw_bel) == id_ICESTORM_LC); - - if (ci.wire_data[ctx->getPipDstWire(pip).index].type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT) - continue; // Permutation pips - BelPin output = get_one_bel_pin(ctx, ctx->getPipDstWire(pip)); - NPNR_ASSERT(output.bel == sw_bel && output.pin == id_O); - unsigned lut_init; - - WireId permWire; - for (auto permPip : ctx->getPipsUphill(ctx->getPipSrcWire(pip))) { - if (ctx->getBoundPipNet(permPip) != nullptr) { - permWire = ctx->getPipSrcWire(permPip); - } - } - NPNR_ASSERT(permWire != WireId()); - std::string dName = ci.wire_data[permWire.index].name.get(); - - switch (dName.back()) { - case '0': - lut_init = 2; - break; - case '1': - lut_init = 4; - break; - case '2': - lut_init = 16; - break; - case '3': - lut_init = 256; - break; - default: - NPNR_ASSERT_FALSE("bad feedthru LUT input"); - } - std::vector lc(20, false); - for (int i = 0; i < 16; i++) { - if ((lut_init >> i) & 0x1) - lc.at(lut_perm.at(i)) = true; - } - - for (int i = 0; i < 20; i++) - set_config(ti, config.at(beli.y).at(beli.x), "LC_" + std::to_string(beli.z), lc.at(i), i); - } else { - for (int i = 0; i < swi.num_bits; i++) { - bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; - int8_t &cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); - if (bool(cbit) != 0) - NPNR_ASSERT(false); - cbit = val; - } - } - } - } - - std::unordered_set sb_io_used_by_pll; - std::unordered_set sb_io_used_by_io; - - // Set logic cell config - for (auto &cell : ctx->cells) { - - BelId bel = cell.second.get()->bel; - if (bel == BelId()) { - std::cout << "Found unplaced cell " << cell.first.str(ctx) << " while generating bitstream!" << std::endl; - continue; - } - if (cell.second->type == ctx->id("ICESTORM_LC")) { - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; - unsigned lut_init = get_param_or_def(cell.second.get(), ctx->id("LUT_INIT")); - bool neg_clk = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK")); - bool dff_enable = get_param_or_def(cell.second.get(), ctx->id("DFF_ENABLE")); - bool async_sr = get_param_or_def(cell.second.get(), ctx->id("ASYNC_SR")); - bool set_noreset = get_param_or_def(cell.second.get(), ctx->id("SET_NORESET")); - bool carry_enable = get_param_or_def(cell.second.get(), ctx->id("CARRY_ENABLE")); - std::vector lc(20, false); - - // Discover permutation - std::unordered_map input_perm; - std::set unused; - for (int i = 0; i < 4; i++) - unused.insert(i); - for (int i = 0; i < 4; i++) { - WireId lut_wire = ctx->getBelPinWire(bel, IdString(ID_I0 + i)); - for (auto pip : ctx->getPipsUphill(lut_wire)) { - if (ctx->getBoundPipNet(pip) != nullptr) { - std::string name = ci.wire_data[ctx->getPipSrcWire(pip).index].name.get(); - switch (name.back()) { - case '0': - input_perm[i] = 0; - unused.erase(0); - break; - case '1': - input_perm[i] = 1; - unused.erase(1); - break; - case '2': - input_perm[i] = 2; - unused.erase(2); - break; - case '3': - input_perm[i] = 3; - unused.erase(3); - break; - default: - NPNR_ASSERT_FALSE("failed to determine LUT permutation"); - } - break; - } - } - } - for (int i = 0; i < 4; i++) { - if (!input_perm.count(i)) { - NPNR_ASSERT(!unused.empty()); - input_perm[i] = *(unused.begin()); - unused.erase(input_perm[i]); - } - } - lut_init = permute_lut(lut_init, input_perm); - for (int i = 0; i < 16; i++) { - if ((lut_init >> i) & 0x1) - lc.at(lut_perm.at(i)) = true; - } - lc.at(8) = carry_enable; - lc.at(9) = dff_enable; - lc.at(18) = set_noreset; - lc.at(19) = async_sr; - - for (int i = 0; i < 20; i++) - set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), lc.at(i), i); - if (dff_enable) - set_config(ti, config.at(y).at(x), "NegClk", neg_clk); - - bool carry_const = get_param_or_def(cell.second.get(), ctx->id("CIN_CONST")); - bool carry_set = get_param_or_def(cell.second.get(), ctx->id("CIN_SET")); - if (carry_const) { - if (!ctx->force) - NPNR_ASSERT(z == 0); - set_config(ti, config.at(y).at(x), "CarryInSet", carry_set); - } - } else if (cell.second->type == ctx->id("SB_IO")) { - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - sb_io_used_by_io.insert(Loc(x, y, z)); - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - unsigned pin_type = get_param_or_def(cell.second.get(), ctx->id("PIN_TYPE")); - bool neg_trigger = get_param_or_def(cell.second.get(), ctx->id("NEG_TRIGGER")); - bool pullup = get_param_or_def(cell.second.get(), ctx->id("PULLUP")); - for (int i = 0; i < 6; i++) { - bool val = (pin_type >> i) & 0x01; - set_config(ti, config.at(y).at(x), "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i), val); - } - set_config(ti, config.at(y).at(x), "NegClk", neg_trigger); - auto ieren = get_ieren(bi, x, y, z); - int iex, iey, iez; - std::tie(iex, iey, iez) = ieren; - NPNR_ASSERT(iez != -1); - - bool input_en = false; - if ((ctx->wire_to_net[ctx->getBelPinWire(bel, id_D_IN_0).index] != nullptr) || - (ctx->wire_to_net[ctx->getBelPinWire(bel, id_D_IN_1).index] != nullptr)) { - input_en = true; - } - - if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), !input_en); - set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup); - } else { - set_config(ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), input_en); - set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup); - } - - if (ctx->args.type == ArchArgs::UP5K) { - if (iez == 0) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", !pullup); - } else if (iez == 1) { - set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", !pullup); - } - } - } else if (cell.second->type == ctx->id("SB_GB")) { - // no cell config bits - } else if (cell.second->type == ctx->id("ICESTORM_RAM")) { - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y; - const TileInfoPOD &ti_ramt = bi.tiles_nonrouting[TILE_RAMT]; - const TileInfoPOD &ti_ramb = bi.tiles_nonrouting[TILE_RAMB]; - if (!(ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) { - set_config(ti_ramb, config.at(y).at(x), "RamConfig.PowerUp", true); - } - bool negclk_r = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_R")); - bool negclk_w = get_param_or_def(cell.second.get(), ctx->id("NEG_CLK_W")); - int write_mode = get_param_or_def(cell.second.get(), ctx->id("WRITE_MODE")); - int read_mode = get_param_or_def(cell.second.get(), ctx->id("READ_MODE")); - set_config(ti_ramb, config.at(y).at(x), "NegClk", negclk_w); - set_config(ti_ramt, config.at(y + 1).at(x), "NegClk", negclk_r); - - set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_0", write_mode & 0x1); - set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_1", write_mode & 0x2); - set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_2", read_mode & 0x1); - set_config(ti_ramt, config.at(y + 1).at(x), "RamConfig.CBIT_3", read_mode & 0x2); - } else if (cell.second->type == ctx->id("SB_WARMBOOT") || cell.second->type == ctx->id("ICESTORM_LFOSC")) { - // No config needed - } else if (cell.second->type == ctx->id("ICESTORM_SPRAM")) { - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - NPNR_ASSERT(ctx->args.type == ArchArgs::UP5K); - if (x == 0 && y == 0) { - const TileInfoPOD &ti_ipcon = bi.tiles_nonrouting[TILE_IPCON]; - if (z == 1) { - set_config(ti_ipcon, config.at(1).at(0), "IpConfig.CBIT_0", true); - } else if (z == 2) { - set_config(ti_ipcon, config.at(1).at(0), "IpConfig.CBIT_1", true); - } else { - NPNR_ASSERT(false); - } - } else if (x == 25 && y == 0) { - const TileInfoPOD &ti_ipcon = bi.tiles_nonrouting[TILE_IPCON]; - if (z == 3) { - set_config(ti_ipcon, config.at(1).at(25), "IpConfig.CBIT_0", true); - } else if (z == 4) { - set_config(ti_ipcon, config.at(1).at(25), "IpConfig.CBIT_1", true); - } else { - NPNR_ASSERT(false); - } - } - } else if (cell.second->type == ctx->id("ICESTORM_DSP")) { - const std::vector> mac16_params = {{"C_REG", 1}, - {"A_REG", 1}, - {"B_REG", 1}, - {"D_REG", 1}, - {"TOP_8x8_MULT_REG", 1}, - {"BOT_8x8_MULT_REG", 1}, - {"PIPELINE_16x16_MULT_REG1", 1}, - {"PIPELINE_16x16_MULT_REG2", 1}, - {"TOPOUTPUT_SELECT", 2}, - {"TOPADDSUB_LOWERINPUT", 2}, - {"TOPADDSUB_UPPERINPUT", 1}, - {"TOPADDSUB_CARRYSELECT", 2}, - {"BOTOUTPUT_SELECT", 2}, - {"BOTADDSUB_LOWERINPUT", 2}, - {"BOTADDSUB_UPPERINPUT", 1}, - {"BOTADDSUB_CARRYSELECT", 2}, - {"MODE_8x8", 1}, - {"A_SIGNED", 1}, - {"B_SIGNED", 1}}; - configure_extra_cell(config, ctx, cell.second.get(), mac16_params, false, std::string("IpConfig.")); - } else if (cell.second->type == ctx->id("ICESTORM_HFOSC")) { - const std::vector> hfosc_params = {{"CLKHF_DIV", 2}, {"TRIM_EN", 1}}; - configure_extra_cell(config, ctx, cell.second.get(), hfosc_params, true, std::string("IpConfig.")); - - } else if (cell.second->type == ctx->id("ICESTORM_PLL")) { - const std::vector> pll_params = {{"DELAY_ADJMODE_FB", 1}, - {"DELAY_ADJMODE_REL", 1}, - {"DIVF", 7}, - {"DIVQ", 3}, - {"DIVR", 4}, - {"FDA_FEEDBACK", 4}, - {"FDA_RELATIVE", 4}, - {"FEEDBACK_PATH", 3}, - {"FILTER_RANGE", 3}, - {"PLLOUT_SELECT_A", 2}, - {"PLLOUT_SELECT_B", 2}, - {"PLLTYPE", 3}, - {"SHIFTREG_DIV_MODE", 1}, - {"TEST_MODE", 1}}; - configure_extra_cell(config, ctx, cell.second.get(), pll_params, false, std::string("PLL.")); - - // Configure the SB_IOs that the clock outputs are going through. - for (auto &port : cell.second->ports) { - // If this port is not a PLLOUT port, ignore it. - if (port.second.name != ctx->id("PLLOUT_A") && port.second.name != ctx->id("PLLOUT_B")) - continue; - - // If the output is not driving any net, ignore it. - if (port.second.net == nullptr) - continue; - - // Get IO Bel that this PLL port goes through by finding sibling - // Bel driving the same wire via PIN_D_IN_0. - auto wire = ctx->getBelPinWire(cell.second->bel, port.second.name); - BelId io_bel; - for (auto pin : ctx->getWireBelPins(wire)) { - if (pin.pin == id_D_IN_0) { - io_bel = pin.bel; - break; - } - } - NPNR_ASSERT(io_bel.index != -1); - auto io_bel_loc = ctx->getBelLocation(io_bel); - - // Check that this SB_IO is either unused or just used as an output. - if (sb_io_used_by_io.count(io_bel_loc)) { - log_error("SB_IO '%s' already in use, cannot route PLL through\n", ctx->getBelName(bel).c_str(ctx)); - } - sb_io_used_by_pll.insert(io_bel_loc); - - // Get IE/REN config location (cf. http://www.clifford.at/icestorm/io_tile.html) - auto ieren = get_ieren(bi, io_bel_loc.x, io_bel_loc.y, io_bel_loc.z); - int iex, iey, iez; - std::tie(iex, iey, iez) = ieren; - NPNR_ASSERT(iez != -1); - - // Write config. - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - // Enable input buffer and disable pull-up resistor in block - // (this is used by the PLL). - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); - // PINTYPE[0] passes the PLL through to the fabric. - set_config(ti, config.at(io_bel_loc.y).at(io_bel_loc.x), - "IOB_" + std::to_string(io_bel_loc.z) + ".PINTYPE_0", true); - } - - } else { - NPNR_ASSERT(false); - } - } - // Set config bits in unused IO and RAM - for (auto bel : ctx->getBels()) { - if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == id_SB_IO) { - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - if (sb_io_used_by_pll.count(Loc(x, y, z))) { - continue; - } - - auto ieren = get_ieren(bi, x, y, z); - int iex, iey, iez; - std::tie(iex, iey, iez) = ieren; - if (iez != -1) { - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.IE_" + std::to_string(iez), true); - set_ie_bit_logical(ctx, ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); - } - } else if (ctx->bel_to_cell[bel.index] == nullptr && ctx->getBelType(bel) == id_ICESTORM_RAM) { - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y; - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; - if ((ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K)) { - set_config(ti, config.at(y).at(x), "RamConfig.PowerUp", true); - } - } - } - - // Set other config bits - for (int y = 0; y < ci.height; y++) { - for (int x = 0; x < ci.width; x++) { - TileType tile = tile_at(ctx, x, y); - const TileInfoPOD &ti = bi.tiles_nonrouting[tile]; - - // set all ColBufCtrl bits (FIXME) - bool setColBufCtrl = true; - if (ctx->args.type == ArchArgs::LP1K || ctx->args.type == ArchArgs::HX1K) { - if (tile == TILE_RAMB || tile == TILE_RAMT) { - setColBufCtrl = (y == 3 || y == 5 || y == 11 || y == 13); - } else { - setColBufCtrl = (y == 4 || y == 5 || y == 12 || y == 13); - } - } else if (ctx->args.type == ArchArgs::LP8K || ctx->args.type == ArchArgs::HX8K) { - setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25); - } else if (ctx->args.type == ArchArgs::UP5K) { - setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || y == 26 || y == 27); - } - if (setColBufCtrl) { - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_0", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_1", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_2", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_3", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_4", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_5", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_6", true); - set_config(ti, config.at(y).at(x), "ColBufCtrl.glb_netwk_7", true); - } - - // Weird UltraPlus bits - if (tile == TILE_DSP0 || tile == TILE_DSP1 || tile == TILE_DSP2 || tile == TILE_DSP3 || - tile == TILE_IPCON) { - if (ctx->args.type == ArchArgs::UP5K && x == 25 && y == 14) { - // Mystery bits not set in this one tile - } else { - for (int lc_idx = 0; lc_idx < 8; lc_idx++) { - static const std::vector ip_dsp_lut_perm = { - 4, 14, 15, 5, 6, 16, 17, 7, 3, 13, 12, 2, 1, 11, 10, 0, - }; - for (int i = 0; i < 16; i++) - set_config(ti, config.at(y).at(x), "LC_" + std::to_string(lc_idx), ((i % 8) >= 4), - ip_dsp_lut_perm.at(i)); - if (tile == TILE_IPCON) - set_config(ti, config.at(y).at(x), - "Cascade.IPCON_LC0" + std::to_string(lc_idx) + "_inmux02_5", true); - else - set_config(ti, config.at(y).at(x), - "Cascade.MULT" + std::to_string(int(tile - TILE_DSP0)) + "_LC0" + - std::to_string(lc_idx) + "_inmux02_5", - true); - } - } - } - } - } - - // Write config out - for (int y = 0; y < ci.height; y++) { - for (int x = 0; x < ci.width; x++) { - TileType tile = tile_at(ctx, x, y); - if (tile == TILE_NONE) - continue; - out << tagTileType(tile); - out << " " << x << " " << y << std::endl; - for (auto row : config.at(y).at(x)) { - for (auto col : row) { - if (col == 1) - out << "1"; - else - out << "0"; - } - out << std::endl; - } - out << std::endl; - } - } - - // Write RAM init data - for (auto &cell : ctx->cells) { - if (cell.second->bel != BelId()) { - if (cell.second->type == ctx->id("ICESTORM_RAM")) { - const BelInfoPOD &beli = ci.bel_data[cell.second->bel.index]; - int x = beli.x, y = beli.y; - out << ".ram_data " << x << " " << y << std::endl; - for (int w = 0; w < 16; w++) { - std::vector bits(256); - std::string init = - get_param_str_or_def(cell.second.get(), ctx->id(std::string("INIT_") + get_hexdigit(w))); - NPNR_ASSERT(init != ""); - for (size_t i = 0; i < init.size(); i++) { - bool val = (init.at((init.size() - 1) - i) == '1'); - bits.at(i) = val; - } - for (int i = bits.size() - 4; i >= 0; i -= 4) { - int c = bits.at(i) + (bits.at(i + 1) << 1) + (bits.at(i + 2) << 2) + (bits.at(i + 3) << 3); - out << char(std::tolower(get_hexdigit(c))); - } - out << std::endl; - } - out << std::endl; - } - } - } - - // Write symbols - // const bool write_symbols = 1; - for (auto wire : ctx->getWires()) { - NetInfo *net = ctx->getBoundWireNet(wire); - if (net != nullptr) - out << ".sym " << wire.index << " " << net->name.str(ctx) << std::endl; - } -} - -void read_config(Context *ctx, std::istream &in, chipconfig_t &config) -{ - constexpr size_t line_buf_size = 65536; - char buffer[line_buf_size]; - int tile_x = -1, tile_y = -1, line_nr = -1; - - while (1) { - in.getline(buffer, line_buf_size); - if (buffer[0] == '.') { - line_nr = -1; - const char *tok = strtok(buffer, " \t\r\n"); - - if (!strcmp(tok, ".device")) { - std::string config_device = strtok(nullptr, " \t\r\n"); - std::string expected; - switch (ctx->args.type) { - case ArchArgs::LP384: - expected = "384"; - break; - case ArchArgs::HX1K: - case ArchArgs::LP1K: - expected = "1k"; - break; - case ArchArgs::HX8K: - case ArchArgs::LP8K: - expected = "8k"; - break; - case ArchArgs::UP5K: - expected = "5k"; - break; - default: - log_error("unsupported device type\n"); - } - if (expected != config_device) - log_error("device type does not match\n"); - } else if (!strcmp(tok, ".io_tile") || !strcmp(tok, ".logic_tile") || !strcmp(tok, ".ramb_tile") || - !strcmp(tok, ".ramt_tile") || !strcmp(tok, ".ipcon_tile") || !strcmp(tok, ".dsp0_tile") || - !strcmp(tok, ".dsp1_tile") || !strcmp(tok, ".dsp2_tile") || !strcmp(tok, ".dsp3_tile")) { - line_nr = 0; - tile_x = atoi(strtok(nullptr, " \t\r\n")); - tile_y = atoi(strtok(nullptr, " \t\r\n")); - - TileType tile = tile_at(ctx, tile_x, tile_y); - if (tok != tagTileType(tile)) - log_error("Wrong tile type for specified position\n"); - - } else if (!strcmp(tok, ".extra_bit")) { - /* - int b = atoi(strtok(nullptr, " \t\r\n")); - int x = atoi(strtok(nullptr, " \t\r\n")); - int y = atoi(strtok(nullptr, " \t\r\n")); - std::tuple key(b, x, y); - extra_bits.insert(key); - */ - } else if (!strcmp(tok, ".sym")) { - int wireIndex = atoi(strtok(nullptr, " \t\r\n")); - const char *name = strtok(nullptr, " \t\r\n"); - - IdString netName = ctx->id(name); - - if (ctx->nets.find(netName) == ctx->nets.end()) { - std::unique_ptr created_net = std::unique_ptr(new NetInfo); - created_net->name = netName; - ctx->nets[netName] = std::move(created_net); - } - - WireId wire; - wire.index = wireIndex; - ctx->bindWire(wire, ctx->nets.at(netName).get(), STRENGTH_WEAK); - } - } else if (line_nr >= 0 && strlen(buffer) > 0) { - if (line_nr > int(config.at(tile_y).at(tile_x).size() - 1)) - log_error("Invalid data in input asc file"); - for (int i = 0; buffer[i] == '0' || buffer[i] == '1'; i++) - config.at(tile_y).at(tile_x).at(line_nr).at(i) = (buffer[i] == '1') ? 1 : 0; - line_nr++; - } - if (in.eof()) - break; - } -} - -bool read_asc(Context *ctx, std::istream &in) -{ - try { - // [y][x][row][col] - const ChipInfoPOD &ci = *ctx->chip_info; - const BitstreamInfoPOD &bi = *ci.bits_info; - chipconfig_t config; - config.resize(ci.height); - for (int y = 0; y < ci.height; y++) { - config.at(y).resize(ci.width); - for (int x = 0; x < ci.width; x++) { - TileType tile = tile_at(ctx, x, y); - int rows = bi.tiles_nonrouting[tile].rows; - int cols = bi.tiles_nonrouting[tile].cols; - config.at(y).at(x).resize(rows, std::vector(cols)); - } - } - read_config(ctx, in, config); - - // Set pips - for (auto pip : ctx->getPips()) { - const PipInfoPOD &pi = ci.pip_data[pip.index]; - const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; - bool isUsed = true; - for (int i = 0; i < swi.num_bits; i++) { - bool val = (pi.switch_mask & (1 << ((swi.num_bits - 1) - i))) != 0; - int8_t cbit = config.at(swi.y).at(swi.x).at(swi.cbits[i].row).at(swi.cbits[i].col); - isUsed &= !(bool(cbit) ^ val); - } - if (isUsed) { - NetInfo *net = ctx->wire_to_net[pi.dst]; - WireId wire; - wire.index = pi.dst; - ctx->unbindWire(wire); - ctx->bindPip(pip, net, STRENGTH_WEAK); - } - } - for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == id_ICESTORM_LC) { - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_LOGIC]; - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - std::vector lc(20, false); - bool isUsed = false; - for (int i = 0; i < 20; i++) { - lc.at(i) = get_config(ti, config.at(y).at(x), "LC_" + std::to_string(z), i); - isUsed |= lc.at(i); - } - bool neg_clk = get_config(ti, config.at(y).at(x), "NegClk"); - isUsed |= neg_clk; - bool carry_set = get_config(ti, config.at(y).at(x), "CarryInSet"); - isUsed |= carry_set; - - if (isUsed) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets and assign values of properties - } - } - if (ctx->getBelType(bel) == id_SB_IO) { - const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; - const BelInfoPOD &beli = ci.bel_data[bel.index]; - int x = beli.x, y = beli.y, z = beli.z; - bool isUsed = false; - for (int i = 0; i < 6; i++) { - isUsed |= get_config(ti, config.at(y).at(x), - "IOB_" + std::to_string(z) + ".PINTYPE_" + std::to_string(i)); - } - bool neg_trigger = get_config(ti, config.at(y).at(x), "NegClk"); - isUsed |= neg_trigger; - - if (isUsed) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_IO")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets and assign values of properties - } - } - } - // Add cells that are without change in initial state of configuration - for (auto &net : ctx->nets) { - for (auto w : net.second->wires) { - if (w.second.pip == PipId()) { - WireId wire = w.first; - for (auto belpin : ctx->getWireBelPins(wire)) { - - if (ctx->checkBelAvail(belpin.bel)) { - if (ctx->getBelType(belpin.bel) == id_ICESTORM_LC) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets - } - if (ctx->getBelType(belpin.bel) == id_SB_IO) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_IO")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets - } - if (ctx->getBelType(belpin.bel) == id_SB_GB) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_GB")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets - } - if (ctx->getBelType(belpin.bel) == id_SB_WARMBOOT) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("SB_WARMBOOT")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets - } - if (ctx->getBelType(belpin.bel) == id_ICESTORM_LFOSC) { - std::unique_ptr created = create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC")); - IdString name = created->name; - ctx->cells[name] = std::move(created); - ctx->bindBel(belpin.bel, ctx->cells[name].get(), STRENGTH_WEAK); - // TODO: Add port mapping to nets - } - } - } - } - } - } - for (auto &cell : ctx->cells) { - if (cell.second->bel != BelId()) { - for (auto &port : cell.second->ports) { - IdString pin = port.first; - WireId wire = ctx->getBelPinWire(cell.second->bel, pin); - if (wire != WireId()) { - NetInfo *net = ctx->getBoundWireNet(wire); - if (net != nullptr) { - port.second.net = net; - PortRef ref; - ref.cell = cell.second.get(); - ref.port = port.second.name; - - if (port.second.type == PORT_OUT) - net->driver = ref; - else - net->users.push_back(ref); - } - } - } - } - } - return true; - } catch (log_execution_error_exception) { - return false; - } -} -NEXTPNR_NAMESPACE_END diff --git a/xc7/bitstream.h b/xc7/bitstream.h deleted file mode 100644 index 41a2ae68..00000000 --- a/xc7/bitstream.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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. - * - */ - -#ifndef ICE40_BITSTREAM_H -#define ICE40_BITSTREAM_H - -#include -#include "nextpnr.h" - -NEXTPNR_NAMESPACE_BEGIN - -void write_asc(const Context *ctx, std::ostream &out); -bool read_asc(Context *ctx, std::istream &in); - -NEXTPNR_NAMESPACE_END - -#endif diff --git a/xc7/delay.cc b/xc7/delay.cc index d76aaefb..98c3c655 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -98,92 +98,10 @@ void ice40DelayFuzzerMain(Context *ctx) } } -namespace { - -struct model_params_t -{ - int neighbourhood; - - int model0_offset; - int model0_norm1; - - int model1_offset; - int model1_norm1; - int model1_norm2; - int model1_norm3; - - int model2_offset; - int model2_linear; - int model2_sqrt; - - int delta_local; - int delta_lutffin; - int delta_sp4; - int delta_sp12; - - static const model_params_t &get(const ArchArgs& args) - { - static const model_params_t model_hx8k = {588, 129253, 8658, 118333, 23915, -73105, 57696, - -86797, 89, 3706, -316, -575, -158, -296}; - - static const model_params_t model_lp8k = {867, 206236, 11043, 191910, 31074, -95972, 75739, - -309793, 30, 11056, -474, -856, -363, -536}; - - static const model_params_t model_up5k = {1761, 305798, 16705, 296830, 24430, -40369, 33038, - -162662, 94, 4705, -1099, -1761, -418, -838}; - - if (args.type == ArchArgs::HX1K || args.type == ArchArgs::HX8K) - return model_hx8k; - - if (args.type == ArchArgs::LP384 || args.type == ArchArgs::LP1K || args.type == ArchArgs::LP8K) - return model_lp8k; - - if (args.type == ArchArgs::UP5K) - return model_up5k; - - NPNR_ASSERT(0); - } -}; - -} // namespace - delay_t Arch::estimateDelay(WireId src, WireId dst) const { - NPNR_ASSERT(src != WireId()); - int x1 = chip_info->wire_data[src.index].x; - int y1 = chip_info->wire_data[src.index].y; - int z1 = chip_info->wire_data[src.index].z; - int type = chip_info->wire_data[src.index].type; - - NPNR_ASSERT(dst != WireId()); - int x2 = chip_info->wire_data[dst.index].x; - int y2 = chip_info->wire_data[dst.index].y; - int z2 = chip_info->wire_data[dst.index].z; - - int dx = abs(x2 - x1); - int dy = abs(y2 - y1); - - const model_params_t &p = model_params_t::get(args); - delay_t v = p.neighbourhood; - - if (dx > 1 || dy > 1) - v = (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128; - - if (dx == 0 && dy == 0) { - if (type == WireInfoPOD::WIRE_TYPE_LOCAL) - v += p.delta_local; - - if (type == WireInfoPOD::WIRE_TYPE_LUTFF_IN || type == WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT) - v += (z1 == z2) ? p.delta_lutffin : 0; - } - - if (type == WireInfoPOD::WIRE_TYPE_SP4_V || type == WireInfoPOD::WIRE_TYPE_SP4_H) - v += p.delta_sp4; - - if (type == WireInfoPOD::WIRE_TYPE_SP12_V || type == WireInfoPOD::WIRE_TYPE_SP12_H) - v += p.delta_sp12; - - return v; + //return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); + return 0; } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const @@ -192,47 +110,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto driver_loc = getBelLocation(driver.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel); - if (driver.port == id_COUT) { - if (driver_loc.y == sink_loc.y) - return 0; - return 250; - } - - int dx = abs(sink_loc.x - driver_loc.x); - int dy = abs(sink_loc.y - driver_loc.y); - - const model_params_t &p = model_params_t::get(args); - - if (dx <= 1 && dy <= 1) - return p.neighbourhood; - -#if 1 - // Model #0 - return (p.model0_offset + p.model0_norm1 * (dx + dy)) / 128; -#else - float norm1 = dx + dy; - - float dx2 = dx * dx; - float dy2 = dy * dy; - float norm2 = sqrtf(dx2 + dy2); - - float dx3 = dx2 * dx; - float dy3 = dy2 * dy; - float norm3 = powf(dx3 + dy3, 1.0 / 3.0); - - // Model #1 - float v = p.model1_offset; - v += p.model1_norm1 * norm1; - v += p.model1_norm2 * norm2; - v += p.model1_norm3 * norm3; - v /= 128; - - // Model #2 - v = p.model2_offset + p.model2_linear * v + p.model2_sqrt * sqrtf(v); - v /= 128; - - return v; -#endif + return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); } NEXTPNR_NAMESPACE_END diff --git a/xc7/family.cmake b/xc7/family.cmake index f558a14d..e69de29b 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,84 +0,0 @@ -if(ICE40_HX1K_ONLY) - set(devices 1k) - foreach (target ${family_targets}) - target_compile_definitions(${target} PRIVATE ICE40_HX1K_ONLY=1) - endforeach (target) -else() - set(devices 384 1k 5k 8k) -endif() - -set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdb.py) - -set(ICEBOX_ROOT "/usr/local/share/icebox" CACHE STRING "icebox location root") -file(MAKE_DIRECTORY ice40/chipdbs/) -add_library(ice40_chipdb OBJECT ice40/chipdbs/) -target_compile_definitions(ice40_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family}) -target_include_directories(ice40_chipdb PRIVATE ${family}/) - -if (MSVC) - target_sources(ice40_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ice40/resource/embed.cc) - set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ice40/resources/chipdb.rc PROPERTIES LANGUAGE RC) - foreach (dev ${devices}) - if (dev EQUAL "5k") - set(OPT_FAST "") - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_up5k.txt) - elseif(dev EQUAL "384") - set(OPT_FAST "") - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp384.txt) - else() - set(OPT_FAST --fast ${ICEBOX_ROOT}/timings_hx${dev}.txt) - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp${dev}.txt) - endif() - set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) - set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) - set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bin) - set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/constids.inc) - set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) - add_custom_command(OUTPUT ${DEV_CC_BBA_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB} - DEPENDS ${DEV_TXT_DB} ${DB_PY} - ) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm ${DEV_CC_BBA_DB} ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) - target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) - set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE) - foreach (target ${family_targets}) - target_sources(${target} PRIVATE $ ${CMAKE_CURRENT_SOURCE_DIR}/ice40/resource/chipdb.rc) - endforeach (target) - endforeach (dev) -else() - target_compile_options(ice40_chipdb PRIVATE -g0 -O0 -w) - foreach (dev ${devices}) - if (dev EQUAL "5k") - set(OPT_FAST "") - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_up5k.txt) - elseif(dev EQUAL "384") - set(OPT_FAST "") - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp384.txt) - else() - set(OPT_FAST --fast ${ICEBOX_ROOT}/timings_hx${dev}.txt) - set(OPT_SLOW --slow ${ICEBOX_ROOT}/timings_lp${dev}.txt) - endif() - set(DEV_TXT_DB ${ICEBOX_ROOT}/chipdb-${dev}.txt) - set(DEV_CC_BBA_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.bba) - set(DEV_CC_DB ${CMAKE_CURRENT_SOURCE_DIR}/ice40/chipdbs/chipdb-${dev}.cc) - set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ice40/constids.inc) - set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ice40/gfx.h) - add_custom_command(OUTPUT ${DEV_CC_BBA_DB} - COMMAND ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${OPT_FAST} ${OPT_SLOW} ${DEV_TXT_DB} > ${DEV_CC_BBA_DB}.new - COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB} - DEPENDS ${DEV_TXT_DB} ${DB_PY} - ) - add_custom_command(OUTPUT ${DEV_CC_DB} - COMMAND bbasm --c ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new - COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB} - DEPENDS bbasm ${DEV_CC_BBA_DB} - ) - target_sources(ice40_chipdb PRIVATE ${DEV_CC_DB}) - foreach (target ${family_targets}) - target_sources(${target} PRIVATE $) - endforeach (target) - endforeach (dev) -endif() diff --git a/xc7/main.cc b/xc7/main.cc index 8bab360d..440a26d0 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -21,7 +21,6 @@ #ifdef MAIN_EXECUTABLE #include -#include "bitstream.h" #include "command.h" #include "design_utils.h" #include "jsonparse.h" @@ -31,133 +30,77 @@ USING_NEXTPNR_NAMESPACE -class Ice40CommandHandler : public CommandHandler +class Xc7CommandHandler : public CommandHandler { public: - Ice40CommandHandler(int argc, char **argv); - virtual ~Ice40CommandHandler(){}; + Xc7CommandHandler(int argc, char **argv); + virtual ~Xc7CommandHandler(){}; std::unique_ptr createContext() override; void setupArchContext(Context *ctx) override; void validate() override; void customAfterLoad(Context *ctx) override; - void customBitstream(Context *ctx) override; protected: po::options_description getArchOptions(); }; -Ice40CommandHandler::Ice40CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} +Xc7CommandHandler::Xc7CommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {} -po::options_description Ice40CommandHandler::getArchOptions() +po::options_description Xc7CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); -#ifdef ICE40_HX1K_ONLY - specific.add_options()("hx1k", "set device type to iCE40HX1K"); -#else - specific.add_options()("lp384", "set device type to iCE40LP384"); - specific.add_options()("lp1k", "set device type to iCE40LP1K"); - specific.add_options()("lp8k", "set device type to iCE40LP8K"); - specific.add_options()("hx1k", "set device type to iCE40HX1K"); - specific.add_options()("hx8k", "set device type to iCE40HX8K"); - specific.add_options()("up5k", "set device type to iCE40UP5K"); -#endif - specific.add_options()("package", po::value(), "set device package"); - specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); - specific.add_options()("asc", po::value(), "asc bitstream file to write"); - specific.add_options()("read", po::value(), "asc bitstream file to read"); - specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); + specific.add_options()("xc7z020", "set device type to xc7z020"); +// specific.add_options()("package", po::value(), "set device package"); +// specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); + specific.add_options()("xdl", po::value(), "XDL file to write"); +// specific.add_options()("read", po::value(), "asc bitstream file to read"); +// specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); return specific; } -void Ice40CommandHandler::validate() +void Xc7CommandHandler::validate() { conflicting_options(vm, "read", "json"); - if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + - vm.count("up5k")) > 1) - log_error("Only one device type can be set\n"); +// if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + +// vm.count("up5k")) > 1) +// log_error("Only one device type can be set\n"); } -void Ice40CommandHandler::customAfterLoad(Context *ctx) +void Xc7CommandHandler::customAfterLoad(Context *ctx) { - if (vm.count("pcf")) { - std::string filename = vm["pcf"].as(); - std::ifstream pcf(filename); - if (!apply_pcf(ctx, filename, pcf)) - log_error("Loading PCF failed.\n"); - } +// if (vm.count("pcf")) { +// std::string filename = vm["pcf"].as(); +// std::ifstream pcf(filename); +// if (!apply_pcf(ctx, filename, pcf)) +// log_error("Loading PCF failed.\n"); +// } } -void Ice40CommandHandler::customBitstream(Context *ctx) +void Xc7CommandHandler::setupArchContext(Context *ctx) { - if (vm.count("asc")) { - std::string filename = vm["asc"].as(); - std::ofstream f(filename); - write_asc(ctx, f); - } +// if (vm.count("tmfuzz")) +// ice40DelayFuzzerMain(ctx); } -void Ice40CommandHandler::setupArchContext(Context *ctx) +std::unique_ptr Xc7CommandHandler::createContext() { - if (vm.count("tmfuzz")) - ice40DelayFuzzerMain(ctx); - - if (vm.count("read")) { - std::string filename = vm["read"].as(); - std::ifstream f(filename); - if (!read_asc(ctx, f)) - log_error("Loading ASC failed.\n"); - } -} - -std::unique_ptr Ice40CommandHandler::createContext() -{ - if (vm.count("lp384")) { - chipArgs.type = ArchArgs::LP384; - chipArgs.package = "qn32"; - } - - if (vm.count("lp1k")) { - chipArgs.type = ArchArgs::LP1K; - chipArgs.package = "tq144"; - } - - if (vm.count("lp8k")) { - chipArgs.type = ArchArgs::LP8K; - chipArgs.package = "ct256"; - } - - if (vm.count("hx1k")) { - chipArgs.type = ArchArgs::HX1K; - chipArgs.package = "tq144"; - } - - if (vm.count("hx8k")) { - chipArgs.type = ArchArgs::HX8K; - chipArgs.package = "ct256"; - } - - if (vm.count("up5k")) { - chipArgs.type = ArchArgs::UP5K; - chipArgs.package = "sg48"; + if (vm.count("xc7z020")) { + chipArgs.type = ArchArgs::XC7Z020; + chipArgs.package = "clg484"; } if (chipArgs.type == ArchArgs::NONE) { - chipArgs.type = ArchArgs::HX1K; - chipArgs.package = "tq144"; + chipArgs.type = ArchArgs::XC7Z020; + chipArgs.package = "clg484"; } -#ifdef ICE40_HX1K_ONLY - if (chipArgs.type != ArchArgs::HX1K) { - log_error("This version of nextpnr-ice40 is built with HX1K-support only.\n"); - } -#endif - if (vm.count("package")) - chipArgs.package = vm["package"].as(); +// if (vm.count("package")) +// chipArgs.package = vm["package"].as(); return std::unique_ptr(new Context(chipArgs)); } int main(int argc, char *argv[]) { - Ice40CommandHandler handler(argc, argv); + Xc7CommandHandler handler(argc, argv); return handler.exec(); } diff --git a/xc7/project.cc b/xc7/project.cc index 8ca10e36..af0a775b 100644 --- a/xc7/project.cc +++ b/xc7/project.cc @@ -38,23 +38,8 @@ std::unique_ptr ProjectHandler::createContext(pt::ptree &root) { ArchArgs chipArgs; std::string arch_type = root.get("project.arch.type"); - if (arch_type == "lp384") { - chipArgs.type = ArchArgs::LP384; - } - if (arch_type == "lp1k") { - chipArgs.type = ArchArgs::LP1K; - } - if (arch_type == "lp8k") { - chipArgs.type = ArchArgs::LP8K; - } - if (arch_type == "hx1k") { - chipArgs.type = ArchArgs::HX1K; - } - if (arch_type == "hx8k") { - chipArgs.type = ArchArgs::HX8K; - } - if (arch_type == "up5k") { - chipArgs.type = ArchArgs::UP5K; + if (arch_type == "xc7z020") { + chipArgs.type = ArchArgs::XC7Z020; } chipArgs.package = root.get("project.arch.package"); From 83574177878cbf755d2cec0c0bc640e36fbd9c9d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 15:53:55 -0700 Subject: [PATCH 004/174] Load Torc DDB --- xc7/arch.cc | 15 +++++++++------ xc7/arch.h | 7 ++++++- xc7/family.cmake | 46 ++++++++++++++++++++++++++++++++++++++++++++++ xc7/main.cc | 6 +++--- xc7/project.cc | 4 ++-- 5 files changed, 66 insertions(+), 12 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 9b739ba4..5d14fac8 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -28,6 +28,8 @@ #include "router1.h" #include "util.h" +#include "torc/common/DirectoryTree.hpp" + NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -43,8 +45,9 @@ void IdString::initialize_arch(const BaseCtx *ctx) Arch::Arch(ArchArgs args) : args(args) { - if (args.type == ArchArgs::XC7Z020) { - //chip_info = get_chip_info(reinterpret_cast *>(chipdb_blob_1k)); + torc::common::DirectoryTree directoryTree("../../torc/src/torc"); + if (args.type == ArchArgs::Z020) { + ddb = new DDB("xc7z020", "clg484"); } else { log_error("Unsupported XC7 chip type.\n"); } @@ -64,8 +67,8 @@ Arch::Arch(ArchArgs args) : args(args) std::string Arch::getChipName() const { - if (args.type == ArchArgs::XC7Z020) { - return "XC7Z020"; + if (args.type == ArchArgs::Z020) { + return "z020"; } else { log_error("Unsupported XC7 chip type.\n"); } @@ -75,8 +78,8 @@ std::string Arch::getChipName() const IdString Arch::archArgsToId(ArchArgs args) const { - if (args.type == ArchArgs::XC7Z020) - return id("xc7z020"); + if (args.type == ArchArgs::Z020) + return id("z020"); return IdString(); } diff --git a/xc7/arch.h b/xc7/arch.h index d92ff0c1..411be954 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -21,6 +21,10 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include "torc/Architecture.hpp" +#include "torc/Common.hpp" +using namespace torc::architecture; + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -378,7 +382,7 @@ struct ArchArgs enum ArchArgsTypes { NONE, - XC7Z020 + Z020 } type = NONE; std::string package; }; @@ -387,6 +391,7 @@ struct Arch : BaseCtx { bool fast_part; const ChipInfoPOD *chip_info; + const DDB *ddb; const PackageInfoPOD *package_info; mutable std::unordered_map bel_by_name; diff --git a/xc7/family.cmake b/xc7/family.cmake index e69de29b..a92fd44b 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -0,0 +1,46 @@ +include_directories(.) +#include_directories(torc/externals/zlib) + +target_link_libraries( + nextpnr-${family} + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Arc.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/ArcUsage.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Array.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDB.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDBConsoleStreams.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDBStreamHelper.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DigestStream.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/ExtendedWireInfo.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/InstancePin.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/OutputStreamHelpers.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Package.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Pad.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveConn.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveDef.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveElement.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveElementPin.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitivePin.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Segments.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Site.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Sites.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Tiles.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/TileInfo.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Tilewire.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Versions.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/VprExporter.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/WireInfo.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/WireUsage.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/XdlImporter.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/XilinxDatabaseTypes.o + + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/Annotated.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DeviceDesignator.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/Devices.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DirectoryTree.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DottedVersion.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/NullOutputStream.o + PRIVATE boost_regex + + PRIVATE ${CMAKE_SOURCE_DIR}/torc/externals/zlib/zfstream.o + PRIVATE z +) diff --git a/xc7/main.cc b/xc7/main.cc index 440a26d0..79f40add 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -82,13 +82,13 @@ void Xc7CommandHandler::setupArchContext(Context *ctx) std::unique_ptr Xc7CommandHandler::createContext() { - if (vm.count("xc7z020")) { - chipArgs.type = ArchArgs::XC7Z020; + if (vm.count("z020")) { + chipArgs.type = ArchArgs::Z020; chipArgs.package = "clg484"; } if (chipArgs.type == ArchArgs::NONE) { - chipArgs.type = ArchArgs::XC7Z020; + chipArgs.type = ArchArgs::Z020; chipArgs.package = "clg484"; } diff --git a/xc7/project.cc b/xc7/project.cc index af0a775b..5c8def1f 100644 --- a/xc7/project.cc +++ b/xc7/project.cc @@ -38,8 +38,8 @@ std::unique_ptr ProjectHandler::createContext(pt::ptree &root) { ArchArgs chipArgs; std::string arch_type = root.get("project.arch.type"); - if (arch_type == "xc7z020") { - chipArgs.type = ArchArgs::XC7Z020; + if (arch_type == "z020") { + chipArgs.type = ArchArgs::Z020; } chipArgs.package = root.get("project.arch.package"); From fbeb039f39a0cd1f0fce5341839e62f67448b87c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 16:01:08 -0700 Subject: [PATCH 005/174] Enable -pcf option but ignore --- xc7/main.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xc7/main.cc b/xc7/main.cc index 79f40add..67515f7b 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -51,7 +51,7 @@ po::options_description Xc7CommandHandler::getArchOptions() po::options_description specific("Architecture specific options"); specific.add_options()("xc7z020", "set device type to xc7z020"); // specific.add_options()("package", po::value(), "set device package"); -// specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); + specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); // specific.add_options()("read", po::value(), "asc bitstream file to read"); // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); @@ -67,12 +67,12 @@ void Xc7CommandHandler::validate() void Xc7CommandHandler::customAfterLoad(Context *ctx) { -// if (vm.count("pcf")) { + if (vm.count("pcf")) { // std::string filename = vm["pcf"].as(); // std::ifstream pcf(filename); // if (!apply_pcf(ctx, filename, pcf)) // log_error("Loading PCF failed.\n"); -// } + } } void Xc7CommandHandler::setupArchContext(Context *ctx) { From 74ff630922b8ea34fe4ae850460676dda7504cc7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 16:01:15 -0700 Subject: [PATCH 006/174] Tweak blinky.sh for xc7 --- xc7/blinky.sh | 10 +++++----- xc7/blinky.v | 6 +++--- xc7/blinky.ys | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index a2326fc3..eeff875f 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,8 +1,8 @@ #!/bin/bash set -ex yosys blinky.ys -../nextpnr-ice40 --json blinky.json --pcf blinky.pcf --asc blinky.asc -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 +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl +#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/xc7/blinky.v b/xc7/blinky.v index 36eaee86..daaac373 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -7,9 +7,9 @@ module blinky ( output led5 ); - SB_GB clk_gb ( - .USER_SIGNAL_TO_GLOBAL_BUFFER(clki), - .GLOBAL_BUFFER_OUTPUT(clk) + BUFG clk_gb ( + .I(clki), + .O(clk) ); localparam BITS = 5; diff --git a/xc7/blinky.ys b/xc7/blinky.ys index a5dd2c85..c4aded99 100644 --- a/xc7/blinky.ys +++ b/xc7/blinky.ys @@ -1,3 +1,3 @@ read_verilog blinky.v -synth_ice40 -top blinky +synth_xilinx -top blinky write_json blinky.json From 45009ac09d320ec17bff36cfc39ff9b59467ca5a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 17:08:50 -0700 Subject: [PATCH 007/174] Remove timing, remove wires --- xc7/arch.cc | 84 +---------------------------------------------------- xc7/arch.h | 2 +- 2 files changed, 2 insertions(+), 84 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 5d14fac8..52d88326 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -668,95 +668,13 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { - for (int i = 0; i < chip_info->num_timing_cells; i++) { - const auto &tc = chip_info->cell_timing[i]; - if (tc.type == cell->type.index) { - for (int j = 0; j < tc.num_paths; j++) { - const auto &path = tc.path_delays[j]; - if (path.from_port == fromPort.index && path.to_port == toPort.index) { - if (fast_part) - delay.delay = path.fast_delay; - else - delay.delay = path.slow_delay; - return true; - } - } - break; - } - } return false; } // Get the port class, also setting clockPort to associated clock if applicable TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const { - if (cell->type == id_ICESTORM_LC) { - if (port == id_CLK) - return TMG_CLOCK_INPUT; - if (port == id_CIN) - return TMG_COMB_INPUT; - if (port == id_COUT || port == id_LO) - return TMG_COMB_OUTPUT; - if (cell->lcInfo.dffEnable) { - clockPort = id_CLK; - if (port == id_O) - return TMG_REGISTER_OUTPUT; - else - return TMG_REGISTER_INPUT; - } else { - if (port == id_O) - return TMG_COMB_OUTPUT; - else - return TMG_COMB_INPUT; - } - } else if (cell->type == id_ICESTORM_RAM) { - - if (port == id_RCLK || port == id_WCLK) - return TMG_CLOCK_INPUT; - - if (port.str(this)[0] == 'R') - clockPort = id_RCLK; - else - clockPort = id_WCLK; - - if (cell->ports.at(port).type == PORT_OUT) - return TMG_REGISTER_OUTPUT; - else - return TMG_REGISTER_INPUT; - } else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) { - clockPort = id_CLK; - if (port == id_CLK) - return TMG_CLOCK_INPUT; - else if (cell->ports.at(port).type == PORT_OUT) - return TMG_REGISTER_OUTPUT; - else - return TMG_REGISTER_INPUT; - } else if (cell->type == id_SB_IO) { - if (port == id_D_IN_0 || port == id_D_IN_1) - return TMG_STARTPOINT; - if (port == id_D_OUT_0 || port == id_D_OUT_1 || port == id_OUTPUT_ENABLE) - return TMG_ENDPOINT; - return TMG_IGNORE; - } else if (cell->type == id_ICESTORM_PLL) { - if (port == id_PLLOUT_A || port == id_PLLOUT_B) - return TMG_GEN_CLOCK; - return TMG_IGNORE; - } else if (cell->type == id_ICESTORM_LFOSC) { - if (port == id_CLKLF) - return TMG_GEN_CLOCK; - return TMG_IGNORE; - } else if (cell->type == id_ICESTORM_HFOSC) { - if (port == id_CLKHF) - return TMG_GEN_CLOCK; - return TMG_IGNORE; - } else if (cell->type == id_SB_GB) { - if (port == id_GLOBAL_BUFFER_OUTPUT) - return TMG_COMB_OUTPUT; - return TMG_COMB_INPUT; - } else if (cell->type == id_SB_WARMBOOT) { - return TMG_ENDPOINT; - } - log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); + return TMG_IGNORE; } bool Arch::isGlobalNet(const NetInfo *net) const diff --git a/xc7/arch.h b/xc7/arch.h index 411be954..5f3988a5 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -592,7 +592,7 @@ struct Arch : BaseCtx { WireRange range; range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; + range.e.cursor = 0; //chip_info->num_wires; return range; } From 8cddc49abc74051834d3da4dd1712d3bf81943f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 18:52:48 -0700 Subject: [PATCH 008/174] Starts placement onto all Xilinx sites --- xc7/arch.cc | 61 +++++++++++----------- xc7/arch.h | 60 +++++++++++----------- xc7/arch_place.cc | 126 +++++++++++++++++++++++----------------------- xc7/archdefs.h | 5 +- 4 files changed, 127 insertions(+), 125 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 52d88326..31b02a9e 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -32,6 +32,12 @@ NEXTPNR_NAMESPACE_BEGIN + +const DDB *ddb = nullptr; +const Sites *ddbSites = nullptr; +const Tiles *ddbTiles = nullptr; + + // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) @@ -61,6 +67,9 @@ Arch::Arch(ArchArgs args) : args(args) // } // if (package_info == nullptr) // log_error("Unsupported package '%s'.\n", args.package.c_str()); + + ddbSites = &ddb->getSites(); + ddbTiles = &ddb->getTiles(); } // ----------------------------------------------------------------------- @@ -89,14 +98,9 @@ BelId Arch::getBelByName(IdString name) const { BelId ret; - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[id(chip_info->bel_data[i].name.get())] = i; - } - - auto it = bel_by_name.find(name); - if (it != bel_by_name.end()) - ret.index = it->second; + auto it = ddbSites->findSiteIndex(name.str(this)); + if (it != SiteIndex(-1)) + ret.index = it; return ret; } @@ -106,32 +110,29 @@ BelId Arch::getBelByLocation(Loc loc) const BelId bel; if (bel_by_loc.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) { + for (SiteIndex i(0); i < ddbSites->getSiteCount(); ++i) { BelId b; b.index = i; - bel_by_loc[getBelLocation(b)] = i; + bel_by_loc[getBelLocation(b)] = b; } } auto it = bel_by_loc.find(loc); if (it != bel_by_loc.end()) - bel.index = it->second; + bel = it->second; return bel; } BelRange Arch::getBelsByTile(int x, int y) const { - // In iCE40 chipdb bels at the same tile are consecutive and dense z ordinates - // are used BelRange br; - br.b.cursor = Arch::getBelByLocation(Loc(x, y, 0)).index; + br.b.cursor = std::next(ddbSites->getSites().begin(), Arch::getBelByLocation(Loc(x, y, 0)).index); br.e.cursor = br.b.cursor; - if (br.e.cursor != -1) { - while (br.e.cursor < chip_info->num_bels && chip_info->bel_data[br.e.cursor].x == x && - chip_info->bel_data[br.e.cursor].y == y) + if (br.e.cursor != ddbSites->getSites().end()) { + while (br.e.cursor < ddbSites->getSites().end() && ddbSites->getSite((*br.e).index).getTileIndex() == ddbSites->getSite((*br.b).index).getTileIndex()) br.e.cursor++; } @@ -316,23 +317,23 @@ IdString Arch::getPipName(PipId pip) const BelId Arch::getPackagePinBel(const std::string &pin) const { - for (int i = 0; i < package_info->num_pins; i++) { - if (package_info->pins[i].name.get() == pin) { - BelId id; - id.index = package_info->pins[i].bel_index; - return id; - } - } +// for (int i = 0; i < package_info->num_pins; i++) { +// if (package_info->pins[i].name.get() == pin) { +// BelId id; +// id.index = package_info->pins[i].bel_index; +// return id; +// } +// } return BelId(); } std::string Arch::getBelPackagePin(BelId bel) const { - for (int i = 0; i < package_info->num_pins; i++) { - if (package_info->pins[i].bel_index == bel.index) { - return std::string(package_info->pins[i].name.get()); - } - } +// for (int i = 0; i < package_info->num_pins; i++) { +// if (package_info->pins[i].bel_index == bel.index) { +// return std::string(package_info->pins[i].name.get()); +// } +// } return ""; } @@ -617,7 +618,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const if (decal.type == DecalId::TYPE_BEL) { BelId bel; - bel.index = decal.index; + bel.index = SiteIndex(decal.index); auto bel_type = getBelType(bel); diff --git a/xc7/arch.h b/xc7/arch.h index 5f3988a5..810ff4d5 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -24,6 +24,7 @@ #include "torc/Architecture.hpp" #include "torc/Common.hpp" using namespace torc::architecture; +using namespace torc::architecture::xilinx; NEXTPNR_NAMESPACE_BEGIN @@ -231,23 +232,17 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { RelPtr cell_timing; }); -#if defined(_MSC_VER) -extern const char *chipdb_blob_384; -extern const char *chipdb_blob_1k; -extern const char *chipdb_blob_5k; -extern const char *chipdb_blob_8k; -#else -extern const char chipdb_blob_384[]; -extern const char chipdb_blob_1k[]; -extern const char chipdb_blob_5k[]; -extern const char chipdb_blob_8k[]; -#endif + +extern const DDB *ddb; +extern const Sites *ddbSites; +extern const Tiles *ddbTiles; + /************************ End of chipdb section. ************************/ struct BelIterator { - int cursor; + Array::iterator cursor; BelIterator operator++() { @@ -268,7 +263,7 @@ struct BelIterator BelId operator*() const { BelId ret; - ret.index = cursor; + ret.index = SiteIndex(std::distance(ddbSites->getSites().begin(), cursor)); return ret; } }; @@ -284,16 +279,17 @@ struct BelRange struct BelPinIterator { - const BelPortPOD *ptr = nullptr; + const BelId bel; + Array::iterator it; - void operator++() { ptr++; } - bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; } + void operator++() { it++; } + bool operator!=(const BelPinIterator &other) const { return it != other.it && bel != other.bel; } BelPin operator*() const { BelPin ret; - ret.bel.index = ptr->bel_index; - ret.pin = ptr->port; + ret.bel = bel; + ret.pin = IdString(); return ret; } }; @@ -391,13 +387,11 @@ struct Arch : BaseCtx { bool fast_part; const ChipInfoPOD *chip_info; - const DDB *ddb; const PackageInfoPOD *package_info; - mutable std::unordered_map bel_by_name; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; - mutable std::unordered_map bel_by_loc; + mutable std::unordered_map bel_by_loc; std::vector bel_carry; std::vector bel_to_cell; @@ -428,7 +422,7 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(chip_info->bel_data[bel.index].name.get()); + return id(ddbSites->getSite(bel.index).getName()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -477,17 +471,19 @@ struct Arch : BaseCtx BelRange getBels() const { BelRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_bels; + range.b.cursor = ddbSites->getSites().begin(); + range.e.cursor = ddbSites->getSites().end(); return range; } Loc getBelLocation(BelId bel) const { + const auto& site = ddbSites->getSite(bel.index); + const auto& tile_info = ddbTiles->getTileInfo(site.getTileIndex()); Loc loc; - loc.x = chip_info->bel_data[bel.index].x; - loc.y = chip_info->bel_data[bel.index].y; - loc.z = chip_info->bel_data[bel.index].z; + loc.x = tile_info.getCol(); + loc.y = tile_info.getRow(); + loc.z = 0; return loc; } @@ -499,7 +495,9 @@ struct Arch : BaseCtx IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return IdString(chip_info->bel_data[bel.index].type); + const auto& site = ddbSites->getSite(bel.index); + const auto& tile_info = ddbTiles->getTileInfo(site.getTileIndex()); + return id(ddbTiles->getTileTypeName(tile_info.getTypeIndex())); } WireId getBelPinWire(BelId bel, IdString pin) const; @@ -582,9 +580,9 @@ struct Arch : BaseCtx BelPinRange getWireBelPins(WireId wire) const { BelPinRange range; - NPNR_ASSERT(wire != WireId()); - range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); - range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; + //NPNR_ASSERT(wire != WireId()); + //range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); + //range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; return range; } diff --git a/xc7/arch_place.cc b/xc7/arch_place.cc index c69fd34f..ca98fa18 100644 --- a/xc7/arch_place.cc +++ b/xc7/arch_place.cc @@ -93,70 +93,70 @@ bool Arch::isBelLocationValid(BelId bel) const bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == id_ICESTORM_LC) { - NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); - - std::array bel_cells; - size_t num_cells = 0; - - Loc bel_loc = getBelLocation(bel); - for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { - CellInfo *ci_other = getBoundBelCell(bel_other); - if (ci_other != nullptr && bel_other != bel) - bel_cells[num_cells++] = ci_other; - } - - bel_cells[num_cells++] = cell; - return logicCellsCompatible(bel_cells.data(), num_cells); - } else if (cell->type == id_SB_IO) { - // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. - - // Find shared PLL by looking for driving bel siblings from D_IN_0 - // that are a PLL clock output. - auto wire = getBelPinWire(bel, id_D_IN_0); - IdString pll_bel_pin; - BelId pll_bel; - for (auto pin : getWireBelPins(wire)) { - if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { - pll_bel = pin.bel; - pll_bel_pin = pin.pin; - break; - } - } - // Is there a PLL that shares this IO buffer? - if (pll_bel.index != -1) { - auto pll_cell = getBoundBelCell(pll_bel); - // Is a PLL placed in this PLL bel? - if (pll_cell != nullptr) { - // Is the shared port driving a net? - auto pi = pll_cell->ports[pll_bel_pin]; - if (pi.net != nullptr) { - // Are we perhaps a PAD INPUT Bel that can be placed here? - if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { - return true; - } - return false; - } - } - } - return getBelPackagePin(bel) != ""; - } else if (cell->type == id_SB_GB) { - NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); - const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; - IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); - int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); - if (net->is_reset && net->is_enable) - return false; - else if (net->is_reset) - return (glb_id % 2) == 0; - else if (net->is_enable) - return (glb_id % 2) == 1; - else - return true; - } else { - // TODO: IO cell clock checks +// if (cell->type == id_ICESTORM_LC) { +// NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); +// +// std::array bel_cells; +// size_t num_cells = 0; +// +// Loc bel_loc = getBelLocation(bel); +// for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { +// CellInfo *ci_other = getBoundBelCell(bel_other); +// if (ci_other != nullptr && bel_other != bel) +// bel_cells[num_cells++] = ci_other; +// } +// +// bel_cells[num_cells++] = cell; +// return logicCellsCompatible(bel_cells.data(), num_cells); +// } else if (cell->type == id_SB_IO) { +// // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. +// +// // Find shared PLL by looking for driving bel siblings from D_IN_0 +// // that are a PLL clock output. +// auto wire = getBelPinWire(bel, id_D_IN_0); +// IdString pll_bel_pin; +// BelId pll_bel; +// for (auto pin : getWireBelPins(wire)) { +// if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { +// pll_bel = pin.bel; +// pll_bel_pin = pin.pin; +// break; +// } +// } +// // Is there a PLL that shares this IO buffer? +// if (pll_bel.index != -1) { +// auto pll_cell = getBoundBelCell(pll_bel); +// // Is a PLL placed in this PLL bel? +// if (pll_cell != nullptr) { +// // Is the shared port driving a net? +// auto pi = pll_cell->ports[pll_bel_pin]; +// if (pi.net != nullptr) { +// // Are we perhaps a PAD INPUT Bel that can be placed here? +// if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { +// return true; +// } +// return false; +// } +// } +// } +// return getBelPackagePin(bel) != ""; +// } else if (cell->type == id_SB_GB) { +// NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); +// const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; +// IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); +// int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); +// if (net->is_reset && net->is_enable) +// return false; +// else if (net->is_reset) +// return (glb_id % 2) == 0; +// else if (net->is_enable) +// return (glb_id % 2) == 1; +// else +// return true; +// } else { +// // TODO: IO cell clock checks return true; - } +// } } NEXTPNR_NAMESPACE_END diff --git a/xc7/archdefs.h b/xc7/archdefs.h index 360617fd..757d0d61 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -21,6 +21,9 @@ #error Include "archdefs.h" via "nextpnr.h" only. #endif +#include "torc/Architecture.hpp" +using namespace torc::architecture::xilinx; + NEXTPNR_NAMESPACE_BEGIN typedef int delay_t; @@ -62,7 +65,7 @@ enum ConstIds struct BelId { - int32_t index = -1; + SiteIndex index = SiteIndex(-1); bool operator==(const BelId &other) const { return index == other.index; } bool operator!=(const BelId &other) const { return index != other.index; } From 2bc7ffc2ea86a9074b5271b16af0fcfb592a86e6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 21:13:49 -0700 Subject: [PATCH 009/174] WIP --- xc7/arch.cc | 54 +++--- xc7/arch.h | 10 +- xc7/arch_place.cc | 70 ++++---- xc7/blinky.v | 4 +- xc7/cells.cc | 429 ++++++++++++++++++++++++---------------------- xc7/cells.h | 16 +- xc7/constids.inc | 18 ++ xc7/pack.cc | 36 ++-- 8 files changed, 327 insertions(+), 310 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 31b02a9e..fd0eb6bd 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -70,6 +70,8 @@ Arch::Arch(ArchArgs args) : args(args) ddbSites = &ddb->getSites(); ddbTiles = &ddb->getTiles(); + + bel_to_cell.resize(ddbSites->getSiteCount()); } // ----------------------------------------------------------------------- @@ -171,32 +173,32 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - NPNR_ASSERT(bel != BelId()); - - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - - if (num_bel_wires < 7) { - for (int i = 0; i < num_bel_wires; i++) { - if (bel_wires[i].port == pin.index) { - ret.index = bel_wires[i].wire_index; - break; - } - } - } else { - int b = 0, e = num_bel_wires - 1; - while (b <= e) { - int i = (b + e) / 2; - if (bel_wires[i].port == pin.index) { - ret.index = bel_wires[i].wire_index; - break; - } - if (bel_wires[i].port > pin.index) - e = i - 1; - else - b = i + 1; - } - } +// NPNR_ASSERT(bel != BelId()); +// +// int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; +// const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); +// +// if (num_bel_wires < 7) { +// for (int i = 0; i < num_bel_wires; i++) { +// if (bel_wires[i].port == pin.index) { +// ret.index = bel_wires[i].wire_index; +// break; +// } +// } +// } else { +// int b = 0, e = num_bel_wires - 1; +// while (b <= e) { +// int i = (b + e) / 2; +// if (bel_wires[i].port == pin.index) { +// ret.index = bel_wires[i].wire_index; +// break; +// } +// if (bel_wires[i].port > pin.index) +// e = i - 1; +// else +// b = i + 1; +// } +// } return ret; } diff --git a/xc7/arch.h b/xc7/arch.h index 810ff4d5..c16040f5 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -433,7 +433,7 @@ struct Arch : BaseCtx NPNR_ASSERT(bel_to_cell[bel.index] == nullptr); bel_to_cell[bel.index] = cell; - bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable); + //bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable); cell->bel = bel; cell->belStrength = strength; refreshUiBel(bel); @@ -446,7 +446,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index]->bel = BelId(); bel_to_cell[bel.index]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = nullptr; - bel_carry[bel.index] = false; + //bel_carry[bel.index] = false; refreshUiBel(bel); } @@ -490,14 +490,14 @@ struct Arch : BaseCtx BelId getBelByLocation(Loc loc) const; BelRange getBelsByTile(int x, int y) const; - bool getBelGlobalBuf(BelId bel) const { return chip_info->bel_data[bel.index].type == ID_SB_GB; } + bool getBelGlobalBuf(BelId bel) const { return getBelType(bel) == id_BUFGCTRL; } IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); const auto& site = ddbSites->getSite(bel.index); - const auto& tile_info = ddbTiles->getTileInfo(site.getTileIndex()); - return id(ddbTiles->getTileTypeName(tile_info.getTypeIndex())); + auto prim_def = site.getPrimitiveDefPtr(); + return id(prim_def->getName()); } WireId getBelPinWire(BelId bel, IdString pin) const; diff --git a/xc7/arch_place.cc b/xc7/arch_place.cc index ca98fa18..463e8312 100644 --- a/xc7/arch_place.cc +++ b/xc7/arch_place.cc @@ -29,45 +29,37 @@ NEXTPNR_NAMESPACE_BEGIN bool Arch::logicCellsCompatible(const CellInfo** it, const size_t size) const { - bool dffs_exist = false, dffs_neg = false; - const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; - int locals_count = 0; - - for (auto cell : boost::make_iterator_range(it, it+size)) { - NPNR_ASSERT(cell->belType == id_ICESTORM_LC); - if (cell->lcInfo.dffEnable) { - if (!dffs_exist) { - dffs_exist = true; - cen = cell->lcInfo.cen; - clk = cell->lcInfo.clk; - sr = cell->lcInfo.sr; - - if (cen != nullptr && !cen->is_global) - locals_count++; - if (clk != nullptr && !clk->is_global) - locals_count++; - if (sr != nullptr && !sr->is_global) - locals_count++; - - if (cell->lcInfo.negClk) { - dffs_neg = true; - } - } else { - if (cen != cell->lcInfo.cen) - return false; - if (clk != cell->lcInfo.clk) - return false; - if (sr != cell->lcInfo.sr) - return false; - if (dffs_neg != cell->lcInfo.negClk) - return false; - } - } - - locals_count += cell->lcInfo.inputCount; - } - - return locals_count <= 32; +// bool dffs_exist = false, dffs_neg = false; +// const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; +// +// for (auto cell : boost::make_iterator_range(it, it+size)) { +// NPNR_ASSERT(cell->belType == id_ICESTORM_LC); +// if (cell->lcInfo.dffEnable) { +// if (!dffs_exist) { +// dffs_exist = true; +// cen = cell->lcInfo.cen; +// clk = cell->lcInfo.clk; +// sr = cell->lcInfo.sr; +// +// if (cell->lcInfo.negClk) { +// dffs_neg = true; +// } +// } else { +// if (cen != cell->lcInfo.cen) +// return false; +// if (clk != cell->lcInfo.clk) +// return false; +// if (sr != cell->lcInfo.sr) +// return false; +// if (dffs_neg != cell->lcInfo.negClk) +// return false; +// } +// } +// locals_count += cell->lcInfo.inputCount; +// } +// +// return locals_count <= 32; + return true; } bool Arch::isBelLocationValid(BelId bel) const diff --git a/xc7/blinky.v b/xc7/blinky.v index daaac373..f636bfcb 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -7,8 +7,8 @@ module blinky ( output led5 ); - BUFG clk_gb ( - .I(clki), + BUFGCTRL clk_gb ( + .I0(clki), .O(clk) ); diff --git a/xc7/cells.cc b/xc7/cells.cc index 5bdc7990..07f33f0c 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -22,6 +22,7 @@ #include "cells.h" #include "design_utils.h" #include "log.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -41,7 +42,8 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri new_cell->name = ctx->id(name); } new_cell->type = type; - if (type == ctx->id("ICESTORM_LC")) { + if (type == ctx->id("XC7_LC")) { + new_cell->type = id_SLICEL; // HACK HACK HACK: Place one LC into each slice new_cell->params[ctx->id("LUT_INIT")] = "0"; new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; @@ -55,195 +57,201 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "I1", PORT_IN); add_port(ctx, new_cell.get(), "I2", PORT_IN); add_port(ctx, new_cell.get(), "I3", PORT_IN); + add_port(ctx, new_cell.get(), "I4", PORT_IN); + add_port(ctx, new_cell.get(), "I5", PORT_IN); add_port(ctx, new_cell.get(), "CIN", PORT_IN); add_port(ctx, new_cell.get(), "CLK", PORT_IN); - add_port(ctx, new_cell.get(), "CEN", PORT_IN); + add_port(ctx, new_cell.get(), "CE", PORT_IN); add_port(ctx, new_cell.get(), "SR", PORT_IN); - add_port(ctx, new_cell.get(), "LO", PORT_OUT); add_port(ctx, new_cell.get(), "O", PORT_OUT); + add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); + add_port(ctx, new_cell.get(), "OQ", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); - } else if (type == ctx->id("SB_IO")) { + } else if (type == ctx->id("IOBUF")) { + new_cell->type = id_IOB33S; new_cell->params[ctx->id("PIN_TYPE")] = "0"; new_cell->params[ctx->id("PULLUP")] = "0"; new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; - add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); - - add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); - add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); - add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); - add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); - - add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); - add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); - add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); - - add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); - add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); - } else if (type == ctx->id("ICESTORM_RAM")) { - new_cell->params[ctx->id("NEG_CLK_W")] = "0"; - new_cell->params[ctx->id("NEG_CLK_R")] = "0"; - new_cell->params[ctx->id("WRITE_MODE")] = "0"; - new_cell->params[ctx->id("READ_MODE")] = "0"; - - add_port(ctx, new_cell.get(), "RCLK", PORT_IN); - add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); - add_port(ctx, new_cell.get(), "RE", PORT_IN); - - add_port(ctx, new_cell.get(), "WCLK", PORT_IN); - add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); - add_port(ctx, new_cell.get(), "WE", PORT_IN); - - for (int i = 0; i < 16; i++) { - add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); - } - - for (int i = 0; i < 11; i++) { - add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); - } - } else if (type == ctx->id("ICESTORM_LFOSC")) { - add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); - add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); - add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); - add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); - } else if (type == ctx->id("ICESTORM_HFOSC")) { - new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; - new_cell->params[ctx->id("TRIM_EN")] = "0b0"; - - add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); - add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); - add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); - add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); - for (int i = 0; i < 10; i++) - add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); - } else if (type == ctx->id("SB_GB")) { - add_port(ctx, new_cell.get(), "USER_SIGNAL_TO_GLOBAL_BUFFER", PORT_IN); - add_port(ctx, new_cell.get(), "GLOBAL_BUFFER_OUTPUT", PORT_OUT); - } else if (type == ctx->id("ICESTORM_SPRAM")) { - add_port(ctx, new_cell.get(), "WREN", PORT_IN); - add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); - add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); - add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); - add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); - add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); - - for (int i = 0; i < 16; i++) { - add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); - } - for (int i = 0; i < 14; i++) { - add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); - } - for (int i = 0; i < 4; i++) { - add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); - } - } else if (type == ctx->id("ICESTORM_DSP")) { - new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; - - new_cell->params[ctx->id("C_REG")] = "0"; - new_cell->params[ctx->id("A_REG")] = "0"; - new_cell->params[ctx->id("B_REG")] = "0"; - new_cell->params[ctx->id("D_REG")] = "0"; - new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; - new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; - new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; - new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; - - new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; - new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; - - new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; - new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; - - new_cell->params[ctx->id("MODE_8x8")] = "0"; - new_cell->params[ctx->id("A_SIGNED")] = "0"; - new_cell->params[ctx->id("B_SIGNED")] = "0"; - - add_port(ctx, new_cell.get(), "CLK", PORT_IN); - add_port(ctx, new_cell.get(), "CE", PORT_IN); - for (int i = 0; i < 16; i++) { - add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); - add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); - } - add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); - add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); - add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); - add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); - - add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); - add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); - add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); - add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); - - add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); - add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); - - add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); - add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); - - add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); - add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); - - add_port(ctx, new_cell.get(), "CI", PORT_IN); - add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); - add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); - - for (int i = 0; i < 32; i++) { - add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); - } - - add_port(ctx, new_cell.get(), "CO", PORT_OUT); - add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); - add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); - - } else if (type == ctx->id("ICESTORM_PLL")) { - new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; - new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; - - new_cell->params[ctx->id("DIVF")] = "0"; - new_cell->params[ctx->id("DIVQ")] = "0"; - new_cell->params[ctx->id("DIVR")] = "0"; - - new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; - new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; - new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; - new_cell->params[ctx->id("FILTER_RANGE")] = "0"; - - new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; - new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; - - new_cell->params[ctx->id("PLLTYPE")] = "0"; - new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; - new_cell->params[ctx->id("TEST_MODE")] = "0"; - - add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); - add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); - add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); - add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); - add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); - add_port(ctx, new_cell.get(), "RESETB", PORT_IN); - - add_port(ctx, new_cell.get(), "SCLK", PORT_IN); - add_port(ctx, new_cell.get(), "SDI", PORT_IN); - add_port(ctx, new_cell.get(), "SDI", PORT_OUT); - - add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); - add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); - add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); +// add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); +// +// add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); +// add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); +// add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); +// add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); +// +// add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); +// add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); +// add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); +// +// add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); +// add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); + add_port(ctx, new_cell.get(), "I", PORT_OUT); + add_port(ctx, new_cell.get(), "O", PORT_IN); +// } else if (type == ctx->id("ICESTORM_RAM")) { +// new_cell->params[ctx->id("NEG_CLK_W")] = "0"; +// new_cell->params[ctx->id("NEG_CLK_R")] = "0"; +// new_cell->params[ctx->id("WRITE_MODE")] = "0"; +// new_cell->params[ctx->id("READ_MODE")] = "0"; +// +// add_port(ctx, new_cell.get(), "RCLK", PORT_IN); +// add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); +// add_port(ctx, new_cell.get(), "RE", PORT_IN); +// +// add_port(ctx, new_cell.get(), "WCLK", PORT_IN); +// add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); +// add_port(ctx, new_cell.get(), "WE", PORT_IN); +// +// for (int i = 0; i < 16; i++) { +// add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); +// } +// +// for (int i = 0; i < 11; i++) { +// add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); +// } +// } else if (type == ctx->id("ICESTORM_LFOSC")) { +// add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); +// add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); +// add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); +// add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); +// } else if (type == ctx->id("ICESTORM_HFOSC")) { +// new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; +// new_cell->params[ctx->id("TRIM_EN")] = "0b0"; +// +// add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); +// add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); +// add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); +// add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); +// for (int i = 0; i < 10; i++) +// add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); + } else if (type == ctx->id("BUFGCTRL")) { + add_port(ctx, new_cell.get(), "I0", PORT_IN); + add_port(ctx, new_cell.get(), "O", PORT_OUT); +// } else if (type == ctx->id("ICESTORM_SPRAM")) { +// add_port(ctx, new_cell.get(), "WREN", PORT_IN); +// add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); +// add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); +// add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); +// add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); +// add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); +// +// for (int i = 0; i < 16; i++) { +// add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); +// } +// for (int i = 0; i < 14; i++) { +// add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); +// } +// for (int i = 0; i < 4; i++) { +// add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); +// } +// } else if (type == ctx->id("ICESTORM_DSP")) { +// new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; +// +// new_cell->params[ctx->id("C_REG")] = "0"; +// new_cell->params[ctx->id("A_REG")] = "0"; +// new_cell->params[ctx->id("B_REG")] = "0"; +// new_cell->params[ctx->id("D_REG")] = "0"; +// new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; +// new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; +// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; +// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; +// +// new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; +// new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; +// new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; +// new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; +// +// new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; +// new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; +// new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; +// new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; +// +// new_cell->params[ctx->id("MODE_8x8")] = "0"; +// new_cell->params[ctx->id("A_SIGNED")] = "0"; +// new_cell->params[ctx->id("B_SIGNED")] = "0"; +// +// add_port(ctx, new_cell.get(), "CLK", PORT_IN); +// add_port(ctx, new_cell.get(), "CE", PORT_IN); +// for (int i = 0; i < 16; i++) { +// add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); +// add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); +// } +// add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); +// add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); +// add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); +// add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); +// +// add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); +// add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); +// add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); +// add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); +// +// add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); +// add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); +// +// add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); +// add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); +// +// add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); +// add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); +// +// add_port(ctx, new_cell.get(), "CI", PORT_IN); +// add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); +// add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); +// +// for (int i = 0; i < 32; i++) { +// add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); +// } +// +// add_port(ctx, new_cell.get(), "CO", PORT_OUT); +// add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); +// add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); +// +// } else if (type == ctx->id("ICESTORM_PLL")) { +// new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; +// new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; +// +// new_cell->params[ctx->id("DIVF")] = "0"; +// new_cell->params[ctx->id("DIVQ")] = "0"; +// new_cell->params[ctx->id("DIVR")] = "0"; +// +// new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; +// new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; +// new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; +// new_cell->params[ctx->id("FILTER_RANGE")] = "0"; +// +// new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; +// new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; +// +// new_cell->params[ctx->id("PLLTYPE")] = "0"; +// new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; +// new_cell->params[ctx->id("TEST_MODE")] = "0"; +// +// add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); +// add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); +// add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); +// add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); +// add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); +// add_port(ctx, new_cell.get(), "RESETB", PORT_IN); +// +// add_port(ctx, new_cell.get(), "SCLK", PORT_IN); +// add_port(ctx, new_cell.get(), "SDI", PORT_IN); +// add_port(ctx, new_cell.get(), "SDI", PORT_OUT); +// +// add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); +// add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); +// add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); } else { - log_error("unable to create iCE40 cell of type %s", type.c_str(ctx)); + log_error("unable to create XC7 cell of type %s\n", type.c_str(ctx)); } return new_cell; } @@ -252,9 +260,16 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; replace_port(lut, ctx->id("I0"), lc, ctx->id("I0")); - replace_port(lut, ctx->id("I1"), lc, ctx->id("I1")); - replace_port(lut, ctx->id("I2"), lc, ctx->id("I2")); - replace_port(lut, ctx->id("I3"), lc, ctx->id("I3")); + if (get_net_or_empty(lut, ctx->id("I1"))) + replace_port(lut, ctx->id("I1"), lc, ctx->id("I1")); + if (get_net_or_empty(lut, ctx->id("I2"))) + replace_port(lut, ctx->id("I2"), lc, ctx->id("I2")); + if (get_net_or_empty(lut, ctx->id("I3"))) + replace_port(lut, ctx->id("I3"), lc, ctx->id("I3")); + if (get_net_or_empty(lut, ctx->id("I4"))) + replace_port(lut, ctx->id("I4"), lc, ctx->id("I3")); + if (get_net_or_empty(lut, ctx->id("I5"))) + replace_port(lut, ctx->id("I5"), lc, ctx->id("I3")); if (no_dff) { replace_port(lut, ctx->id("O"), lc, ctx->id("O")); lc->params[ctx->id("DFF_ENABLE")] = "0"; @@ -264,43 +279,41 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) { lc->params[ctx->id("DFF_ENABLE")] = "1"; - std::string config = dff->type.str(ctx).substr(6); + std::string config = dff->type.str(ctx).substr(2); auto citer = config.begin(); replace_port(dff, ctx->id("C"), lc, ctx->id("CLK")); - if (citer != config.end() && *citer == 'N') { - lc->params[ctx->id("NEG_CLK")] = "1"; - ++citer; - } else { - lc->params[ctx->id("NEG_CLK")] = "0"; - } - - if (citer != config.end() && *citer == 'E') { - replace_port(dff, ctx->id("E"), lc, ctx->id("CEN")); - ++citer; - } - if (citer != config.end()) { - if ((config.end() - citer) >= 2) { - char c = *(citer++); - NPNR_ASSERT(c == 'S'); - lc->params[ctx->id("ASYNC_SR")] = "0"; - } else { + if (*citer == 'C' || *citer == 'P') lc->params[ctx->id("ASYNC_SR")] = "1"; - } + else + lc->params[ctx->id("ASYNC_SR")] = "0"; if (*citer == 'S') { citer++; replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); lc->params[ctx->id("SET_NORESET")] = "1"; - } else { - NPNR_ASSERT(*citer == 'R'); + } else if (*citer == 'R') { citer++; replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); lc->params[ctx->id("SET_NORESET")] = "0"; + } else if (*citer == 'C') { + citer++; + replace_port(dff, ctx->id("CLR"), lc, ctx->id("SR")); + lc->params[ctx->id("SET_NORESET")] = "0"; + } else { + NPNR_ASSERT(*citer == 'P'); + citer++; + replace_port(dff, ctx->id("PRE"), lc, ctx->id("SR")); + lc->params[ctx->id("SET_NORESET")] = "1"; } } + if (citer != config.end() && *citer == 'E') { + replace_port(dff, ctx->id("CE"), lc, ctx->id("CE")); + ++citer; + } + NPNR_ASSERT(citer == config.end()); if (pass_thru_lut) { @@ -308,7 +321,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l replace_port(dff, ctx->id("D"), lc, ctx->id("I0")); } - replace_port(dff, ctx->id("Q"), lc, ctx->id("O")); + replace_port(dff, ctx->id("Q"), lc, ctx->id("OQ")); } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) @@ -318,25 +331,25 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) auto pu_attr = nxio->attrs.find(ctx->id("PULLUP")); if (pu_attr != nxio->attrs.end()) sbio->params[ctx->id("PULLUP")] = pu_attr->second; - replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); + replace_port(nxio, ctx->id("O"), sbio, ctx->id("I")); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { sbio->params[ctx->id("PIN_TYPE")] = "25"; - replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); + replace_port(nxio, ctx->id("I"), sbio, ctx->id("O")); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below sbio->params[ctx->id("PIN_TYPE")] = "25"; - replace_port(nxio, ctx->id("I"), sbio, ctx->id("D_OUT_0")); - replace_port(nxio, ctx->id("O"), sbio, ctx->id("D_IN_0")); + replace_port(nxio, ctx->id("I"), sbio, ctx->id("O")); + replace_port(nxio, ctx->id("O"), sbio, ctx->id("I")); } else { NPNR_ASSERT(false); } - NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net; + NetInfo *donet = sbio->ports.at(ctx->id("O")).net; CellInfo *tbuf = net_driven_by( ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, ctx->id("Y")); if (tbuf) { sbio->params[ctx->id("PIN_TYPE")] = "41"; - replace_port(tbuf, ctx->id("A"), sbio, ctx->id("D_OUT_0")); + replace_port(tbuf, ctx->id("A"), sbio, ctx->id("O")); replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE")); ctx->nets.erase(donet->name); if (!donet->users.empty()) diff --git a/xc7/cells.h b/xc7/cells.h index 16135448..2a1d8f90 100644 --- a/xc7/cells.h +++ b/xc7/cells.h @@ -30,31 +30,23 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT -inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); } +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_LUT1 || cell->type == id_LUT2 || cell->type == id_LUT3 || cell->type == id_LUT4 || cell->type == id_LUT5 || cell->type == id_LUT6; } // Return true if a cell is a flipflop inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) { - return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") || - cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") || - cell->type == ctx->id("SB_DFFESR") || cell->type == ctx->id("SB_DFFER") || - cell->type == ctx->id("SB_DFFESS") || cell->type == ctx->id("SB_DFFES") || - cell->type == ctx->id("SB_DFFN") || cell->type == ctx->id("SB_DFFNE") || - cell->type == ctx->id("SB_DFFNSR") || cell->type == ctx->id("SB_DFFNR") || - cell->type == ctx->id("SB_DFFNSS") || cell->type == ctx->id("SB_DFFNS") || - cell->type == ctx->id("SB_DFFNESR") || cell->type == ctx->id("SB_DFFNER") || - cell->type == ctx->id("SB_DFFNESS") || cell->type == ctx->id("SB_DFFNES"); + return cell->type == id_FDRE || cell->type == id_FDSE || cell->type == id_FDCE || cell->type == id_FDPE; } inline bool is_carry(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); } -inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); } +inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("XC7_LC"); } // Return true if a cell is a SB_IO inline bool is_sb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); } // Return true if a cell is a global buffer -inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); } +inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("BUFGCTRL"); } // Return true if a cell is a RAM inline bool is_ram(const BaseCtx *ctx, const CellInfo *cell) diff --git a/xc7/constids.inc b/xc7/constids.inc index adcea7ad..10543fb3 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -435,3 +435,21 @@ X(ICESTORM_SPRAM) X(DFF_ENABLE) X(CARRY_ENABLE) X(NEG_CLK) + +X(LUT1) +X(LUT2) +X(LUT3) +X(LUT4) +X(LUT5) +X(LUT6) + +X(FDRE) +X(FDSE) +X(FDCE) +X(FDPE) + +X(BUFGCTRL) +X(SLICEL) +X(IOBUF) +X(IOB33S) +X(IOB33M) // What is the difference between IOB33S and IOB33M? diff --git a/xc7/pack.cc b/xc7/pack.cc index 05338713..e8207210 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -42,7 +42,7 @@ static void pack_lut_lutffs(Context *ctx) if (ctx->verbose) log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); if (is_lut(ctx, ci)) { - std::unique_ptr packed = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_LC"); + std::unique_ptr packed = create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); if (ctx->verbose) @@ -97,7 +97,7 @@ static void pack_nonlut_ffs(Context *ctx) CellInfo *ci = cell.second; if (is_ff(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), ci->name.str(ctx) + "_DFFLC"); + create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); if (ctx->verbose) log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); @@ -192,7 +192,7 @@ static void pack_carries(Context *ctx) } else { // No LC to pack into matching I0/I1, insert a new one std::unique_ptr created_lc = - create_ice_cell(ctx, ctx->id("ICESTORM_LC"), cell.first.str(ctx) + "$CARRY"); + create_ice_cell(ctx, ctx->id("XC7_LC"), cell.first.str(ctx) + "$CARRY"); carry_lc = created_lc.get(); created_lc->ports.at(ctx->id("I1")).net = i0_net; if (i0_net) { @@ -331,7 +331,7 @@ static void pack_constants(Context *ctx) { log_info("Packing constants..\n"); - std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_GND"); + std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_GND"); gnd_cell->params[ctx->id("LUT_INIT")] = "0"; std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); @@ -339,7 +339,7 @@ static void pack_constants(Context *ctx) gnd_net->driver.port = ctx->id("O"); gnd_cell->ports.at(ctx->id("O")).net = gnd_net.get(); - std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), "$PACKER_VCC"); + std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); vcc_cell->params[ctx->id("LUT_INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); @@ -405,9 +405,9 @@ static void pack_io(Context *ctx) sb = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_sb_io, ctx->id("PACKAGE_PIN"), true, ci); } if (sb != nullptr) { - // Trivial case, SB_IO used. Just destroy the net and the + // Trivial case, IOBUF used. Just destroy the net and the // iobuf - log_info("%s feeds SB_IO %s, removing %s %s.\n", ci->name.c_str(ctx), sb->name.c_str(ctx), + log_info("%s feeds IOBUF %s, removing %s %s.\n", ci->name.c_str(ctx), sb->name.c_str(ctx), ci->type.c_str(ctx), ci->name.c_str(ctx)); NetInfo *net = sb->ports.at(ctx->id("PACKAGE_PIN")).net; if (net != nullptr) { @@ -421,9 +421,9 @@ static void pack_io(Context *ctx) } } } else { - // Create a SB_IO buffer + // Create a IOBUF buffer std::unique_ptr ice_cell = - create_ice_cell(ctx, ctx->id("SB_IO"), ci->name.str(ctx) + "$sb_io"); + create_ice_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); nxio_to_sb(ctx, ci, ice_cell.get()); new_cells.push_back(std::move(ice_cell)); sb = new_cells.back().get(); @@ -452,19 +452,19 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) { std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); - std::unique_ptr gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name); - gb->ports[ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER")].net = net; + std::unique_ptr gb = create_ice_cell(ctx, id_BUFGCTRL, "$bufg_" + glb_name); + gb->ports[ctx->id("I0")].net = net; PortRef pr; pr.cell = gb.get(); - pr.port = ctx->id("USER_SIGNAL_TO_GLOBAL_BUFFER"); + pr.port = ctx->id("I0"); net->users.push_back(pr); pr.cell = gb.get(); - pr.port = ctx->id("GLOBAL_BUFFER_OUTPUT"); + pr.port = ctx->id("O"); std::unique_ptr glbnet = std::unique_ptr(new NetInfo()); glbnet->name = ctx->id(glb_name); glbnet->driver = pr; - gb->ports[ctx->id("GLOBAL_BUFFER_OUTPUT")].net = glbnet.get(); + gb->ports[ctx->id("O")].net = glbnet.get(); std::vector keep_users; for (auto user : net->users) { if (is_clock_port(ctx, user) || (is_reset && is_reset_port(ctx, user)) || @@ -582,7 +582,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString NPNR_ASSERT(port.net != nullptr); // Create pass-through LUT. - std::unique_ptr pt = create_ice_cell(ctx, ctx->id("ICESTORM_LC"), + std::unique_ptr pt = create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); pt->params[ctx->id("LUT_INIT")] = "65280"; // output is always I3 @@ -596,7 +596,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString // New users of the original cell's port std::vector new_users; for (const auto &user : port.net->users) { - if (onlyNonLUTs && user.cell->type == ctx->id("ICESTORM_LC")) { + if (onlyNonLUTs && user.cell->type == ctx->id("XC7_LC")) { new_users.push_back(user); continue; } @@ -823,7 +823,7 @@ static void pack_special(Context *ctx) unsigned int lut_count = 0; for (const auto &user : port.net->users) { NPNR_ASSERT(user.cell != nullptr); - if (user.cell->type == ctx->id("ICESTORM_LC")) { + if (user.cell->type == ctx->id("XC7_LC")) { found_lut = true; lut_count++; } else { @@ -856,7 +856,7 @@ static void pack_special(Context *ctx) int z = 0; for (const auto &user : port.net->users) { NPNR_ASSERT(user.cell != nullptr); - NPNR_ASSERT(user.cell->type == ctx->id("ICESTORM_LC")); + NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC")); // TODO(q3k): handle when the Bel might be already the // target of another constraint. From 67a0fa11e673015c252f9c8fe655c95f69ea53a7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 21:36:23 -0700 Subject: [PATCH 010/174] Enable timing --- xc7/arch.cc | 39 ++++++++++++++++++++++++++++++++++++--- xc7/cells.h | 2 +- xc7/constids.inc | 7 ++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index fd0eb6bd..7202d1cc 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -677,14 +677,47 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort // Get the port class, also setting clockPort to associated clock if applicable TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const { - return TMG_IGNORE; + if (cell->type == id_SLICEL) { + if (port == id_CLK) + return TMG_CLOCK_INPUT; + if (port == id_CIN) + return TMG_COMB_INPUT; + if (port == id_COUT || port == id_O) + return TMG_COMB_OUTPUT; + if (cell->lcInfo.dffEnable) { + clockPort = id_CLK; + if (port == id_OQ) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; + } else { + if (port == id_O) + return TMG_COMB_OUTPUT; + else + return TMG_COMB_INPUT; + } + // TODO + //if (port == id_OMUX) + } + else if (cell->type == id_IOB33S) { + if (port == id_I) + return TMG_STARTPOINT; + else if (port == id_O) + return TMG_ENDPOINT; + } + else if (cell->type == id_BUFGCTRL) { + if (port == id_O) + return TMG_COMB_OUTPUT; + return TMG_COMB_INPUT; + } + log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } bool Arch::isGlobalNet(const NetInfo *net) const { if (net == nullptr) return false; - return net->driver.cell != nullptr && net->driver.port == id_GLOBAL_BUFFER_OUTPUT; + return net->driver.cell != nullptr && net->driver.cell->type == id_BUFGCTRL && net->driver.port == id_O; } // Assign arch arg info @@ -712,7 +745,7 @@ void Arch::assignArchInfo() void Arch::assignCellInfo(CellInfo *cell) { cell->belType = cell->type; - if (cell->type == id_ICESTORM_LC) { + if (cell->type == id_SLICEL) { cell->lcInfo.dffEnable = bool_or_default(cell->params, id_DFF_ENABLE); cell->lcInfo.carryEnable = bool_or_default(cell->params, id_CARRY_ENABLE); cell->lcInfo.negClk = bool_or_default(cell->params, id_NEG_CLK); diff --git a/xc7/cells.h b/xc7/cells.h index 2a1d8f90..3f671f2a 100644 --- a/xc7/cells.h +++ b/xc7/cells.h @@ -46,7 +46,7 @@ inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type inline bool is_sb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); } // Return true if a cell is a global buffer -inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("BUFGCTRL"); } +inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_BUFGCTRL; } // Return true if a cell is a RAM inline bool is_ram(const BaseCtx *ctx, const CellInfo *cell) diff --git a/xc7/constids.inc b/xc7/constids.inc index 10543fb3..6dd7da6c 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -3,8 +3,11 @@ X(I0) X(I1) X(I2) X(I3) +X(I4) +X(I5) X(O) -X(LO) +X(OQ) +X(OMUX) X(CIN) X(COUT) X(CEN) @@ -436,6 +439,8 @@ X(DFF_ENABLE) X(CARRY_ENABLE) X(NEG_CLK) +X(I) + X(LUT1) X(LUT2) X(LUT3) From 32f5346378530e0e616d77a18cc5c244bf7822df Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 22:23:52 -0700 Subject: [PATCH 011/174] Hacked blinky.ys yosys script --- xc7/blinky.ys | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/xc7/blinky.ys b/xc7/blinky.ys index c4aded99..090b0ab5 100644 --- a/xc7/blinky.ys +++ b/xc7/blinky.ys @@ -1,3 +1,53 @@ read_verilog blinky.v -synth_xilinx -top blinky + +#synth_xilinx -top blinky + +#begin: + read_verilog -lib +/xilinx/cells_sim.v + read_verilog -lib +/xilinx/cells_xtra.v +# read_verilog -lib +/xilinx/brams_bb.v +# read_verilog -lib +/xilinx/drams_bb.v + hierarchy -check -top blinky + +#flatten: (only if -flatten) + proc + flatten + +#coarse: + synth -run coarse + +#bram: +# memory_bram -rules +/xilinx/brams.txt +# techmap -map +/xilinx/brams_map.v +# +#dram: +# memory_bram -rules +/xilinx/drams.txt +# techmap -map +/xilinx/drams_map.v + +fine: + opt -fast -full + memory_map + dffsr2dff +# dff2dffe + opt -full + techmap -map +/techmap.v #-map +/xilinx/arith_map.v + opt -fast + +map_luts: + abc -luts 2:2,3,6:5 #,10,20 [-dff] + clean + +map_cells: + techmap -map +/xilinx/cells_map.v + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT + clean + +check: + hierarchy -check + stat + check -noinit + +#edif: (only if -edif) +# write_edif + write_json blinky.json From 57c273898c7964512bc3090ea559c701fe59cb26 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 11 Aug 2018 22:24:13 -0700 Subject: [PATCH 012/174] Finishes placement now --- xc7/arch.cc | 95 +++++++++++++++++--------------- xc7/arch.h | 95 ++++++++++++++++---------------- xc7/archdefs.h | 7 +-- xc7/cells.cc | 36 ++++++------- xc7/constids.inc | 10 ++++ xc7/delay.cc | 138 +++++++++++++++++++++++------------------------ xc7/pack.cc | 42 ++++++++------- 7 files changed, 225 insertions(+), 198 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 7202d1cc..d7b06c73 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -173,6 +173,9 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; + const auto& site = ddbSites->getSite(bel.index); + ret.index = site.getPinTilewire(pin.str(this)); + // NPNR_ASSERT(bel != BelId()); // // int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; @@ -229,9 +232,9 @@ WireId Arch::getWireByName(IdString name) const wire_by_name[id(chip_info->wire_data[i].name.get())] = i; } - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) - ret.index = it->second; + //auto it = wire_by_name.find(name); + //if (it != wire_by_name.end()) + // ret.index = it->second; return ret; } @@ -239,38 +242,38 @@ WireId Arch::getWireByName(IdString name) const IdString Arch::getWireType(WireId wire) const { NPNR_ASSERT(wire != WireId()); - switch (chip_info->wire_data[wire.index].type) { - case WireInfoPOD::WIRE_TYPE_NONE: - return IdString(); - case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: - return id("GLB2LOCAL"); - case WireInfoPOD::WIRE_TYPE_GLB_NETWK: - return id("GLB_NETWK"); - case WireInfoPOD::WIRE_TYPE_LOCAL: - return id("LOCAL"); - case WireInfoPOD::WIRE_TYPE_LUTFF_IN: - return id("LUTFF_IN"); - case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: - return id("LUTFF_IN_LUT"); - case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: - return id("LUTFF_LOUT"); - case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: - return id("LUTFF_OUT"); - case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: - return id("LUTFF_COUT"); - case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: - return id("LUTFF_GLOBAL"); - case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: - return id("CARRY_IN_MUX"); - case WireInfoPOD::WIRE_TYPE_SP4_V: - return id("SP4_V"); - case WireInfoPOD::WIRE_TYPE_SP4_H: - return id("SP4_H"); - case WireInfoPOD::WIRE_TYPE_SP12_V: - return id("SP12_V"); - case WireInfoPOD::WIRE_TYPE_SP12_H: - return id("SP12_H"); - } +// switch (chip_info->wire_data[wire.index].type) { +// case WireInfoPOD::WIRE_TYPE_NONE: +// return IdString(); +// case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: +// return id("GLB2LOCAL"); +// case WireInfoPOD::WIRE_TYPE_GLB_NETWK: +// return id("GLB_NETWK"); +// case WireInfoPOD::WIRE_TYPE_LOCAL: +// return id("LOCAL"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_IN: +// return id("LUTFF_IN"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: +// return id("LUTFF_IN_LUT"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: +// return id("LUTFF_LOUT"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: +// return id("LUTFF_OUT"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: +// return id("LUTFF_COUT"); +// case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: +// return id("LUTFF_GLOBAL"); +// case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: +// return id("CARRY_IN_MUX"); +// case WireInfoPOD::WIRE_TYPE_SP4_V: +// return id("SP4_V"); +// case WireInfoPOD::WIRE_TYPE_SP4_H: +// return id("SP4_H"); +// case WireInfoPOD::WIRE_TYPE_SP12_V: +// return id("SP12_V"); +// case WireInfoPOD::WIRE_TYPE_SP12_H: +// return id("SP12_H"); +// } return IdString(); } @@ -507,8 +510,8 @@ DecalXY Arch::getWireDecal(WireId wire) const { DecalXY decalxy; decalxy.decal.type = DecalId::TYPE_WIRE; - decalxy.decal.index = wire.index; - decalxy.decal.active = wire_to_net.at(wire.index) != nullptr; + //decalxy.decal.index = wire.index; + //decalxy.decal.active = wire_to_net.at(wire.index) != nullptr; return decalxy; } @@ -671,6 +674,15 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { + if (cell->type == id_SLICEL) + { + if (fromPort.index >= id_A1.index && fromPort.index <= id_A6.index) + return toPort == id_A || toPort == id_AQ; + } + else if (cell->type == id_BUFGCTRL) + { + return true; + } return false; } @@ -682,19 +694,16 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_CLOCK_INPUT; if (port == id_CIN) return TMG_COMB_INPUT; - if (port == id_COUT || port == id_O) + if (port == id_COUT || port == id_A) return TMG_COMB_OUTPUT; if (cell->lcInfo.dffEnable) { clockPort = id_CLK; - if (port == id_OQ) + if (port == id_AQ) return TMG_REGISTER_OUTPUT; else return TMG_REGISTER_INPUT; } else { - if (port == id_O) - return TMG_COMB_OUTPUT; - else - return TMG_COMB_INPUT; + return TMG_COMB_INPUT; } // TODO //if (port == id_OMUX) diff --git a/xc7/arch.h b/xc7/arch.h index c16040f5..d41f8984 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -305,10 +305,11 @@ struct BelPinRange struct WireIterator { - int cursor = -1; + Tilewire cursor; - void operator++() { cursor++; } - bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } + // TODO + void operator++() { /*cursor++;*/ } + bool operator!=(const WireIterator &other) const { return !(cursor == other.cursor); } WireId operator*() const { @@ -511,18 +512,19 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return id(chip_info->wire_data[wire.index].name.get()); + //return id(chip_info->wire_data[wire.index].name.get()); + return IdString(); } IdString getWireType(WireId wire) const; - uint32_t getWireChecksum(WireId wire) const { return wire.index; } + uint32_t getWireChecksum(WireId wire) const { return hash_value(wire.index); } void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == nullptr); - wire_to_net[wire.index] = net; + //NPNR_ASSERT(wire_to_net[wire.index] == nullptr); + //wire_to_net[wire.index] = net; net->wires[wire].pip = PipId(); net->wires[wire].strength = strength; refreshUiWire(wire); @@ -531,49 +533,52 @@ struct Arch : BaseCtx void unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != nullptr); + //NPNR_ASSERT(wire_to_net[wire.index] != nullptr); - auto &net_wires = wire_to_net[wire.index]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); + //auto &net_wires = wire_to_net[wire.index]->wires; + //auto it = net_wires.find(wire); + //NPNR_ASSERT(it != net_wires.end()); - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip.index] = nullptr; - switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; - } + //auto pip = it->second.pip; + //if (pip != PipId()) { + // pip_to_net[pip.index] = nullptr; + // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + //} - net_wires.erase(it); - wire_to_net[wire.index] = nullptr; + //net_wires.erase(it); + //wire_to_net[wire.index] = nullptr; refreshUiWire(wire); } bool checkWireAvail(WireId wire) const { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == nullptr; + //NPNR_ASSERT(wire != WireId()); + //return wire_to_net[wire.index] == nullptr; + return true; } NetInfo *getBoundWireNet(WireId wire) const { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + //NPNR_ASSERT(wire != WireId()); + //return wire_to_net[wire.index]; + return nullptr; } NetInfo *getConflictingWireNet(WireId wire) const { - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; + //NPNR_ASSERT(wire != WireId()); + //return wire_to_net[wire.index]; + return nullptr; } DelayInfo getWireDelay(WireId wire) const { DelayInfo delay; - NPNR_ASSERT(wire != WireId()); - if (fast_part) - delay.delay = chip_info->wire_data[wire.index].fast_delay; - else - delay.delay = chip_info->wire_data[wire.index].slow_delay; + //NPNR_ASSERT(wire != WireId()); + //if (fast_part) + // delay.delay = chip_info->wire_data[wire.index].fast_delay; + //else + // delay.delay = chip_info->wire_data[wire.index].slow_delay; return delay; } @@ -589,8 +594,8 @@ struct Arch : BaseCtx WireRange getWires() const { WireRange range; - range.b.cursor = 0; - range.e.cursor = 0; //chip_info->num_wires; + //range.b.cursor = 0; + //range.e.cursor = chip_info->num_wires; return range; } @@ -608,11 +613,11 @@ struct Arch : BaseCtx switches_locked[chip_info->pip_data[pip.index].switch_index] = net; WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] == nullptr); - wire_to_net[dst.index] = net; - net->wires[dst].pip = pip; - net->wires[dst].strength = strength; + //dst.index = chip_info->pip_data[pip.index].dst; + //NPNR_ASSERT(wire_to_net[dst.index] == nullptr); + //wire_to_net[dst.index] = net; + //net->wires[dst].pip = pip; + //net->wires[dst].strength = strength; refreshUiPip(pip); refreshUiWire(dst); } @@ -624,9 +629,9 @@ struct Arch : BaseCtx NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != nullptr); - wire_to_net[dst.index] = nullptr; + //dst.index = chip_info->pip_data[pip.index].dst; + //NPNR_ASSERT(wire_to_net[dst.index] != nullptr); + //wire_to_net[dst.index] = nullptr; pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index] = nullptr; @@ -698,7 +703,7 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].src; + //wire.index = chip_info->pip_data[pip.index].src; return wire; } @@ -706,7 +711,7 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = chip_info->pip_data[pip.index].dst; + //wire.index = chip_info->pip_data[pip.index].dst; return wire; } @@ -725,8 +730,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + //range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); + //range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; return range; } @@ -734,8 +739,8 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); - range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + //range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); + //range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; return range; } diff --git a/xc7/archdefs.h b/xc7/archdefs.h index 757d0d61..fd5796c3 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -22,6 +22,7 @@ #endif #include "torc/Architecture.hpp" +using namespace torc::architecture; using namespace torc::architecture::xilinx; NEXTPNR_NAMESPACE_BEGIN @@ -73,10 +74,10 @@ struct BelId struct WireId { - int32_t index = -1; + Tilewire index; bool operator==(const WireId &other) const { return index == other.index; } - bool operator!=(const WireId &other) const { return index != other.index; } + bool operator!=(const WireId &other) const { return !(index == other.index); } }; struct PipId @@ -163,7 +164,7 @@ template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept { - return hash()(wire.index); + return hash_value(wire.index); } }; diff --git a/xc7/cells.cc b/xc7/cells.cc index 07f33f0c..635eaaef 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -53,21 +53,21 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri new_cell->params[ctx->id("CIN_CONST")] = "0"; new_cell->params[ctx->id("CIN_SET")] = "0"; - add_port(ctx, new_cell.get(), "I0", PORT_IN); - add_port(ctx, new_cell.get(), "I1", PORT_IN); - add_port(ctx, new_cell.get(), "I2", PORT_IN); - add_port(ctx, new_cell.get(), "I3", PORT_IN); - add_port(ctx, new_cell.get(), "I4", PORT_IN); - add_port(ctx, new_cell.get(), "I5", PORT_IN); + add_port(ctx, new_cell.get(), "A1", PORT_IN); + add_port(ctx, new_cell.get(), "A2", PORT_IN); + add_port(ctx, new_cell.get(), "A3", PORT_IN); + add_port(ctx, new_cell.get(), "A4", PORT_IN); + add_port(ctx, new_cell.get(), "A5", PORT_IN); + add_port(ctx, new_cell.get(), "A6", PORT_IN); add_port(ctx, new_cell.get(), "CIN", PORT_IN); add_port(ctx, new_cell.get(), "CLK", PORT_IN); add_port(ctx, new_cell.get(), "CE", PORT_IN); add_port(ctx, new_cell.get(), "SR", PORT_IN); - add_port(ctx, new_cell.get(), "O", PORT_OUT); - add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); - add_port(ctx, new_cell.get(), "OQ", PORT_OUT); + add_port(ctx, new_cell.get(), "A", PORT_OUT); + add_port(ctx, new_cell.get(), "AQ", PORT_OUT); + add_port(ctx, new_cell.get(), "AMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { new_cell->type = id_IOB33S; @@ -259,19 +259,19 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; - replace_port(lut, ctx->id("I0"), lc, ctx->id("I0")); + replace_port(lut, ctx->id("I0"), lc, ctx->id("A1")); if (get_net_or_empty(lut, ctx->id("I1"))) - replace_port(lut, ctx->id("I1"), lc, ctx->id("I1")); + replace_port(lut, ctx->id("I1"), lc, ctx->id("A2")); if (get_net_or_empty(lut, ctx->id("I2"))) - replace_port(lut, ctx->id("I2"), lc, ctx->id("I2")); + replace_port(lut, ctx->id("I2"), lc, ctx->id("A3")); if (get_net_or_empty(lut, ctx->id("I3"))) - replace_port(lut, ctx->id("I3"), lc, ctx->id("I3")); + replace_port(lut, ctx->id("I3"), lc, ctx->id("A4")); if (get_net_or_empty(lut, ctx->id("I4"))) - replace_port(lut, ctx->id("I4"), lc, ctx->id("I3")); + replace_port(lut, ctx->id("I4"), lc, ctx->id("A5")); if (get_net_or_empty(lut, ctx->id("I5"))) - replace_port(lut, ctx->id("I5"), lc, ctx->id("I3")); + replace_port(lut, ctx->id("I5"), lc, ctx->id("A6")); if (no_dff) { - replace_port(lut, ctx->id("O"), lc, ctx->id("O")); + replace_port(lut, ctx->id("O"), lc, ctx->id("A")); lc->params[ctx->id("DFF_ENABLE")] = "0"; } } @@ -318,10 +318,10 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if (pass_thru_lut) { lc->params[ctx->id("LUT_INIT")] = "2"; - replace_port(dff, ctx->id("D"), lc, ctx->id("I0")); + replace_port(dff, ctx->id("D"), lc, ctx->id("A1")); } - replace_port(dff, ctx->id("Q"), lc, ctx->id("OQ")); + replace_port(dff, ctx->id("Q"), lc, ctx->id("AQ")); } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) diff --git a/xc7/constids.inc b/xc7/constids.inc index 6dd7da6c..27c5c4e7 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -441,6 +441,16 @@ X(NEG_CLK) X(I) +X(A1) +X(A2) +X(A3) +X(A4) +X(A5) +X(A6) +X(A) +X(AQ) +X(AMUX) + X(LUT1) X(LUT2) X(LUT3) diff --git a/xc7/delay.cc b/xc7/delay.cc index 98c3c655..c85ec359 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -27,75 +27,75 @@ NEXTPNR_NAMESPACE_BEGIN void ice40DelayFuzzerMain(Context *ctx) { - std::vector srcWires, dstWires; - - for (int i = 0; i < ctx->chip_info->num_wires; i++) { - WireId wire; - wire.index = i; - - switch (ctx->chip_info->wire_data[i].type) { - case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: - srcWires.push_back(wire); - break; - - case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: - dstWires.push_back(wire); - break; - - default: - break; - } - } - - ctx->shuffle(srcWires); - ctx->shuffle(dstWires); - - int index = 0; - int cnt = 0; - - while (cnt < NUM_FUZZ_ROUTES) { - if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { - index = 0; - ctx->shuffle(srcWires); - ctx->shuffle(dstWires); - } - - WireId src = srcWires[index]; - WireId dst = dstWires[index++]; - std::unordered_map route; - -#if NUM_FUZZ_ROUTES <= 1000 - if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) - continue; -#else - if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) - continue; -#endif - - WireId cursor = dst; - delay_t delay = 0; - - while (1) { - delay += ctx->getWireDelay(cursor).maxDelay(); - - printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", - int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), - ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), - int(ctx->estimateDelay(cursor, dst))); - - if (cursor == src) - break; - - PipId pip = route.at(cursor); - delay += ctx->getPipDelay(pip).maxDelay(); - cursor = ctx->getPipSrcWire(pip); - } - - cnt++; - - if (cnt % 100 == 0) - fprintf(stderr, "Fuzzed %d arcs.\n", cnt); - } +// std::vector srcWires, dstWires; +// +// for (int i = 0; i < ctx->chip_info->num_wires; i++) { +// WireId wire; +// wire.index = i; +// +// switch (ctx->chip_info->wire_data[i].type) { +// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: +// srcWires.push_back(wire); +// break; +// +// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: +// dstWires.push_back(wire); +// break; +// +// default: +// break; +// } +// } +// +// ctx->shuffle(srcWires); +// ctx->shuffle(dstWires); +// +// int index = 0; +// int cnt = 0; +// +// while (cnt < NUM_FUZZ_ROUTES) { +// if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { +// index = 0; +// ctx->shuffle(srcWires); +// ctx->shuffle(dstWires); +// } +// +// WireId src = srcWires[index]; +// WireId dst = dstWires[index++]; +// std::unordered_map route; +// +//#if NUM_FUZZ_ROUTES <= 1000 +// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) +// continue; +//#else +// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) +// continue; +//#endif +// +// WireId cursor = dst; +// delay_t delay = 0; +// +// while (1) { +// delay += ctx->getWireDelay(cursor).maxDelay(); +// +// printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", +// int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), +// ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), +// int(ctx->estimateDelay(cursor, dst))); +// +// if (cursor == src) +// break; +// +// PipId pip = route.at(cursor); +// delay += ctx->getPipDelay(pip).maxDelay(); +// cursor = ctx->getPipSrcWire(pip); +// } +// +// cnt++; +// +// if (cnt % 100 == 0) +// fprintf(stderr, "Fuzzed %d arcs.\n", cnt); +// } } delay_t Arch::estimateDelay(WireId src, WireId dst) const diff --git a/xc7/pack.cc b/xc7/pack.cc index e8207210..1b2765a0 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -336,16 +336,16 @@ static void pack_constants(Context *ctx) std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); - gnd_net->driver.port = ctx->id("O"); - gnd_cell->ports.at(ctx->id("O")).net = gnd_net.get(); + gnd_net->driver.port = ctx->id("A"); + gnd_cell->ports.at(ctx->id("A")).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); vcc_cell->params[ctx->id("LUT_INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); - vcc_net->driver.port = ctx->id("O"); - vcc_cell->ports.at(ctx->id("O")).net = vcc_net.get(); + vcc_net->driver.port = ctx->id("A"); + vcc_cell->ports.at(ctx->id("A")).net = vcc_net.get(); std::vector dead_nets; @@ -451,6 +451,7 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) { + asm("int3"); std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); std::unique_ptr gb = create_ice_cell(ctx, id_BUFGCTRL, "$bufg_" + glb_name); gb->ports[ctx->id("I0")].net = net; @@ -847,25 +848,25 @@ static void pack_special(Context *ctx) // Find wire that will be driven by this port. const auto pll_out_wire = ctx->getBelPinWire(pll_bel, port.name); - NPNR_ASSERT(pll_out_wire.index != -1); + NPNR_ASSERT(pll_out_wire != WireId()); // Now, constrain all LUTs on the output of the signal to be at // the correct Bel relative to the PLL Bel. - int x = ctx->chip_info->wire_data[pll_out_wire.index].x; - int y = ctx->chip_info->wire_data[pll_out_wire.index].y; - int z = 0; - for (const auto &user : port.net->users) { - NPNR_ASSERT(user.cell != nullptr); - NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC")); + //int x = ctx->chip_info->wire_data[pll_out_wire.index].x; + //int y = ctx->chip_info->wire_data[pll_out_wire.index].y; + //int z = 0; + //for (const auto &user : port.net->users) { + // NPNR_ASSERT(user.cell != nullptr); + // NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC")); - // TODO(q3k): handle when the Bel might be already the - // target of another constraint. - NPNR_ASSERT(z < 8); - auto target_bel = ctx->getBelByLocation(Loc(x, y, z++)); - auto target_bel_name = ctx->getBelName(target_bel).str(ctx); - user.cell->attrs[ctx->id("BEL")] = target_bel_name; - log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str()); - } + // // TODO(q3k): handle when the Bel might be already the + // // target of another constraint. + // NPNR_ASSERT(z < 8); + // auto target_bel = ctx->getBelByLocation(Loc(x, y, z++)); + // auto target_bel_name = ctx->getBelName(target_bel).str(ctx); + // user.cell->attrs[ctx->id("BEL")] = target_bel_name; + // log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str()); + //} } new_cells.push_back(std::move(packed)); @@ -887,7 +888,8 @@ bool Arch::pack() try { log_break(); pack_constants(ctx); - promote_globals(ctx); + // TODO + //promote_globals(ctx); pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); From 0fe579f046b21586db950f95f07500e293c1820b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 18:56:25 -0700 Subject: [PATCH 013/174] Add torc symlink --- torc | 1 + 1 file changed, 1 insertion(+) create mode 120000 torc diff --git a/torc b/torc new file mode 120000 index 00000000..bfd9e8f8 --- /dev/null +++ b/torc @@ -0,0 +1 @@ +../torc/src/torc \ No newline at end of file From 13e30a4eb102aa0aee17b153667d83de38caac90 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 18:56:36 -0700 Subject: [PATCH 014/174] Add nextpnr-xc7 to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f3be78e5..74ff0107 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ /nextpnr-generic* /nextpnr-ice40* /nextpnr-ecp5* +/nextpnr-xc7* cmake-build-*/ Makefile cmake_install.cmake From 8dedd7a83cb1d91278179c7f304f43b5583dc543 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 19:07:33 -0700 Subject: [PATCH 015/174] Add stub for XDL output --- xc7/main.cc | 12 +++++++++++- xc7/xdl.cc | 33 +++++++++++++++++++++++++++++++++ xc7/xdl.h | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 xc7/xdl.cc create mode 100644 xc7/xdl.h diff --git a/xc7/main.cc b/xc7/main.cc index 67515f7b..ec73c940 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -27,6 +27,7 @@ #include "log.h" #include "pcf.h" #include "timing.h" +#include "xdl.h" USING_NEXTPNR_NAMESPACE @@ -39,6 +40,7 @@ class Xc7CommandHandler : public CommandHandler void setupArchContext(Context *ctx) override; void validate() override; void customAfterLoad(Context *ctx) override; + void customBitstream(Context *ctx) override; protected: po::options_description getArchOptions(); @@ -53,7 +55,6 @@ po::options_description Xc7CommandHandler::getArchOptions() // specific.add_options()("package", po::value(), "set device package"); specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); -// specific.add_options()("read", po::value(), "asc bitstream file to read"); // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); return specific; } @@ -74,6 +75,15 @@ void Xc7CommandHandler::customAfterLoad(Context *ctx) // log_error("Loading PCF failed.\n"); } } +void Xc7CommandHandler::customBitstream(Context *ctx) +{ + if (vm.count("xdl")) { + std::string filename = vm["xdl"].as(); + std::ofstream f(filename); + write_xdl(ctx, f); + } +} + void Xc7CommandHandler::setupArchContext(Context *ctx) { // if (vm.count("tmfuzz")) diff --git a/xc7/xdl.cc b/xc7/xdl.cc new file mode 100644 index 00000000..40ed9744 --- /dev/null +++ b/xc7/xdl.cc @@ -0,0 +1,33 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * Copyright (C) 2018 David Shah + * Copyright (C) 2018 Serge Bazanski + * + * 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 "xdl.h" +#include +#include +#include "cells.h" +#include "log.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_xdl(const Context *ctx, std::ostream &out) +{ +} + +NEXTPNR_NAMESPACE_END diff --git a/xc7/xdl.h b/xc7/xdl.h new file mode 100644 index 00000000..19bc5478 --- /dev/null +++ b/xc7/xdl.h @@ -0,0 +1,33 @@ +/* + * 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. + * + */ + +#ifndef XC7_BITSTREAM_H +#define XC7_BITSTREAM_H + +#include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +void write_xdl(const Context *ctx, std::ostream &out); + +NEXTPNR_NAMESPACE_END + +#endif From f6f20dce0c59355cd27b6fea7eaa26849e4dca71 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 19:20:13 -0700 Subject: [PATCH 016/174] Rename ddb to torc --- xc7/arch.cc | 26 +++++++++++++------------- xc7/arch.h | 20 ++++++++++---------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index d7b06c73..5af81542 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -33,9 +33,9 @@ NEXTPNR_NAMESPACE_BEGIN -const DDB *ddb = nullptr; -const Sites *ddbSites = nullptr; -const Tiles *ddbTiles = nullptr; +const DDB *torc = nullptr; +const Sites *torc_sites = nullptr; +const Tiles *torc_tiles = nullptr; // ----------------------------------------------------------------------- @@ -53,7 +53,7 @@ Arch::Arch(ArchArgs args) : args(args) { torc::common::DirectoryTree directoryTree("../../torc/src/torc"); if (args.type == ArchArgs::Z020) { - ddb = new DDB("xc7z020", "clg484"); + torc = new DDB("xc7z020", "clg484"); } else { log_error("Unsupported XC7 chip type.\n"); } @@ -68,10 +68,10 @@ Arch::Arch(ArchArgs args) : args(args) // if (package_info == nullptr) // log_error("Unsupported package '%s'.\n", args.package.c_str()); - ddbSites = &ddb->getSites(); - ddbTiles = &ddb->getTiles(); + torc_sites = &torc->getSites(); + torc_tiles = &torc->getTiles(); - bel_to_cell.resize(ddbSites->getSiteCount()); + bel_to_cell.resize(torc_sites->getSiteCount()); } // ----------------------------------------------------------------------- @@ -100,7 +100,7 @@ BelId Arch::getBelByName(IdString name) const { BelId ret; - auto it = ddbSites->findSiteIndex(name.str(this)); + auto it = torc_sites->findSiteIndex(name.str(this)); if (it != SiteIndex(-1)) ret.index = it; @@ -112,7 +112,7 @@ BelId Arch::getBelByLocation(Loc loc) const BelId bel; if (bel_by_loc.empty()) { - for (SiteIndex i(0); i < ddbSites->getSiteCount(); ++i) { + for (SiteIndex i(0); i < torc_sites->getSiteCount(); ++i) { BelId b; b.index = i; bel_by_loc[getBelLocation(b)] = b; @@ -130,11 +130,11 @@ BelRange Arch::getBelsByTile(int x, int y) const { BelRange br; - br.b.cursor = std::next(ddbSites->getSites().begin(), Arch::getBelByLocation(Loc(x, y, 0)).index); + br.b.cursor = std::next(torc_sites->getSites().begin(), Arch::getBelByLocation(Loc(x, y, 0)).index); br.e.cursor = br.b.cursor; - if (br.e.cursor != ddbSites->getSites().end()) { - while (br.e.cursor < ddbSites->getSites().end() && ddbSites->getSite((*br.e).index).getTileIndex() == ddbSites->getSite((*br.b).index).getTileIndex()) + if (br.e.cursor != torc_sites->getSites().end()) { + while (br.e.cursor < torc_sites->getSites().end() && torc_sites->getSite((*br.e).index).getTileIndex() == torc_sites->getSite((*br.b).index).getTileIndex()) br.e.cursor++; } @@ -173,7 +173,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - const auto& site = ddbSites->getSite(bel.index); + const auto& site = torc_sites->getSite(bel.index); ret.index = site.getPinTilewire(pin.str(this)); // NPNR_ASSERT(bel != BelId()); diff --git a/xc7/arch.h b/xc7/arch.h index d41f8984..8ee8c7d6 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -233,9 +233,9 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { }); -extern const DDB *ddb; -extern const Sites *ddbSites; -extern const Tiles *ddbTiles; +extern const DDB *torc; +extern const Sites *torc_sites; +extern const Tiles *torc_tiles; /************************ End of chipdb section. ************************/ @@ -263,7 +263,7 @@ struct BelIterator BelId operator*() const { BelId ret; - ret.index = SiteIndex(std::distance(ddbSites->getSites().begin(), cursor)); + ret.index = SiteIndex(std::distance(torc_sites->getSites().begin(), cursor)); return ret; } }; @@ -423,7 +423,7 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(ddbSites->getSite(bel.index).getName()); + return id(torc_sites->getSite(bel.index).getName()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -472,15 +472,15 @@ struct Arch : BaseCtx BelRange getBels() const { BelRange range; - range.b.cursor = ddbSites->getSites().begin(); - range.e.cursor = ddbSites->getSites().end(); + range.b.cursor = torc_sites->getSites().begin(); + range.e.cursor = torc_sites->getSites().end(); return range; } Loc getBelLocation(BelId bel) const { - const auto& site = ddbSites->getSite(bel.index); - const auto& tile_info = ddbTiles->getTileInfo(site.getTileIndex()); + const auto& site = torc_sites->getSite(bel.index); + const auto& tile_info = torc_tiles->getTileInfo(site.getTileIndex()); Loc loc; loc.x = tile_info.getCol(); loc.y = tile_info.getRow(); @@ -496,7 +496,7 @@ struct Arch : BaseCtx IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - const auto& site = ddbSites->getSite(bel.index); + const auto& site = torc_sites->getSite(bel.index); auto prim_def = site.getPrimitiveDefPtr(); return id(prim_def->getName()); } From 56b7299cca07d47ad45cfd8fce64d2241be6d777 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 20:21:03 -0700 Subject: [PATCH 017/174] {SLICEL,SLICEM} -> QUARTER_SLICE --- xc7/arch.cc | 49 ++++++++++++++++++++++++++++++++++++++++-------- xc7/arch.h | 39 ++++++++++++++++++++------------------ xc7/archdefs.h | 6 ++++-- xc7/cells.cc | 2 +- xc7/constids.inc | 2 +- 5 files changed, 68 insertions(+), 30 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 5af81542..ce13edeb 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -36,6 +36,7 @@ NEXTPNR_NAMESPACE_BEGIN const DDB *torc = nullptr; const Sites *torc_sites = nullptr; const Tiles *torc_tiles = nullptr; +std::vector bel_index_to_type; // ----------------------------------------------------------------------- @@ -71,6 +72,17 @@ Arch::Arch(ArchArgs args) : args(args) torc_sites = &torc->getSites(); torc_tiles = &torc->getTiles(); + bel_index_to_type.resize(torc_sites->getSiteCount()); + for (SiteIndex i(0); i < torc_sites->getSiteCount(); ++i) { + const auto& s = torc_sites->getSite(i); + auto pd = s.getPrimitiveDefPtr(); + const auto& type = pd->getName(); + if (type == "SLICEL" || type == "SLICEM") + bel_index_to_type[i] = id_QUARTER_SLICE; + else + bel_index_to_type[i] = id(type); + } + bel_to_cell.resize(torc_sites->getSiteCount()); } @@ -115,6 +127,15 @@ BelId Arch::getBelByLocation(Loc loc) const for (SiteIndex i(0); i < torc_sites->getSiteCount(); ++i) { BelId b; b.index = i; + if (bel_index_to_type[i] == id_QUARTER_SLICE) { + b.pos = BelId::A; + bel_by_loc[getBelLocation(b)] = b; + b.pos = BelId::B; + bel_by_loc[getBelLocation(b)] = b; + b.pos = BelId::C; + bel_by_loc[getBelLocation(b)] = b; + b.pos = BelId::D; + } bel_by_loc[getBelLocation(b)] = b; } } @@ -130,12 +151,14 @@ BelRange Arch::getBelsByTile(int x, int y) const { BelRange br; - br.b.cursor = std::next(torc_sites->getSites().begin(), Arch::getBelByLocation(Loc(x, y, 0)).index); - br.e.cursor = br.b.cursor; + auto b = getBelByLocation(Loc(x, y, 0)); + br.b.index = b.index; + br.b.pos = b.pos; + br.e = br.b; - if (br.e.cursor != torc_sites->getSites().end()) { - while (br.e.cursor < torc_sites->getSites().end() && torc_sites->getSite((*br.e).index).getTileIndex() == torc_sites->getSite((*br.b).index).getTileIndex()) - br.e.cursor++; + if (br.e.index != SiteIndex(torc_sites->getSiteCount())) { + while (br.e.index < SiteIndex(torc_sites->getSiteCount()) && torc_sites->getSite((*br.e).index).getTileIndex() == torc_sites->getSite((*br.b).index).getTileIndex()) + br.e++; } return br; @@ -674,7 +697,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { - if (cell->type == id_SLICEL) + if (cell->type == id_QUARTER_SLICE) { if (fromPort.index >= id_A1.index && fromPort.index <= id_A6.index) return toPort == id_A || toPort == id_AQ; @@ -689,7 +712,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort // Get the port class, also setting clockPort to associated clock if applicable TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const { - if (cell->type == id_SLICEL) { + if (cell->type == id_QUARTER_SLICE) { if (port == id_CLK) return TMG_CLOCK_INPUT; if (port == id_CIN) @@ -754,7 +777,7 @@ void Arch::assignArchInfo() void Arch::assignCellInfo(CellInfo *cell) { cell->belType = cell->type; - if (cell->type == id_SLICEL) { + if (cell->type == id_QUARTER_SLICE) { cell->lcInfo.dffEnable = bool_or_default(cell->params, id_DFF_ENABLE); cell->lcInfo.carryEnable = bool_or_default(cell->params, id_CARRY_ENABLE); cell->lcInfo.negClk = bool_or_default(cell->params, id_NEG_CLK); @@ -773,4 +796,14 @@ void Arch::assignCellInfo(CellInfo *cell) } } +void operator++(BelId::bel &b) { + switch (b) { + case BelId::A: b = BelId::B; return; + case BelId::B: b = BelId::C; return; + case BelId::C: b = BelId::D; return; + default: break; + } + throw; +} + NEXTPNR_NAMESPACE_END diff --git a/xc7/arch.h b/xc7/arch.h index 8ee8c7d6..295a0759 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -236,36 +236,41 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { extern const DDB *torc; extern const Sites *torc_sites; extern const Tiles *torc_tiles; +extern std::vector bel_index_to_type; /************************ End of chipdb section. ************************/ -struct BelIterator +struct BelIterator : public BelId { - Array::iterator cursor; - BelIterator operator++() { - cursor++; + if (bel_index_to_type[index] == id_QUARTER_SLICE) { + if (pos < D) { + ++pos; + return *this; + } + } + + if (bel_index_to_type[++index] == id_QUARTER_SLICE) + pos = A; + else + pos = NOT_APPLICABLE; + return *this; } BelIterator operator++(int) { BelIterator prior(*this); - cursor++; + operator++(); return prior; } - bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } + bool operator!=(const BelIterator &other) const { return BelId::operator!=(other); } - bool operator==(const BelIterator &other) const { return cursor == other.cursor; } + bool operator==(const BelIterator &other) const { return BelId::operator==(other); } - BelId operator*() const - { - BelId ret; - ret.index = SiteIndex(std::distance(torc_sites->getSites().begin(), cursor)); - return ret; - } + BelId operator*() const { return *this; } }; struct BelRange @@ -472,8 +477,8 @@ struct Arch : BaseCtx BelRange getBels() const { BelRange range; - range.b.cursor = torc_sites->getSites().begin(); - range.e.cursor = torc_sites->getSites().end(); + range.b.index = SiteIndex(0); + range.e.index = SiteIndex(torc_sites->getSiteCount()); return range; } @@ -496,9 +501,7 @@ struct Arch : BaseCtx IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - const auto& site = torc_sites->getSite(bel.index); - auto prim_def = site.getPrimitiveDefPtr(); - return id(prim_def->getName()); + return bel_index_to_type[bel.index]; } WireId getBelPinWire(BelId bel, IdString pin) const; diff --git a/xc7/archdefs.h b/xc7/archdefs.h index fd5796c3..bfeadea4 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -67,10 +67,12 @@ enum ConstIds struct BelId { SiteIndex index = SiteIndex(-1); + enum bel : int8_t { NOT_APPLICABLE, A, B, C, D } pos = NOT_APPLICABLE; - bool operator==(const BelId &other) const { return index == other.index; } - bool operator!=(const BelId &other) const { return index != other.index; } + bool operator==(const BelId &other) const { return index == other.index && pos == pos; } + bool operator!=(const BelId &other) const { return index != other.index || pos != pos; } }; +void operator++(BelId::bel &b); struct WireId { diff --git a/xc7/cells.cc b/xc7/cells.cc index 635eaaef..c36d1443 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -43,7 +43,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri } new_cell->type = type; if (type == ctx->id("XC7_LC")) { - new_cell->type = id_SLICEL; // HACK HACK HACK: Place one LC into each slice + new_cell->type = id_QUARTER_SLICE; // HACK HACK HACK: Place one LC into each slice new_cell->params[ctx->id("LUT_INIT")] = "0"; new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; diff --git a/xc7/constids.inc b/xc7/constids.inc index 27c5c4e7..632524de 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -464,7 +464,7 @@ X(FDCE) X(FDPE) X(BUFGCTRL) -X(SLICEL) +X(QUARTER_SLICE) X(IOBUF) X(IOB33S) X(IOB33M) // What is the difference between IOB33S and IOB33M? From 7b15569c694eb19a982f21746a391415e5930285 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 20:29:04 -0700 Subject: [PATCH 018/174] Use general pin names for QUARTER_SLICE --- xc7/arch.cc | 31 ++++++++++++++------------ xc7/archdefs.h | 2 +- xc7/cells.cc | 58 ++++++++++++++++++++++++------------------------ xc7/constids.inc | 13 ++--------- xc7/pack.cc | 8 +++---- 5 files changed, 53 insertions(+), 59 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ce13edeb..caee112f 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -197,7 +197,10 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const WireId ret; const auto& site = torc_sites->getSite(bel.index); - ret.index = site.getPinTilewire(pin.str(this)); + auto pin_name = pin.str(this); + if (bel_index_to_type[bel.index] == id_QUARTER_SLICE) + pin_name[0] = bel.pos; + ret.index = site.getPinTilewire(pin_name); // NPNR_ASSERT(bel != BelId()); // @@ -699,8 +702,8 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort { if (cell->type == id_QUARTER_SLICE) { - if (fromPort.index >= id_A1.index && fromPort.index <= id_A6.index) - return toPort == id_A || toPort == id_AQ; + if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) + return toPort == id_O || toPort == id_OQ; } else if (cell->type == id_BUFGCTRL) { @@ -717,11 +720,11 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_CLOCK_INPUT; if (port == id_CIN) return TMG_COMB_INPUT; - if (port == id_COUT || port == id_A) + if (port == id_COUT || port == id_O) return TMG_COMB_OUTPUT; if (cell->lcInfo.dffEnable) { clockPort = id_CLK; - if (port == id_AQ) + if (port == id_OQ) return TMG_REGISTER_OUTPUT; else return TMG_REGISTER_INPUT; @@ -784,15 +787,15 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lcInfo.clk = get_net_or_empty(cell, id_CLK); cell->lcInfo.cen = get_net_or_empty(cell, id_CEN); cell->lcInfo.sr = get_net_or_empty(cell, id_SR); - cell->lcInfo.inputCount = 0; - if (get_net_or_empty(cell, id_I0)) - cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I1)) - cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I2)) - cell->lcInfo.inputCount++; - if (get_net_or_empty(cell, id_I3)) - cell->lcInfo.inputCount++; +// cell->lcInfo.inputCount = 0; +// if (get_net_or_empty(cell, id_I0)) +// cell->lcInfo.inputCount++; +// if (get_net_or_empty(cell, id_I1)) +// cell->lcInfo.inputCount++; +// if (get_net_or_empty(cell, id_I2)) +// cell->lcInfo.inputCount++; +// if (get_net_or_empty(cell, id_I3)) +// cell->lcInfo.inputCount++; } } diff --git a/xc7/archdefs.h b/xc7/archdefs.h index bfeadea4..9c0efc70 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -67,7 +67,7 @@ enum ConstIds struct BelId { SiteIndex index = SiteIndex(-1); - enum bel : int8_t { NOT_APPLICABLE, A, B, C, D } pos = NOT_APPLICABLE; + enum bel : int8_t { NOT_APPLICABLE, A='A', B='B', C='C', D='D' } pos = NOT_APPLICABLE; bool operator==(const BelId &other) const { return index == other.index && pos == pos; } bool operator!=(const BelId &other) const { return index != other.index || pos != pos; } diff --git a/xc7/cells.cc b/xc7/cells.cc index c36d1443..ad0ab420 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -53,21 +53,21 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri new_cell->params[ctx->id("CIN_CONST")] = "0"; new_cell->params[ctx->id("CIN_SET")] = "0"; - add_port(ctx, new_cell.get(), "A1", PORT_IN); - add_port(ctx, new_cell.get(), "A2", PORT_IN); - add_port(ctx, new_cell.get(), "A3", PORT_IN); - add_port(ctx, new_cell.get(), "A4", PORT_IN); - add_port(ctx, new_cell.get(), "A5", PORT_IN); - add_port(ctx, new_cell.get(), "A6", PORT_IN); + add_port(ctx, new_cell.get(), "I1", PORT_IN); + add_port(ctx, new_cell.get(), "I2", PORT_IN); + add_port(ctx, new_cell.get(), "I3", PORT_IN); + add_port(ctx, new_cell.get(), "I4", PORT_IN); + add_port(ctx, new_cell.get(), "I5", PORT_IN); + add_port(ctx, new_cell.get(), "I6", PORT_IN); add_port(ctx, new_cell.get(), "CIN", PORT_IN); add_port(ctx, new_cell.get(), "CLK", PORT_IN); add_port(ctx, new_cell.get(), "CE", PORT_IN); add_port(ctx, new_cell.get(), "SR", PORT_IN); - add_port(ctx, new_cell.get(), "A", PORT_OUT); - add_port(ctx, new_cell.get(), "AQ", PORT_OUT); - add_port(ctx, new_cell.get(), "AMUX", PORT_OUT); + add_port(ctx, new_cell.get(), "O", PORT_OUT); + add_port(ctx, new_cell.get(), "OQ", PORT_OUT); + add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { new_cell->type = id_IOB33S; @@ -259,19 +259,19 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; - replace_port(lut, ctx->id("I0"), lc, ctx->id("A1")); - if (get_net_or_empty(lut, ctx->id("I1"))) - replace_port(lut, ctx->id("I1"), lc, ctx->id("A2")); - if (get_net_or_empty(lut, ctx->id("I2"))) - replace_port(lut, ctx->id("I2"), lc, ctx->id("A3")); - if (get_net_or_empty(lut, ctx->id("I3"))) - replace_port(lut, ctx->id("I3"), lc, ctx->id("A4")); - if (get_net_or_empty(lut, ctx->id("I4"))) - replace_port(lut, ctx->id("I4"), lc, ctx->id("A5")); - if (get_net_or_empty(lut, ctx->id("I5"))) - replace_port(lut, ctx->id("I5"), lc, ctx->id("A6")); + replace_port(lut, ctx->id("I0"), lc, id_I1); + if (get_net_or_empty(lut, id_I1)) + replace_port(lut, id_I1, lc, id_I2); + if (get_net_or_empty(lut, id_I2)) + replace_port(lut, id_I2, lc, id_I3); + if (get_net_or_empty(lut, id_I3)) + replace_port(lut, id_I3, lc, id_I4); + if (get_net_or_empty(lut, id_I4)) + replace_port(lut, id_I4, lc, id_I5); + if (get_net_or_empty(lut, id_I5)) + replace_port(lut, id_I5, lc, id_I6); if (no_dff) { - replace_port(lut, ctx->id("O"), lc, ctx->id("A")); + replace_port(lut, id_O, lc, id_O); lc->params[ctx->id("DFF_ENABLE")] = "0"; } } @@ -318,10 +318,10 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if (pass_thru_lut) { lc->params[ctx->id("LUT_INIT")] = "2"; - replace_port(dff, ctx->id("D"), lc, ctx->id("A1")); + replace_port(dff, ctx->id("D"), lc, id_I1); } - replace_port(dff, ctx->id("Q"), lc, ctx->id("AQ")); + replace_port(dff, ctx->id("Q"), lc, id_OQ); } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) @@ -331,25 +331,25 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) auto pu_attr = nxio->attrs.find(ctx->id("PULLUP")); if (pu_attr != nxio->attrs.end()) sbio->params[ctx->id("PULLUP")] = pu_attr->second; - replace_port(nxio, ctx->id("O"), sbio, ctx->id("I")); + replace_port(nxio, id_O, sbio, id_I); } else if (nxio->type == ctx->id("$nextpnr_obuf")) { sbio->params[ctx->id("PIN_TYPE")] = "25"; - replace_port(nxio, ctx->id("I"), sbio, ctx->id("O")); + replace_port(nxio, id_I, sbio, id_O); } else if (nxio->type == ctx->id("$nextpnr_iobuf")) { // N.B. tristate will be dealt with below sbio->params[ctx->id("PIN_TYPE")] = "25"; - replace_port(nxio, ctx->id("I"), sbio, ctx->id("O")); - replace_port(nxio, ctx->id("O"), sbio, ctx->id("I")); + replace_port(nxio, id_I, sbio, id_O); + replace_port(nxio, id_O, sbio, id_I); } else { NPNR_ASSERT(false); } - NetInfo *donet = sbio->ports.at(ctx->id("O")).net; + NetInfo *donet = sbio->ports.at(id_O).net; CellInfo *tbuf = net_driven_by( ctx, donet, [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, ctx->id("Y")); if (tbuf) { sbio->params[ctx->id("PIN_TYPE")] = "41"; - replace_port(tbuf, ctx->id("A"), sbio, ctx->id("O")); + replace_port(tbuf, ctx->id("A"), sbio, id_O); replace_port(tbuf, ctx->id("E"), sbio, ctx->id("OUTPUT_ENABLE")); ctx->nets.erase(donet->name); if (!donet->users.empty()) diff --git a/xc7/constids.inc b/xc7/constids.inc index 632524de..2fa867a0 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -1,10 +1,11 @@ // pin and port names -X(I0) +//X(I0) X(I1) X(I2) X(I3) X(I4) X(I5) +X(I6) X(O) X(OQ) X(OMUX) @@ -441,16 +442,6 @@ X(NEG_CLK) X(I) -X(A1) -X(A2) -X(A3) -X(A4) -X(A5) -X(A6) -X(A) -X(AQ) -X(AMUX) - X(LUT1) X(LUT2) X(LUT3) diff --git a/xc7/pack.cc b/xc7/pack.cc index 1b2765a0..1e27f8a3 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -336,16 +336,16 @@ static void pack_constants(Context *ctx) std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); - gnd_net->driver.port = ctx->id("A"); - gnd_cell->ports.at(ctx->id("A")).net = gnd_net.get(); + gnd_net->driver.port = id_O; + gnd_cell->ports.at(id_O).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); vcc_cell->params[ctx->id("LUT_INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); - vcc_net->driver.port = ctx->id("A"); - vcc_cell->ports.at(ctx->id("A")).net = vcc_net.get(); + vcc_net->driver.port = id_O; + vcc_cell->ports.at(id_O).net = vcc_net.get(); std::vector dead_nets; From 72c785db0e0f949492b805a896bec5f9e36f10ef Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 12 Aug 2018 22:09:16 -0700 Subject: [PATCH 019/174] Convert to use torc_info --- xc7/arch.cc | 56 +++++++++++++++++++++++++++-------------------------- xc7/arch.h | 46 +++++++++++++++++++++++++++++++------------ 2 files changed, 63 insertions(+), 39 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index caee112f..4e6f32f6 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -33,10 +33,26 @@ NEXTPNR_NAMESPACE_BEGIN -const DDB *torc = nullptr; -const Sites *torc_sites = nullptr; -const Tiles *torc_tiles = nullptr; -std::vector bel_index_to_type; +std::unique_ptr torc_info; +TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), site_index_to_type(construct_site_index_to_type(ctx, sites)) +{ +} +std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Sites &sites) +{ + std::vector site_index_to_type; + site_index_to_type.resize(sites.getSiteCount()); + for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { + const auto& s = sites.getSite(i); + auto pd = s.getPrimitiveDefPtr(); + const auto& type = pd->getName(); + if (type == "SLICEL" || type == "SLICEM") + site_index_to_type[i] = id_QUARTER_SLICE; + else + site_index_to_type[i] = ctx->id(type); + } + return site_index_to_type; +} // ----------------------------------------------------------------------- @@ -54,7 +70,7 @@ Arch::Arch(ArchArgs args) : args(args) { torc::common::DirectoryTree directoryTree("../../torc/src/torc"); if (args.type == ArchArgs::Z020) { - torc = new DDB("xc7z020", "clg484"); + torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", "clg484")); } else { log_error("Unsupported XC7 chip type.\n"); } @@ -69,21 +85,7 @@ Arch::Arch(ArchArgs args) : args(args) // if (package_info == nullptr) // log_error("Unsupported package '%s'.\n", args.package.c_str()); - torc_sites = &torc->getSites(); - torc_tiles = &torc->getTiles(); - - bel_index_to_type.resize(torc_sites->getSiteCount()); - for (SiteIndex i(0); i < torc_sites->getSiteCount(); ++i) { - const auto& s = torc_sites->getSite(i); - auto pd = s.getPrimitiveDefPtr(); - const auto& type = pd->getName(); - if (type == "SLICEL" || type == "SLICEM") - bel_index_to_type[i] = id_QUARTER_SLICE; - else - bel_index_to_type[i] = id(type); - } - - bel_to_cell.resize(torc_sites->getSiteCount()); + bel_to_cell.resize(torc_info->sites.getSiteCount()); } // ----------------------------------------------------------------------- @@ -112,7 +114,7 @@ BelId Arch::getBelByName(IdString name) const { BelId ret; - auto it = torc_sites->findSiteIndex(name.str(this)); + auto it = torc_info->sites.findSiteIndex(name.str(this)); if (it != SiteIndex(-1)) ret.index = it; @@ -124,10 +126,10 @@ BelId Arch::getBelByLocation(Loc loc) const BelId bel; if (bel_by_loc.empty()) { - for (SiteIndex i(0); i < torc_sites->getSiteCount(); ++i) { + for (SiteIndex i(0); i < torc_info->sites.getSiteCount(); ++i) { BelId b; b.index = i; - if (bel_index_to_type[i] == id_QUARTER_SLICE) { + if (torc_info->site_index_to_type[i] == id_QUARTER_SLICE) { b.pos = BelId::A; bel_by_loc[getBelLocation(b)] = b; b.pos = BelId::B; @@ -156,8 +158,8 @@ BelRange Arch::getBelsByTile(int x, int y) const br.b.pos = b.pos; br.e = br.b; - if (br.e.index != SiteIndex(torc_sites->getSiteCount())) { - while (br.e.index < SiteIndex(torc_sites->getSiteCount()) && torc_sites->getSite((*br.e).index).getTileIndex() == torc_sites->getSite((*br.b).index).getTileIndex()) + if (br.e.index != SiteIndex(torc_info->sites.getSiteCount())) { + while (br.e.index < SiteIndex(torc_info->sites.getSiteCount()) && torc_info->sites.getSite((*br.e).index).getTileIndex() == torc_info->sites.getSite((*br.b).index).getTileIndex()) br.e++; } @@ -196,9 +198,9 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - const auto& site = torc_sites->getSite(bel.index); + const auto& site = torc_info->sites.getSite(bel.index); auto pin_name = pin.str(this); - if (bel_index_to_type[bel.index] == id_QUARTER_SLICE) + if (torc_info->site_index_to_type[bel.index] == id_QUARTER_SLICE) pin_name[0] = bel.pos; ret.index = site.getPinTilewire(pin_name); diff --git a/xc7/arch.h b/xc7/arch.h index 295a0759..5f54a5ea 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -233,10 +233,27 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { }); -extern const DDB *torc; -extern const Sites *torc_sites; -extern const Tiles *torc_tiles; -extern std::vector bel_index_to_type; +struct Arch; +struct TorcInfo { + TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName); + std::unique_ptr ddb; + const Sites &sites; + const Tiles &tiles; + + SiteIndex sites_begin() const { return SiteIndex(0); } + SiteIndex sites_end() const { return SiteIndex(sites.getSiteCount()); } + const TileInfo& site_index_to_tile_info(SiteIndex si) const { + const auto& site = sites.getSite(si); + return tiles.getTileInfo(site.getTileIndex()); + } + const std::string& site_index_to_name(SiteIndex si) const { + return sites.getSite(si).getName(); + } + + const std::vector site_index_to_type; + static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); +}; +extern std::unique_ptr torc_info; /************************ End of chipdb section. ************************/ @@ -245,14 +262,14 @@ struct BelIterator : public BelId { BelIterator operator++() { - if (bel_index_to_type[index] == id_QUARTER_SLICE) { + if (torc_info->site_index_to_type[index] == id_QUARTER_SLICE) { if (pos < D) { ++pos; return *this; } } - if (bel_index_to_type[++index] == id_QUARTER_SLICE) + if (torc_info->site_index_to_type[++index] == id_QUARTER_SLICE) pos = A; else pos = NOT_APPLICABLE; @@ -428,7 +445,13 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(torc_sites->getSite(bel.index).getName()); + auto name = torc_info->site_index_to_name(bel.index); + if (torc_info->site_index_to_type[bel.index] == id_QUARTER_SLICE) { + name.reserve(name.size() + 2); + name += "_"; + name += bel.pos; + } + return id(name); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -477,15 +500,14 @@ struct Arch : BaseCtx BelRange getBels() const { BelRange range; - range.b.index = SiteIndex(0); - range.e.index = SiteIndex(torc_sites->getSiteCount()); + range.b.index = torc_info->sites_begin(); + range.e.index = torc_info->sites_end(); return range; } Loc getBelLocation(BelId bel) const { - const auto& site = torc_sites->getSite(bel.index); - const auto& tile_info = torc_tiles->getTileInfo(site.getTileIndex()); + const auto& tile_info = torc_info->site_index_to_tile_info(bel.index); Loc loc; loc.x = tile_info.getCol(); loc.y = tile_info.getRow(); @@ -501,7 +523,7 @@ struct Arch : BaseCtx IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return bel_index_to_type[bel.index]; + return torc_info->site_index_to_type[bel.index]; } WireId getBelPinWire(BelId bel, IdString pin) const; From b8b981305683d174bf826ec1b95b560b20bc92de Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 14 Aug 2018 08:42:27 -0700 Subject: [PATCH 020/174] id_QUARTER_SLICE -> id_SLICE_LUT6, fix getBelLocation() --- xc7/arch.cc | 44 +++++++++++++++++++++++++++++++++----------- xc7/arch.h | 28 ++++++++++++++++++---------- xc7/cells.cc | 2 +- xc7/constids.inc | 2 +- 4 files changed, 53 insertions(+), 23 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 4e6f32f6..ce7c5c1a 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), site_index_to_type(construct_site_index_to_type(ctx, sites)) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), site_index_to_type(construct_site_index_to_type(ctx, sites)), site_index_to_z_offset(construct_site_index_to_z_offset(sites, site_index_to_type)) { } std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Sites &sites) @@ -43,16 +43,31 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si std::vector site_index_to_type; site_index_to_type.resize(sites.getSiteCount()); for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { - const auto& s = sites.getSite(i); + auto s = sites.getSite(i); auto pd = s.getPrimitiveDefPtr(); - const auto& type = pd->getName(); + auto type = pd->getName(); if (type == "SLICEL" || type == "SLICEM") - site_index_to_type[i] = id_QUARTER_SLICE; + site_index_to_type[i] = id_SLICE_LUT6; else site_index_to_type[i] = ctx->id(type); } return site_index_to_type; } +std::vector TorcInfo::construct_site_index_to_z_offset(const Sites &sites, const std::vector &site_index_to_type) +{ + std::vector site_index_to_z_offset; + site_index_to_z_offset.resize(site_index_to_type.size()); + for (SiteIndex i(0); i < site_index_to_type.size(); ++i) { + if (site_index_to_type[i] == id_SLICE_LUT6) { + auto site = sites.getSite(i); + auto site_name = site.getName(); + auto site_name_back = site_name.back(); + if (site_name_back == '1' || site_name_back == '3' || site_name_back == '5' || site_name_back == '7' || site_name_back == '9') + site_index_to_z_offset[i] = 4; + } + } + return site_index_to_z_offset; +} // ----------------------------------------------------------------------- @@ -129,7 +144,7 @@ BelId Arch::getBelByLocation(Loc loc) const for (SiteIndex i(0); i < torc_info->sites.getSiteCount(); ++i) { BelId b; b.index = i; - if (torc_info->site_index_to_type[i] == id_QUARTER_SLICE) { + if (torc_info->site_index_to_type[i] == id_SLICE_LUT6) { b.pos = BelId::A; bel_by_loc[getBelLocation(b)] = b; b.pos = BelId::B; @@ -198,12 +213,19 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - const auto& site = torc_info->sites.getSite(bel.index); + auto &site = torc_info->sites.getSite(bel.index); auto pin_name = pin.str(this); - if (torc_info->site_index_to_type[bel.index] == id_QUARTER_SLICE) - pin_name[0] = bel.pos; + if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { + // For all LUT based inputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT + if (pin_name[0] == 'I' || pin_name[0] == 'O') + pin_name[0] = bel.pos; + } ret.index = site.getPinTilewire(pin_name); + if (ret.index.isUndefined()) + log_error("no wire found for site '%s' pin '%s' \n", torc_info->site_index_to_name(bel.index).c_str(), pin_name.c_str()); + + // NPNR_ASSERT(bel != BelId()); // // int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; @@ -702,7 +724,7 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { - if (cell->type == id_QUARTER_SLICE) + if (cell->type == id_SLICE_LUT6) { if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) return toPort == id_O || toPort == id_OQ; @@ -717,7 +739,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort // Get the port class, also setting clockPort to associated clock if applicable TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const { - if (cell->type == id_QUARTER_SLICE) { + if (cell->type == id_SLICE_LUT6) { if (port == id_CLK) return TMG_CLOCK_INPUT; if (port == id_CIN) @@ -782,7 +804,7 @@ void Arch::assignArchInfo() void Arch::assignCellInfo(CellInfo *cell) { cell->belType = cell->type; - if (cell->type == id_QUARTER_SLICE) { + if (cell->type == id_SLICE_LUT6) { cell->lcInfo.dffEnable = bool_or_default(cell->params, id_DFF_ENABLE); cell->lcInfo.carryEnable = bool_or_default(cell->params, id_CARRY_ENABLE); cell->lcInfo.negClk = bool_or_default(cell->params, id_NEG_CLK); diff --git a/xc7/arch.h b/xc7/arch.h index 5f54a5ea..379369c6 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -243,7 +243,7 @@ struct TorcInfo { SiteIndex sites_begin() const { return SiteIndex(0); } SiteIndex sites_end() const { return SiteIndex(sites.getSiteCount()); } const TileInfo& site_index_to_tile_info(SiteIndex si) const { - const auto& site = sites.getSite(si); + auto &site = sites.getSite(si); return tiles.getTileInfo(site.getTileIndex()); } const std::string& site_index_to_name(SiteIndex si) const { @@ -251,7 +251,11 @@ struct TorcInfo { } const std::vector site_index_to_type; + const std::vector site_index_to_z_offset; + +private: static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); + static std::vector construct_site_index_to_z_offset(const Sites &sites, const std::vector &site_index_to_type); }; extern std::unique_ptr torc_info; @@ -262,14 +266,12 @@ struct BelIterator : public BelId { BelIterator operator++() { - if (torc_info->site_index_to_type[index] == id_QUARTER_SLICE) { - if (pos < D) { - ++pos; - return *this; - } + if (pos >= A && pos < D) { + ++pos; + return *this; } - if (torc_info->site_index_to_type[++index] == id_QUARTER_SLICE) + if (torc_info->site_index_to_type[++index] == id_SLICE_LUT6) pos = A; else pos = NOT_APPLICABLE; @@ -446,7 +448,8 @@ struct Arch : BaseCtx { NPNR_ASSERT(bel != BelId()); auto name = torc_info->site_index_to_name(bel.index); - if (torc_info->site_index_to_type[bel.index] == id_QUARTER_SLICE) { + if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { + // Append LUT name to name name.reserve(name.size() + 2); name += "_"; name += bel.pos; @@ -507,11 +510,16 @@ struct Arch : BaseCtx Loc getBelLocation(BelId bel) const { - const auto& tile_info = torc_info->site_index_to_tile_info(bel.index); + auto &tile_info = torc_info->site_index_to_tile_info(bel.index); + Loc loc; loc.x = tile_info.getCol(); loc.y = tile_info.getRow(); - loc.z = 0; + if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { + loc.z = bel.pos - 'A'; + // Apply offset if upper slice + loc.z += torc_info->site_index_to_z_offset[bel.index]; + } return loc; } diff --git a/xc7/cells.cc b/xc7/cells.cc index ad0ab420..c43af075 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -43,7 +43,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri } new_cell->type = type; if (type == ctx->id("XC7_LC")) { - new_cell->type = id_QUARTER_SLICE; // HACK HACK HACK: Place one LC into each slice + new_cell->type = id_SLICE_LUT6; new_cell->params[ctx->id("LUT_INIT")] = "0"; new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; diff --git a/xc7/constids.inc b/xc7/constids.inc index 2fa867a0..8e07efd9 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -455,7 +455,7 @@ X(FDCE) X(FDPE) X(BUFGCTRL) -X(QUARTER_SLICE) +X(SLICE_LUT6) X(IOBUF) X(IOB33S) X(IOB33M) // What is the difference between IOB33S and IOB33M? From d05ac75fdae369f9c9a596cd98420954315b621b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Aug 2018 21:52:34 -0700 Subject: [PATCH 021/174] Add basics for XDL exporter --- xc7/family.cmake | 23 +++++++++++++++++++ xc7/xdl.cc | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/xc7/family.cmake b/xc7/family.cmake index a92fd44b..6da9fe48 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -43,4 +43,27 @@ target_link_libraries( PRIVATE ${CMAKE_SOURCE_DIR}/torc/externals/zlib/zfstream.o PRIVATE z + + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Circuit.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/ConfigMap.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Config.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Design.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Factory.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Instance.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/InstancePin.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/InstanceReference.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Module.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/ModuleTransformer.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Named.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Net.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/OutputStreamHelpers.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Pip.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Port.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Progenitor.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Progeny.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Renamable.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Routethrough.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/TilewirePlaceholder.o + PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/XdlExporter.o +# PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/XdlImporter.o ) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 40ed9744..5894d5ae 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -18,16 +18,74 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ +#include "nextpnr.h" #include "xdl.h" #include #include #include "cells.h" #include "log.h" +#include "util.h" + +#include "torc/Physical.hpp" +using namespace torc::architecture::xilinx; +using namespace torc::physical; NEXTPNR_NAMESPACE_BEGIN void write_xdl(const Context *ctx, std::ostream &out) { + XdlExporter exporter(out); + auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "", ""); + + std::map site_to_instance; + + for (const auto& cell : ctx->cells) { + const char* type; + if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; + else if (cell.second->type == id_IOB33S) type = "IOB33S"; + else if (cell.second->type == id_BUFGCTRL) type = "BUFGCTRL"; + else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); + + auto ret = site_to_instance.emplace(cell.second->bel.index, nullptr); + InstanceSharedPtr instPtr; + if (ret.second) { + instPtr = Factory::newInstancePtr(cell.second->name.str(ctx), type, "", ""); + auto b = designPtr->addInstance(instPtr); + assert(b); + ret.first->second = instPtr; + + const auto& tile_info = torc_info->site_index_to_tile_info(cell.second->bel.index); + instPtr->setTile(tile_info.getName()); + instPtr->setSite(torc_info->site_index_to_name(cell.second->bel.index)); + } + else + instPtr = ret.first->second; + + if (cell.second->type == id_SLICE_LUT6) { + std::string config(1, cell.second->bel.pos); + config += "6LUT"; + instPtr->setConfig(config, cell.second->name.str(ctx), "#LUT:O6="); + } + else if (cell.second->type == id_IOB33S) { + if (get_net_or_empty(cell.second.get(), id_I)) { + instPtr->setConfig("IUSED", "", "0"); + instPtr->setConfig("IBUF_LOW_PWR", "", "TRUE"); + instPtr->setConfig("ISTANDARD", "", "LVCMOS25"); + } + else { + instPtr->setConfig("OUSED", "", "0"); + instPtr->setConfig("OSTANDARD", "", "LVCMOS25"); + instPtr->setConfig("DRIVE", "", "12"); + instPtr->setConfig("SLEW", "", "SLOW"); + } + } + else if (cell.second->type == id_BUFGCTRL) { + } + else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); + } + + exporter(designPtr); + } NEXTPNR_NAMESPACE_END From 17918b59920bcee376e5b749ce9f89a01de62b8b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 17 Aug 2018 23:05:12 -0700 Subject: [PATCH 022/174] Fix for multiple id_SLICE_LUT6 per actual SLICE --- xc7/arch.cc | 106 +++++++++++++++++++++++++++++-------------------- xc7/arch.h | 71 ++++++++++++++++++--------------- xc7/archdefs.h | 8 ++-- xc7/xdl.cc | 18 ++++++--- 4 files changed, 117 insertions(+), 86 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ce7c5c1a..05d0841a 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,17 +35,36 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), site_index_to_type(construct_site_index_to_type(ctx, sites)), site_index_to_z_offset(construct_site_index_to_z_offset(sites, site_index_to_type)) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)) { } +std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) +{ + std::vector bel_to_site_index; + bel_to_site_index.reserve(sites.getSiteCount()); + for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { + const auto &s = sites.getSite(i); + const auto &pd = s.getPrimitiveDefPtr(); + const auto &type = pd->getName(); + if (type == "SLICEL" || type == "SLICEM") { + bel_to_site_index.push_back(i); + bel_to_site_index.push_back(i); + bel_to_site_index.push_back(i); + bel_to_site_index.push_back(i); + } + else + bel_to_site_index.push_back(i); + } + return bel_to_site_index; +} std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Sites &sites) { std::vector site_index_to_type; site_index_to_type.resize(sites.getSiteCount()); for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { - auto s = sites.getSite(i); - auto pd = s.getPrimitiveDefPtr(); - auto type = pd->getName(); + const auto &s = sites.getSite(i); + const auto &pd = s.getPrimitiveDefPtr(); + const auto &type = pd->getName(); if (type == "SLICEL" || type == "SLICEM") site_index_to_type[i] = id_SLICE_LUT6; else @@ -53,20 +72,33 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si } return site_index_to_type; } -std::vector TorcInfo::construct_site_index_to_z_offset(const Sites &sites, const std::vector &site_index_to_type) +std::vector TorcInfo::construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type) { - std::vector site_index_to_z_offset; - site_index_to_z_offset.resize(site_index_to_type.size()); + std::vector bel_to_z; + bel_to_z.resize(num_bels); + int32_t bel_index = 0; for (SiteIndex i(0); i < site_index_to_type.size(); ++i) { if (site_index_to_type[i] == id_SLICE_LUT6) { auto site = sites.getSite(i); auto site_name = site.getName(); auto site_name_back = site_name.back(); - if (site_name_back == '1' || site_name_back == '3' || site_name_back == '5' || site_name_back == '7' || site_name_back == '9') - site_index_to_z_offset[i] = 4; + if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || site_name_back == '8') { + bel_to_z[bel_index++] = 0; + bel_to_z[bel_index++] = 1; + bel_to_z[bel_index++] = 2; + bel_to_z[bel_index++] = 3; + } + else { + bel_to_z[bel_index++] = 4; + bel_to_z[bel_index++] = 5; + bel_to_z[bel_index++] = 6; + bel_to_z[bel_index++] = 7; + } } + else + ++bel_index; } - return site_index_to_z_offset; + return bel_to_z; } @@ -100,7 +132,7 @@ Arch::Arch(ArchArgs args) : args(args) // if (package_info == nullptr) // log_error("Unsupported package '%s'.\n", args.package.c_str()); - bel_to_cell.resize(torc_info->sites.getSiteCount()); + bel_to_cell.resize(torc_info->num_bels); } // ----------------------------------------------------------------------- @@ -141,18 +173,9 @@ BelId Arch::getBelByLocation(Loc loc) const BelId bel; if (bel_by_loc.empty()) { - for (SiteIndex i(0); i < torc_info->sites.getSiteCount(); ++i) { + for (int i = 0; i < torc_info->num_bels; i++) { BelId b; b.index = i; - if (torc_info->site_index_to_type[i] == id_SLICE_LUT6) { - b.pos = BelId::A; - bel_by_loc[getBelLocation(b)] = b; - b.pos = BelId::B; - bel_by_loc[getBelLocation(b)] = b; - b.pos = BelId::C; - bel_by_loc[getBelLocation(b)] = b; - b.pos = BelId::D; - } bel_by_loc[getBelLocation(b)] = b; } } @@ -168,14 +191,13 @@ BelRange Arch::getBelsByTile(int x, int y) const { BelRange br; - auto b = getBelByLocation(Loc(x, y, 0)); - br.b.index = b.index; - br.b.pos = b.pos; - br.e = br.b; + br.b.cursor = Arch::getBelByLocation(Loc(x, y, 0)).index; + br.e.cursor = br.b.cursor; - if (br.e.index != SiteIndex(torc_info->sites.getSiteCount())) { - while (br.e.index < SiteIndex(torc_info->sites.getSiteCount()) && torc_info->sites.getSite((*br.e).index).getTileIndex() == torc_info->sites.getSite((*br.b).index).getTileIndex()) - br.e++; + if (br.e.cursor != -1) { + while (br.e.cursor < chip_info->num_bels && chip_info->bel_data[br.e.cursor].x == x && + chip_info->bel_data[br.e.cursor].y == y) + br.e.cursor++; } return br; @@ -213,17 +235,25 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - auto &site = torc_info->sites.getSite(bel.index); + auto site_index = torc_info->bel_to_site_index[bel.index]; auto pin_name = pin.str(this); - if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { + if (torc_info->site_index_to_type[site_index] == id_SLICE_LUT6) { // For all LUT based inputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT - if (pin_name[0] == 'I' || pin_name[0] == 'O') - pin_name[0] = bel.pos; + if (pin_name[0] == 'I' || pin_name[0] == 'O') { + switch (torc_info->bel_to_z[bel.index]) { + case 0: case 4: pin_name[0] = 'A'; break; + case 1: case 5: pin_name[0] = 'B'; break; + case 2: case 6: pin_name[0] = 'C'; break; + case 3: case 7: pin_name[0] = 'D'; break; + default: throw; + } + } } + auto &site = torc_info->sites.getSite(site_index); ret.index = site.getPinTilewire(pin_name); if (ret.index.isUndefined()) - log_error("no wire found for site '%s' pin '%s' \n", torc_info->site_index_to_name(bel.index).c_str(), pin_name.c_str()); + log_error("no wire found for site '%s' pin '%s' \n", torc_info->bel_to_name(bel.index).c_str(), pin_name.c_str()); // NPNR_ASSERT(bel != BelId()); @@ -823,14 +853,4 @@ void Arch::assignCellInfo(CellInfo *cell) } } -void operator++(BelId::bel &b) { - switch (b) { - case BelId::A: b = BelId::B; return; - case BelId::B: b = BelId::C; return; - case BelId::C: b = BelId::D; return; - default: break; - } - throw; -} - NEXTPNR_NAMESPACE_END diff --git a/xc7/arch.h b/xc7/arch.h index 379369c6..60039240 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -240,56 +240,57 @@ struct TorcInfo { const Sites &sites; const Tiles &tiles; - SiteIndex sites_begin() const { return SiteIndex(0); } - SiteIndex sites_end() const { return SiteIndex(sites.getSiteCount()); } - const TileInfo& site_index_to_tile_info(SiteIndex si) const { + const TileInfo& bel_to_tile_info(int32_t index) const { + auto si = bel_to_site_index[index]; auto &site = sites.getSite(si); return tiles.getTileInfo(site.getTileIndex()); } - const std::string& site_index_to_name(SiteIndex si) const { + const std::string& bel_to_name(int32_t index) const { + auto si = bel_to_site_index[index]; return sites.getSite(si).getName(); } + const std::vector bel_to_site_index; + const int num_bels; const std::vector site_index_to_type; - const std::vector site_index_to_z_offset; + const std::vector bel_to_z; private: + static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); - static std::vector construct_site_index_to_z_offset(const Sites &sites, const std::vector &site_index_to_type); + static std::vector construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type); }; extern std::unique_ptr torc_info; /************************ End of chipdb section. ************************/ -struct BelIterator : public BelId +struct BelIterator { + int cursor; + BelIterator operator++() { - if (pos >= A && pos < D) { - ++pos; - return *this; - } - - if (torc_info->site_index_to_type[++index] == id_SLICE_LUT6) - pos = A; - else - pos = NOT_APPLICABLE; - + cursor++; return *this; } BelIterator operator++(int) { BelIterator prior(*this); - operator++(); + cursor++; return prior; } - bool operator!=(const BelIterator &other) const { return BelId::operator!=(other); } + bool operator!=(const BelIterator &other) const { return cursor != other.cursor; } - bool operator==(const BelIterator &other) const { return BelId::operator==(other); } + bool operator==(const BelIterator &other) const { return cursor == other.cursor; } - BelId operator*() const { return *this; } + BelId operator*() const + { + BelId ret; + ret.index = cursor; + return ret; + } }; struct BelRange @@ -447,12 +448,19 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - auto name = torc_info->site_index_to_name(bel.index); - if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { + auto name = torc_info->bel_to_name(bel.index); + auto site_index = torc_info->bel_to_site_index[bel.index]; + if (torc_info->site_index_to_type[site_index] == id_SLICE_LUT6) { // Append LUT name to name name.reserve(name.size() + 2); name += "_"; - name += bel.pos; + switch (torc_info->bel_to_z[bel.index]) { + case 0: case 4: name += 'A'; break; + case 1: case 5: name += 'B'; break; + case 2: case 6: name += 'C'; break; + case 3: case 7: name += 'D'; break; + default: throw; + } } return id(name); } @@ -503,23 +511,19 @@ struct Arch : BaseCtx BelRange getBels() const { BelRange range; - range.b.index = torc_info->sites_begin(); - range.e.index = torc_info->sites_end(); + range.b.cursor = 0; + range.e.cursor = torc_info->num_bels; return range; } Loc getBelLocation(BelId bel) const { - auto &tile_info = torc_info->site_index_to_tile_info(bel.index); + auto &tile_info = torc_info->bel_to_tile_info(bel.index); Loc loc; loc.x = tile_info.getCol(); loc.y = tile_info.getRow(); - if (torc_info->site_index_to_type[bel.index] == id_SLICE_LUT6) { - loc.z = bel.pos - 'A'; - // Apply offset if upper slice - loc.z += torc_info->site_index_to_z_offset[bel.index]; - } + loc.z = torc_info->bel_to_z[bel.index]; return loc; } @@ -531,7 +535,8 @@ struct Arch : BaseCtx IdString getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return torc_info->site_index_to_type[bel.index]; + auto site_index = torc_info->bel_to_site_index[bel.index]; + return torc_info->site_index_to_type[site_index]; } WireId getBelPinWire(BelId bel, IdString pin) const; diff --git a/xc7/archdefs.h b/xc7/archdefs.h index 9c0efc70..9f0f8382 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -66,13 +66,11 @@ enum ConstIds struct BelId { - SiteIndex index = SiteIndex(-1); - enum bel : int8_t { NOT_APPLICABLE, A='A', B='B', C='C', D='D' } pos = NOT_APPLICABLE; + int32_t index = -1; - bool operator==(const BelId &other) const { return index == other.index && pos == pos; } - bool operator!=(const BelId &other) const { return index != other.index || pos != pos; } + bool operator==(const BelId &other) const { return index == other.index; } + bool operator!=(const BelId &other) const { return index != other.index; } }; -void operator++(BelId::bel &b); struct WireId { diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 5894d5ae..c627c4db 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -37,7 +37,7 @@ void write_xdl(const Context *ctx, std::ostream &out) XdlExporter exporter(out); auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "", ""); - std::map site_to_instance; + std::unordered_map site_to_instance; for (const auto& cell : ctx->cells) { const char* type; @@ -46,7 +46,8 @@ void write_xdl(const Context *ctx, std::ostream &out) else if (cell.second->type == id_BUFGCTRL) type = "BUFGCTRL"; else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); - auto ret = site_to_instance.emplace(cell.second->bel.index, nullptr); + auto site_index = torc_info->bel_to_site_index[cell.second->bel.index]; + auto ret = site_to_instance.emplace(site_index, nullptr); InstanceSharedPtr instPtr; if (ret.second) { instPtr = Factory::newInstancePtr(cell.second->name.str(ctx), type, "", ""); @@ -54,15 +55,22 @@ void write_xdl(const Context *ctx, std::ostream &out) assert(b); ret.first->second = instPtr; - const auto& tile_info = torc_info->site_index_to_tile_info(cell.second->bel.index); + const auto& tile_info = torc_info->bel_to_tile_info(cell.second->bel.index); instPtr->setTile(tile_info.getName()); - instPtr->setSite(torc_info->site_index_to_name(cell.second->bel.index)); + instPtr->setSite(torc_info->bel_to_name(cell.second->bel.index)); } else instPtr = ret.first->second; if (cell.second->type == id_SLICE_LUT6) { - std::string config(1, cell.second->bel.pos); + std::string config; + switch (torc_info->bel_to_z[cell.second->bel.index]) { + case 0: case 4: config += 'A'; break; + case 1: case 5: config += 'B'; break; + case 2: case 6: config += 'C'; break; + case 3: case 7: config += 'D'; break; + default: throw; + } config += "6LUT"; instPtr->setConfig(config, cell.second->name.str(ctx), "#LUT:O6="); } From a7ccc01c4575a17e07d86286e13af57c637b67b9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 17:38:55 -0700 Subject: [PATCH 023/174] Use getBelType() --- xc7/arch.cc | 4 ++-- xc7/arch.h | 3 +-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 05d0841a..892fe1ec 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -235,9 +235,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const { WireId ret; - auto site_index = torc_info->bel_to_site_index[bel.index]; auto pin_name = pin.str(this); - if (torc_info->site_index_to_type[site_index] == id_SLICE_LUT6) { + if (getBelType(bel) == id_SLICE_LUT6) { // For all LUT based inputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { switch (torc_info->bel_to_z[bel.index]) { @@ -249,6 +248,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const } } } + auto site_index = torc_info->bel_to_site_index[bel.index]; auto &site = torc_info->sites.getSite(site_index); ret.index = site.getPinTilewire(pin_name); diff --git a/xc7/arch.h b/xc7/arch.h index 60039240..cb504016 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -449,8 +449,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(bel != BelId()); auto name = torc_info->bel_to_name(bel.index); - auto site_index = torc_info->bel_to_site_index[bel.index]; - if (torc_info->site_index_to_type[site_index] == id_SLICE_LUT6) { + if (getBelType(bel) == id_SLICE_LUT6) { // Append LUT name to name name.reserve(name.size() + 2); name += "_"; From 07fb4702ceae5c5b03864bb0c961c40edbb2d955 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 19:16:24 -0700 Subject: [PATCH 024/174] Populate LUT masks --- xc7/cells.cc | 6 ++--- xc7/pack.cc | 6 ++--- xc7/xdl.cc | 73 +++++++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 72 insertions(+), 13 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index c43af075..f5f23f5a 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -44,7 +44,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri new_cell->type = type; if (type == ctx->id("XC7_LC")) { new_cell->type = id_SLICE_LUT6; - new_cell->params[ctx->id("LUT_INIT")] = "0"; + new_cell->params[ctx->id("INIT")] = "0"; new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; new_cell->params[ctx->id("DFF_ENABLE")] = "0"; @@ -258,7 +258,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { - lc->params[ctx->id("LUT_INIT")] = lut->params[ctx->id("LUT_INIT")]; + lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; replace_port(lut, ctx->id("I0"), lc, id_I1); if (get_net_or_empty(lut, id_I1)) replace_port(lut, id_I1, lc, id_I2); @@ -317,7 +317,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l NPNR_ASSERT(citer == config.end()); if (pass_thru_lut) { - lc->params[ctx->id("LUT_INIT")] = "2"; + lc->params[ctx->id("INIT")] = "1"; replace_port(dff, ctx->id("D"), lc, id_I1); } diff --git a/xc7/pack.cc b/xc7/pack.cc index 1e27f8a3..ee9682f1 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -332,7 +332,7 @@ static void pack_constants(Context *ctx) log_info("Packing constants..\n"); std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_GND"); - gnd_cell->params[ctx->id("LUT_INIT")] = "0"; + gnd_cell->params[ctx->id("INIT")] = "0"; std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); gnd_net->driver.cell = gnd_cell.get(); @@ -340,7 +340,7 @@ static void pack_constants(Context *ctx) gnd_cell->ports.at(id_O).net = gnd_net.get(); std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); - vcc_cell->params[ctx->id("LUT_INIT")] = "1"; + vcc_cell->params[ctx->id("INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); vcc_net->driver.cell = vcc_cell.get(); @@ -585,7 +585,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString // Create pass-through LUT. std::unique_ptr pt = create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); - pt->params[ctx->id("LUT_INIT")] = "65280"; // output is always I3 + pt->params[ctx->id("INIT")] = "65280"; // output is always I3 // Create LUT output net. std::unique_ptr out_net = std::unique_ptr(new NetInfo); diff --git a/xc7/xdl.cc b/xc7/xdl.cc index c627c4db..cb7157ab 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -38,6 +38,8 @@ void write_xdl(const Context *ctx, std::ostream &out) auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "", ""); std::unordered_map site_to_instance; + std::vector> lut_inputs; + lut_inputs.reserve(6); for (const auto& cell : ctx->cells) { const char* type; @@ -63,16 +65,73 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr = ret.first->second; if (cell.second->type == id_SLICE_LUT6) { - std::string config; + std::string setting, value; + std::string lut; switch (torc_info->bel_to_z[cell.second->bel.index]) { - case 0: case 4: config += 'A'; break; - case 1: case 5: config += 'B'; break; - case 2: case 6: config += 'C'; break; - case 3: case 7: config += 'D'; break; + case 0: case 4: lut = 'A'; break; + case 1: case 5: lut = 'B'; break; + case 2: case 6: lut = 'C'; break; + case 3: case 7: lut = 'D'; break; default: throw; } - config += "6LUT"; - instPtr->setConfig(config, cell.second->name.str(ctx), "#LUT:O6="); + + setting = lut + "6LUT"; + value = "#LUT:O6="; + lut_inputs.clear(); + if (get_net_or_empty(cell.second.get(), id_I1)) lut_inputs.emplace_back(lut + "1", "~" + lut + "1"); + if (get_net_or_empty(cell.second.get(), id_I2)) lut_inputs.emplace_back(lut + "2", "~" + lut + "2"); + if (get_net_or_empty(cell.second.get(), id_I3)) lut_inputs.emplace_back(lut + "3", "~" + lut + "3"); + if (get_net_or_empty(cell.second.get(), id_I4)) lut_inputs.emplace_back(lut + "4", "~" + lut + "4"); + if (get_net_or_empty(cell.second.get(), id_I5)) lut_inputs.emplace_back(lut + "5", "~" + lut + "5"); + if (get_net_or_empty(cell.second.get(), id_I6)) lut_inputs.emplace_back(lut + "6", "~" + lut + "6"); + const auto& init = cell.second->params[ctx->id("INIT")]; + // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t + if (lut_inputs.size() < 6) { + auto init_as_uint = boost::lexical_cast(init); + NPNR_ASSERT(init_as_uint < (1ull << (1u << lut_inputs.size()))); + if (lut_inputs.empty()) + value += init; + else + for (unsigned o = 0; o < (1u << lut_inputs.size()); ++o) { + if ((init_as_uint >> o) & 0x1) continue; + if (o > 0) value += "+"; + value += "("; + value += (o & 1) ? lut_inputs[0].first : lut_inputs[0].second; + for (unsigned i = 1; i < lut_inputs.size(); ++i) { + value += "*"; + value += o & (1 << i) ? lut_inputs[i].first : lut_inputs[i].second; + } + value += ")"; + } + } + // Otherwise as a bit string + else { + NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); + for (unsigned i = 0; i < (1u << lut_inputs.size()); ++i) { + if (init[i] == '0') continue; + if (i > 0) value += "+"; + value += "("; + value += (i & 1) ? lut_inputs[0].first : lut_inputs[0].second; + for (unsigned i = 1; i < lut_inputs.size(); ++i) { + value += "*"; + value += i & (1 << i) ? lut_inputs[i].first : lut_inputs[i].second; + } + value += ")"; + } + } + + auto O = get_net_or_empty(cell.second.get(), id_O); + if (O) + instPtr->setConfig(setting, O->name.str(ctx), value); + else + instPtr->setConfig(setting, cell.second->name.str(ctx), value); + + auto OQ = get_net_or_empty(cell.second.get(), id_OQ); + if (OQ) { + setting = lut; + setting += "FF"; + instPtr->setConfig(setting, OQ->name.c_str(ctx), "#FF"); + } } else if (cell.second->type == id_IOB33S) { if (get_net_or_empty(cell.second.get(), id_I)) { From dcc08b27cce0cdffdf9cb952c23a85b4a8c25a94 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 19:41:11 -0700 Subject: [PATCH 025/174] Output unrouted nets into XDL --- xc7/xdl.cc | 54 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 8 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index cb7157ab..2ae566b9 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -41,6 +41,16 @@ void write_xdl(const Context *ctx, std::ostream &out) std::vector> lut_inputs; lut_inputs.reserve(6); + auto bel_to_lut = [](const BelId bel) { + switch (torc_info->bel_to_z[bel.index]) { + case 0: case 4: return "A"; break; + case 1: case 5: return "B"; break; + case 2: case 6: return "C"; break; + case 3: case 7: return "D"; break; + default: throw; + } + }; + for (const auto& cell : ctx->cells) { const char* type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; @@ -66,14 +76,7 @@ void write_xdl(const Context *ctx, std::ostream &out) if (cell.second->type == id_SLICE_LUT6) { std::string setting, value; - std::string lut; - switch (torc_info->bel_to_z[cell.second->bel.index]) { - case 0: case 4: lut = 'A'; break; - case 1: case 5: lut = 'B'; break; - case 2: case 6: lut = 'C'; break; - case 3: case 7: lut = 'D'; break; - default: throw; - } + const std::string lut = bel_to_lut(cell.second->bel); setting = lut + "6LUT"; value = "#LUT:O6="; @@ -151,6 +154,41 @@ void write_xdl(const Context *ctx, std::ostream &out) else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } + for (const auto &net : ctx->nets) { + const auto &driver = net.second->driver; + + auto site_index = torc_info->bel_to_site_index[driver.cell->bel.index]; + auto instPtr = site_to_instance.at(site_index); + + auto netPtr = Factory::newNetPtr(net.second->name.str(ctx)); + + auto pin_name = driver.port.str(ctx); + // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT + if (driver.cell->type == id_SLICE_LUT6 && (pin_name[0] == 'I' || pin_name[0] == 'O')) { + const auto lut = bel_to_lut(driver.cell->bel); + pin_name[0] = lut[0]; + } + auto pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); + netPtr->addSource(pinPtr); + + for (const auto &user : net.second->users) { + site_index = torc_info->bel_to_site_index[user.cell->bel.index]; + instPtr = site_to_instance.at(site_index); + + pin_name = user.port.str(ctx); + // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT + if (user.cell->type == id_SLICE_LUT6 && (pin_name[0] == 'I' || pin_name[0] == 'O')) { + const auto lut = bel_to_lut(user.cell->bel); + pin_name[0] = lut[0]; + } + pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); + netPtr->addSink(pinPtr); + } + + auto b = designPtr->addNet(netPtr); + assert(b); + } + exporter(designPtr); } From a87f26b25411b8bb272746da5be751dad7995d38 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 19:41:24 -0700 Subject: [PATCH 026/174] Update comment --- xc7/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 892fe1ec..df21c208 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -237,7 +237,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const auto pin_name = pin.str(this); if (getBelType(bel) == id_SLICE_LUT6) { - // For all LUT based inputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT + // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { switch (torc_info->bel_to_z[bel.index]) { case 0: case 4: pin_name[0] = 'A'; break; From 699bd3ef5aac988c9ba6a8c06ac90c8de07a40d7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 19 Aug 2018 22:31:50 -0700 Subject: [PATCH 027/174] Fix for leading '+', and use An for LUT masks --- xc7/xdl.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 2ae566b9..99345174 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -81,12 +81,12 @@ void write_xdl(const Context *ctx, std::ostream &out) setting = lut + "6LUT"; value = "#LUT:O6="; lut_inputs.clear(); - if (get_net_or_empty(cell.second.get(), id_I1)) lut_inputs.emplace_back(lut + "1", "~" + lut + "1"); - if (get_net_or_empty(cell.second.get(), id_I2)) lut_inputs.emplace_back(lut + "2", "~" + lut + "2"); - if (get_net_or_empty(cell.second.get(), id_I3)) lut_inputs.emplace_back(lut + "3", "~" + lut + "3"); - if (get_net_or_empty(cell.second.get(), id_I4)) lut_inputs.emplace_back(lut + "4", "~" + lut + "4"); - if (get_net_or_empty(cell.second.get(), id_I5)) lut_inputs.emplace_back(lut + "5", "~" + lut + "5"); - if (get_net_or_empty(cell.second.get(), id_I6)) lut_inputs.emplace_back(lut + "6", "~" + lut + "6"); + if (get_net_or_empty(cell.second.get(), id_I1)) lut_inputs.emplace_back("A1", "~A1"); + if (get_net_or_empty(cell.second.get(), id_I2)) lut_inputs.emplace_back("A2", "~A2"); + if (get_net_or_empty(cell.second.get(), id_I3)) lut_inputs.emplace_back("A3", "~A3"); + if (get_net_or_empty(cell.second.get(), id_I4)) lut_inputs.emplace_back("A4", "~A4"); + if (get_net_or_empty(cell.second.get(), id_I5)) lut_inputs.emplace_back("A5", "~A5"); + if (get_net_or_empty(cell.second.get(), id_I6)) lut_inputs.emplace_back("A6", "~A6"); const auto& init = cell.second->params[ctx->id("INIT")]; // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t if (lut_inputs.size() < 6) { @@ -110,14 +110,15 @@ void write_xdl(const Context *ctx, std::ostream &out) // Otherwise as a bit string else { NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); + unsigned n = 0; for (unsigned i = 0; i < (1u << lut_inputs.size()); ++i) { if (init[i] == '0') continue; - if (i > 0) value += "+"; + if (n++ > 0) value += "+"; value += "("; value += (i & 1) ? lut_inputs[0].first : lut_inputs[0].second; - for (unsigned i = 1; i < lut_inputs.size(); ++i) { + for (unsigned j = 1; j < lut_inputs.size(); ++j) { value += "*"; - value += i & (1 << i) ? lut_inputs[i].first : lut_inputs[i].second; + value += i & (1 << j) ? lut_inputs[j].first : lut_inputs[j].second; } value += ")"; } From 718f5b81f040fd38171f9691bdd8dd675a40d872 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Aug 2018 19:19:45 -0700 Subject: [PATCH 028/174] Escape colons in config names --- xc7/xdl.cc | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 99345174..3cbd8164 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -125,10 +125,13 @@ void write_xdl(const Context *ctx, std::ostream &out) } auto O = get_net_or_empty(cell.second.get(), id_O); + std::string lut_name; if (O) - instPtr->setConfig(setting, O->name.str(ctx), value); + lut_name = O->name.str(ctx); else - instPtr->setConfig(setting, cell.second->name.str(ctx), value); + lut_name = cell.second->name.str(ctx); + boost::replace_all(lut_name, ":", "\\:"); + instPtr->setConfig(setting, lut_name, value); auto OQ = get_net_or_empty(cell.second.get(), id_OQ); if (OQ) { From f7be783a327cafd48b75946f59388462f868fc08 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Aug 2018 19:21:53 -0700 Subject: [PATCH 029/174] Escape flop names as well --- xc7/xdl.cc | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 3cbd8164..f2aed473 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -75,7 +75,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr = ret.first->second; if (cell.second->type == id_SLICE_LUT6) { - std::string setting, value; + std::string setting, name, value; const std::string lut = bel_to_lut(cell.second->bel); setting = lut + "6LUT"; @@ -125,19 +125,20 @@ void write_xdl(const Context *ctx, std::ostream &out) } auto O = get_net_or_empty(cell.second.get(), id_O); - std::string lut_name; if (O) - lut_name = O->name.str(ctx); + name = O->name.str(ctx); else - lut_name = cell.second->name.str(ctx); - boost::replace_all(lut_name, ":", "\\:"); - instPtr->setConfig(setting, lut_name, value); + name = cell.second->name.str(ctx); + boost::replace_all(name, ":", "\\:"); + instPtr->setConfig(setting, name, value); auto OQ = get_net_or_empty(cell.second.get(), id_OQ); if (OQ) { setting = lut; setting += "FF"; - instPtr->setConfig(setting, OQ->name.c_str(ctx), "#FF"); + name = OQ->name.str(ctx); + boost::replace_all(name, ":", "\\:"); + instPtr->setConfig(setting, name, "#FF"); } } else if (cell.second->type == id_IOB33S) { From 3e1085ecb5d16a3fed2d3dab4d43557e578b1664 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Aug 2018 19:25:54 -0700 Subject: [PATCH 030/174] Combine IOB33S and IOB33M --- xc7/arch.cc | 4 +++- xc7/cells.cc | 2 +- xc7/constids.inc | 4 +--- xc7/xdl.cc | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index df21c208..764d2231 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -67,6 +67,8 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si const auto &type = pd->getName(); if (type == "SLICEL" || type == "SLICEM") site_index_to_type[i] = id_SLICE_LUT6; + else if (type == "IOB33S" || type == "IOB33M") + site_index_to_type[i] = id_IOB; else site_index_to_type[i] = ctx->id(type); } @@ -788,7 +790,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id // TODO //if (port == id_OMUX) } - else if (cell->type == id_IOB33S) { + else if (cell->type == id_IOB) { if (port == id_I) return TMG_STARTPOINT; else if (port == id_O) diff --git a/xc7/cells.cc b/xc7/cells.cc index f5f23f5a..dbdc4b82 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -70,7 +70,7 @@ std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { - new_cell->type = id_IOB33S; + new_cell->type = id_IOB; new_cell->params[ctx->id("PIN_TYPE")] = "0"; new_cell->params[ctx->id("PULLUP")] = "0"; new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; diff --git a/xc7/constids.inc b/xc7/constids.inc index 8e07efd9..c760bdb0 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -456,6 +456,4 @@ X(FDPE) X(BUFGCTRL) X(SLICE_LUT6) -X(IOBUF) -X(IOB33S) -X(IOB33M) // What is the difference between IOB33S and IOB33M? +X(IOB) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index f2aed473..3fa20d5a 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -54,7 +54,7 @@ void write_xdl(const Context *ctx, std::ostream &out) for (const auto& cell : ctx->cells) { const char* type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33S) type = "IOB33S"; + else if (cell.second->type == id_IOB) type = "IOB33S"; else if (cell.second->type == id_BUFGCTRL) type = "BUFGCTRL"; else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -141,7 +141,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig(setting, name, "#FF"); } } - else if (cell.second->type == id_IOB33S) { + else if (cell.second->type == id_IOB) { if (get_net_or_empty(cell.second.get(), id_I)) { instPtr->setConfig("IUSED", "", "0"); instPtr->setConfig("IBUF_LOW_PWR", "", "TRUE"); From 0a16e24c82c5bffc32c18584da3cbe9e1454f0a5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Aug 2018 19:29:04 -0700 Subject: [PATCH 031/174] create_ice_cell -> create_xc7_cell --- xc7/cells.cc | 2 +- xc7/cells.h | 4 ++-- xc7/chains.cc | 4 ++-- xc7/pack.cc | 28 ++++++++++++++-------------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index dbdc4b82..9a26e9ea 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -32,7 +32,7 @@ void add_port(const Context *ctx, CellInfo *cell, std::string name, PortType dir cell->ports[id] = PortInfo{id, nullptr, dir}; } -std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::string name) +std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::string name) { static int auto_idx = 0; std::unique_ptr new_cell = std::unique_ptr(new CellInfo()); diff --git a/xc7/cells.h b/xc7/cells.h index 3f671f2a..de323b36 100644 --- a/xc7/cells.h +++ b/xc7/cells.h @@ -25,9 +25,9 @@ NEXTPNR_NAMESPACE_BEGIN -// Create a standard iCE40 cell and return it +// Create a standard xc7 cell and return it // Name will be automatically assigned if not specified -std::unique_ptr create_ice_cell(Context *ctx, IdString type, std::string name = ""); +std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_LUT1 || cell->type == id_LUT2 || cell->type == id_LUT3 || cell->type == id_LUT4 || cell->type == id_LUT5 || cell->type == id_LUT6; } diff --git a/xc7/chains.cc b/xc7/chains.cc index bb20b60b..407b72ff 100644 --- a/xc7/chains.cc +++ b/xc7/chains.cc @@ -127,7 +127,7 @@ class ChainConstrainer CellInfo *make_carry_pass_out(PortInfo &cout_port) { NPNR_ASSERT(cout_port.net != nullptr); - std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + std::unique_ptr lc = create_xc7_cell(ctx, ctx->id("ICESTORM_LC")); lc->params[ctx->id("LUT_INIT")] = "65280"; // 0xff00: O = I3 lc->params[ctx->id("CARRY_ENABLE")] = "1"; lc->ports.at(ctx->id("O")).net = cout_port.net; @@ -158,7 +158,7 @@ class ChainConstrainer CellInfo *make_carry_feed_in(CellInfo *cin_cell, PortInfo &cin_port) { NPNR_ASSERT(cin_port.net != nullptr); - std::unique_ptr lc = create_ice_cell(ctx, ctx->id("ICESTORM_LC")); + std::unique_ptr lc = create_xc7_cell(ctx, ctx->id("ICESTORM_LC")); lc->params[ctx->id("CARRY_ENABLE")] = "1"; lc->params[ctx->id("CIN_CONST")] = "1"; lc->params[ctx->id("CIN_SET")] = "1"; diff --git a/xc7/pack.cc b/xc7/pack.cc index ee9682f1..8175685c 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -42,7 +42,7 @@ static void pack_lut_lutffs(Context *ctx) if (ctx->verbose) log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); if (is_lut(ctx, ci)) { - std::unique_ptr packed = create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_LC"); + std::unique_ptr packed = create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); if (ctx->verbose) @@ -97,7 +97,7 @@ static void pack_nonlut_ffs(Context *ctx) CellInfo *ci = cell.second; if (is_ff(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_DFFLC"); + create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); if (ctx->verbose) log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); @@ -192,7 +192,7 @@ static void pack_carries(Context *ctx) } else { // No LC to pack into matching I0/I1, insert a new one std::unique_ptr created_lc = - create_ice_cell(ctx, ctx->id("XC7_LC"), cell.first.str(ctx) + "$CARRY"); + create_xc7_cell(ctx, ctx->id("XC7_LC"), cell.first.str(ctx) + "$CARRY"); carry_lc = created_lc.get(); created_lc->ports.at(ctx->id("I1")).net = i0_net; if (i0_net) { @@ -263,7 +263,7 @@ static void pack_ram(Context *ctx) CellInfo *ci = cell.second; if (is_ram(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM"); + create_xc7_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM"); packed_cells.insert(ci->name); for (auto param : ci->params) packed->params[param.first] = param.second; @@ -331,7 +331,7 @@ static void pack_constants(Context *ctx) { log_info("Packing constants..\n"); - std::unique_ptr gnd_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_GND"); + std::unique_ptr gnd_cell = create_xc7_cell(ctx, ctx->id("XC7_LC"), "$PACKER_GND"); gnd_cell->params[ctx->id("INIT")] = "0"; std::unique_ptr gnd_net = std::unique_ptr(new NetInfo); gnd_net->name = ctx->id("$PACKER_GND_NET"); @@ -339,7 +339,7 @@ static void pack_constants(Context *ctx) gnd_net->driver.port = id_O; gnd_cell->ports.at(id_O).net = gnd_net.get(); - std::unique_ptr vcc_cell = create_ice_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); + std::unique_ptr vcc_cell = create_xc7_cell(ctx, ctx->id("XC7_LC"), "$PACKER_VCC"); vcc_cell->params[ctx->id("INIT")] = "1"; std::unique_ptr vcc_net = std::unique_ptr(new NetInfo); vcc_net->name = ctx->id("$PACKER_VCC_NET"); @@ -423,7 +423,7 @@ static void pack_io(Context *ctx) } else { // Create a IOBUF buffer std::unique_ptr ice_cell = - create_ice_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); + create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); nxio_to_sb(ctx, ci, ice_cell.get()); new_cells.push_back(std::move(ice_cell)); sb = new_cells.back().get(); @@ -453,7 +453,7 @@ static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen { asm("int3"); std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); - std::unique_ptr gb = create_ice_cell(ctx, id_BUFGCTRL, "$bufg_" + glb_name); + std::unique_ptr gb = create_xc7_cell(ctx, id_BUFGCTRL, "$bufg_" + glb_name); gb->ports[ctx->id("I0")].net = net; PortRef pr; pr.cell = gb.get(); @@ -583,7 +583,7 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString NPNR_ASSERT(port.net != nullptr); // Create pass-through LUT. - std::unique_ptr pt = create_ice_cell(ctx, ctx->id("XC7_LC"), + std::unique_ptr pt = create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); pt->params[ctx->id("INIT")] = "65280"; // output is always I3 @@ -636,7 +636,7 @@ static void pack_special(Context *ctx) CellInfo *ci = cell.second; if (is_sb_lfosc(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); + create_xc7_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); packed_cells.insert(ci->name); replace_port(ci, ctx->id("CLKLFEN"), packed.get(), ctx->id("CLKLFEN")); replace_port(ci, ctx->id("CLKLFPU"), packed.get(), ctx->id("CLKLFPU")); @@ -648,7 +648,7 @@ static void pack_special(Context *ctx) new_cells.push_back(std::move(packed)); } else if (is_sb_hfosc(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_HFOSC"), ci->name.str(ctx) + "_OSC"); + create_xc7_cell(ctx, ctx->id("ICESTORM_HFOSC"), ci->name.str(ctx) + "_OSC"); packed_cells.insert(ci->name); packed->params[ctx->id("CLKHF_DIV")] = str_or_default(ci->params, ctx->id("CLKHF_DIV"), "0b00"); replace_port(ci, ctx->id("CLKHFEN"), packed.get(), ctx->id("CLKHFEN")); @@ -661,7 +661,7 @@ static void pack_special(Context *ctx) new_cells.push_back(std::move(packed)); } else if (is_sb_spram(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_SPRAM"), ci->name.str(ctx) + "_RAM"); + create_xc7_cell(ctx, ctx->id("ICESTORM_SPRAM"), ci->name.str(ctx) + "_RAM"); packed_cells.insert(ci->name); for (auto port : ci->ports) { PortInfo &pi = port.second; @@ -675,7 +675,7 @@ static void pack_special(Context *ctx) new_cells.push_back(std::move(packed)); } else if (is_sb_mac16(ctx, ci)) { std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP"); + create_xc7_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP"); packed_cells.insert(ci->name); for (auto attr : ci->attrs) packed->attrs[attr.first] = attr.second; @@ -697,7 +697,7 @@ static void pack_special(Context *ctx) bool is_core = !is_pad; std::unique_ptr packed = - create_ice_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); + create_xc7_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); packed->attrs[ctx->id("TYPE")] = ci->type.str(ctx); packed_cells.insert(ci->name); From 5b6255abf1a339a1ba89d7e50fc9bcf87b78a1b1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 20 Aug 2018 21:50:06 -0700 Subject: [PATCH 032/174] Fix LUT masks, add speedgrade, fix IOB type --- xc7/xdl.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 3fa20d5a..df7996d5 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN void write_xdl(const Context *ctx, std::ostream &out) { XdlExporter exporter(out); - auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "", ""); + auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "-1", ""); std::unordered_map site_to_instance; std::vector> lut_inputs; @@ -54,7 +54,12 @@ void write_xdl(const Context *ctx, std::ostream &out) for (const auto& cell : ctx->cells) { const char* type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB) type = "IOB33S"; + else if (cell.second->type == id_IOB) { + auto site_index = torc_info->bel_to_site_index[cell.second->bel.index]; + const auto &site = torc_info->sites.getSite(site_index); + auto prim_def = site.getPrimitiveDefPtr(); + type = prim_def->getName().c_str(); + } else if (cell.second->type == id_BUFGCTRL) type = "BUFGCTRL"; else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -94,10 +99,11 @@ void write_xdl(const Context *ctx, std::ostream &out) NPNR_ASSERT(init_as_uint < (1ull << (1u << lut_inputs.size()))); if (lut_inputs.empty()) value += init; - else + else { + unsigned n = 0; for (unsigned o = 0; o < (1u << lut_inputs.size()); ++o) { if ((init_as_uint >> o) & 0x1) continue; - if (o > 0) value += "+"; + if (n++ > 0) value += "+"; value += "("; value += (o & 1) ? lut_inputs[0].first : lut_inputs[0].second; for (unsigned i = 1; i < lut_inputs.size(); ++i) { @@ -106,6 +112,7 @@ void write_xdl(const Context *ctx, std::ostream &out) } value += ")"; } + } } // Otherwise as a bit string else { @@ -148,7 +155,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("ISTANDARD", "", "LVCMOS25"); } else { - instPtr->setConfig("OUSED", "", "0"); + //instPtr->setConfig("OUSED", "", "0"); instPtr->setConfig("OSTANDARD", "", "LVCMOS25"); instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); From b658a39d73fa99144280d366c6aadc798cc7df96 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Aug 2018 22:18:00 -0700 Subject: [PATCH 033/174] IOB -> IOB33; preserve FF init as DFF_INIT, use BUFGCTRL with PRESELECT_I0 in blinky --- xc7/arch.cc | 4 ++-- xc7/blinky.v | 2 +- xc7/cells.cc | 8 ++++++-- xc7/constids.inc | 2 +- xc7/pack.cc | 1 - xc7/xdl.cc | 28 ++++++++++++++++------------ 6 files changed, 26 insertions(+), 19 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 764d2231..085e2212 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -68,7 +68,7 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si if (type == "SLICEL" || type == "SLICEM") site_index_to_type[i] = id_SLICE_LUT6; else if (type == "IOB33S" || type == "IOB33M") - site_index_to_type[i] = id_IOB; + site_index_to_type[i] = id_IOB33; else site_index_to_type[i] = ctx->id(type); } @@ -790,7 +790,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id // TODO //if (port == id_OMUX) } - else if (cell->type == id_IOB) { + else if (cell->type == id_IOB33) { if (port == id_I) return TMG_STARTPOINT; else if (port == id_O) diff --git a/xc7/blinky.v b/xc7/blinky.v index f636bfcb..547209e8 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -7,7 +7,7 @@ module blinky ( output led5 ); - BUFGCTRL clk_gb ( + BUFGCTRL #(.PRESELECT_I0("TRUE")) clk_gb ( .I0(clki), .O(clk) ); diff --git a/xc7/cells.cc b/xc7/cells.cc index 9a26e9ea..34829f97 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -70,7 +70,7 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { - new_cell->type = id_IOB; + new_cell->type = id_IOB33; new_cell->params[ctx->id("PIN_TYPE")] = "0"; new_cell->params[ctx->id("PULLUP")] = "0"; new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; @@ -130,7 +130,7 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri // add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); // for (int i = 0; i < 10; i++) // add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); - } else if (type == ctx->id("BUFGCTRL")) { + } else if (type == id_BUFGCTRL) { add_port(ctx, new_cell.get(), "I0", PORT_IN); add_port(ctx, new_cell.get(), "O", PORT_OUT); // } else if (type == ctx->id("ICESTORM_SPRAM")) { @@ -322,6 +322,10 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l } replace_port(dff, ctx->id("Q"), lc, id_OQ); + + auto it = dff->params.find(ctx->id("INIT")); + if (it != dff->params.end()) + lc->params[ctx->id("DFF_INIT")] = it->second; } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) diff --git a/xc7/constids.inc b/xc7/constids.inc index c760bdb0..0be998f6 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -456,4 +456,4 @@ X(FDPE) X(BUFGCTRL) X(SLICE_LUT6) -X(IOB) +X(IOB33) diff --git a/xc7/pack.cc b/xc7/pack.cc index 8175685c..05404fdb 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -451,7 +451,6 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) { - asm("int3"); std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); std::unique_ptr gb = create_xc7_cell(ctx, id_BUFGCTRL, "$bufg_" + glb_name); gb->ports[ctx->id("I0")].net = net; diff --git a/xc7/xdl.cc b/xc7/xdl.cc index df7996d5..04238747 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -54,13 +54,7 @@ void write_xdl(const Context *ctx, std::ostream &out) for (const auto& cell : ctx->cells) { const char* type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB) { - auto site_index = torc_info->bel_to_site_index[cell.second->bel.index]; - const auto &site = torc_info->sites.getSite(site_index); - auto prim_def = site.getPrimitiveDefPtr(); - type = prim_def->getName().c_str(); - } - else if (cell.second->type == id_BUFGCTRL) type = "BUFGCTRL"; + else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL) type = cell.second->type.c_str(ctx); else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); auto site_index = torc_info->bel_to_site_index[cell.second->bel.index]; @@ -132,8 +126,10 @@ void write_xdl(const Context *ctx, std::ostream &out) } auto O = get_net_or_empty(cell.second.get(), id_O); - if (O) + if (O) { name = O->name.str(ctx); + instPtr->setConfig(lut + "USED", "", "0"); + } else name = cell.second->name.str(ctx); boost::replace_all(name, ":", "\\:"); @@ -146,22 +142,30 @@ void write_xdl(const Context *ctx, std::ostream &out) name = OQ->name.str(ctx); boost::replace_all(name, ":", "\\:"); instPtr->setConfig(setting, name, "#FF"); + instPtr->setConfig(setting + "MUX", "", "O6"); + instPtr->setConfig(setting + "INIT", "", "INIT" + cell.second->params.at(ctx->id("DFF_INIT"))); } } - else if (cell.second->type == id_IOB) { + else if (cell.second->type == id_IOB33) { if (get_net_or_empty(cell.second.get(), id_I)) { instPtr->setConfig("IUSED", "", "0"); instPtr->setConfig("IBUF_LOW_PWR", "", "TRUE"); - instPtr->setConfig("ISTANDARD", "", "LVCMOS25"); + instPtr->setConfig("ISTANDARD", "", "LVCMOS33"); } else { - //instPtr->setConfig("OUSED", "", "0"); - instPtr->setConfig("OSTANDARD", "", "LVCMOS25"); + instPtr->setConfig("OUSED", "", "0"); + instPtr->setConfig("OSTANDARD", "", "LVCMOS33"); instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } } else if (cell.second->type == id_BUFGCTRL) { + static const char* params_whitelist[] = { "PRESELECT_I0", "PRESELECT_I1" }; + for (auto w : params_whitelist) { + auto it = cell.second->params.find(ctx->id(w)); + if (it != cell.second->params.end()) + instPtr->setConfig(it->first.c_str(ctx), "", it->second.c_str()); + } } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From 3a177c72c6f3b00c86861e896d4d90ac7cf8462e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Aug 2018 22:24:14 -0700 Subject: [PATCH 034/174] Preserve packed LUT name as LUT_NAME parameter --- xc7/cells.cc | 1 + xc7/xdl.cc | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index 34829f97..01109b96 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -274,6 +274,7 @@ void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) replace_port(lut, id_O, lc, id_O); lc->params[ctx->id("DFF_ENABLE")] = "0"; } + lc->params[ctx->id("LUT_NAME")] = lut->name.str(ctx); } void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_lut) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 04238747..7ed9fd5d 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -125,16 +125,21 @@ void write_xdl(const Context *ctx, std::ostream &out) } } - auto O = get_net_or_empty(cell.second.get(), id_O); - if (O) { - name = O->name.str(ctx); - instPtr->setConfig(lut + "USED", "", "0"); - } + auto it = cell.second->params.find(ctx->id("LUT_NAME")); + if (it != cell.second->params.end()) + name = it->second; else name = cell.second->name.str(ctx); boost::replace_all(name, ":", "\\:"); instPtr->setConfig(setting, name, value); + auto O = get_net_or_empty(cell.second.get(), id_O); + if (O) { + setting = lut; + setting += name; + instPtr->setConfig(setting, "", "0"); + } + auto OQ = get_net_or_empty(cell.second.get(), id_OQ); if (OQ) { setting = lut; From 82fbc551f8b3b09bb844b0eaf0a13c4c775a8777 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 21 Aug 2018 22:58:20 -0700 Subject: [PATCH 035/174] Fix DRC errors --- xc7/xdl.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 7ed9fd5d..5c77d323 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -136,7 +136,7 @@ void write_xdl(const Context *ctx, std::ostream &out) auto O = get_net_or_empty(cell.second.get(), id_O); if (O) { setting = lut; - setting += name; + setting += "USED"; instPtr->setConfig(setting, "", "0"); } @@ -149,6 +149,14 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig(setting, name, "#FF"); instPtr->setConfig(setting + "MUX", "", "O6"); instPtr->setConfig(setting + "INIT", "", "INIT" + cell.second->params.at(ctx->id("DFF_INIT"))); + assert(cell.second->params.at(ctx->id("SET_NORESET")) == "0"); // TODO + instPtr->setConfig(setting + "SR", "", "SRLOW"); + + NPNR_ASSERT(!cell.second->lcInfo.negClk); // TODO + instPtr->setConfig("CLKINV", "", "CLK"); + + instPtr->setConfig("SRUSEDMUX", "", "IN"); + instPtr->setConfig("CEUSEDMUX", "", "IN"); } } else if (cell.second->type == id_IOB33) { From df2f295545be313c3dddf0ac639bc86a812780f8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Sep 2018 13:09:28 -0700 Subject: [PATCH 036/174] Apparently netgen needs SYNC_ATTR to be set --- xc7/xdl.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 5c77d323..612c3e12 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -157,6 +157,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("SRUSEDMUX", "", "IN"); instPtr->setConfig("CEUSEDMUX", "", "IN"); + instPtr->setConfig("SYNC_ATTR", "", "ASYNC"); } } else if (cell.second->type == id_IOB33) { From ca7eef26acb6e0d9aec9107181e3503883359ede Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Sep 2018 16:57:11 -0700 Subject: [PATCH 037/174] Wires now encapsulate segments --- xc7/arch.cc | 42 +++++++++++++++++++++++++----- xc7/arch.h | 69 ++++++++++++++++++++++++++++++-------------------- xc7/archdefs.h | 6 ++--- 3 files changed, 80 insertions(+), 37 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 085e2212..ee772408 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles)), num_wires(wire_to_tilewire.size()) { } std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) @@ -102,6 +102,29 @@ std::vector TorcInfo::construct_bel_to_z(const Sites &sites, const int n } return bel_to_z; } +std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segments, const Tiles& tiles) +{ + std::vector wire_to_tilewire(segments.getCompactSegmentCount()); + + Tilewire currentTilewire; + for(TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { + // iterate over every wire in the tile + const auto& tileInfo = tiles.getTileInfo(tileIndex); + auto tileTypeIndex = tileInfo.getTypeIndex(); + auto wireCount = tiles.getWireCount(tileTypeIndex); + currentTilewire.setTileIndex(tileIndex); + for(WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { + currentTilewire.setWireIndex(wireIndex); + + const auto& currentSegment = segments.getTilewireSegment(currentTilewire); + if (currentSegment.getAnchorTileIndex() != tileIndex) continue; + + wire_to_tilewire[currentSegment.getCompactSegmentIndex()] = currentTilewire; + } + } + + return wire_to_tilewire; +} // ----------------------------------------------------------------------- @@ -134,7 +157,11 @@ Arch::Arch(ArchArgs args) : args(args) // if (package_info == nullptr) // log_error("Unsupported package '%s'.\n", args.package.c_str()); + //bel_carry.resize(chip_info->num_bels); bel_to_cell.resize(torc_info->num_bels); + wire_to_net.resize(torc_info->num_wires); + //pip_to_net.resize(chip_info->num_pips); + //switches_locked.resize(chip_info->num_switches); } // ----------------------------------------------------------------------- @@ -251,12 +278,13 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const } } auto site_index = torc_info->bel_to_site_index[bel.index]; - auto &site = torc_info->sites.getSite(site_index); - ret.index = site.getPinTilewire(pin_name); + const auto &site = torc_info->sites.getSite(site_index); + auto &tw = site.getPinTilewire(pin_name); - if (ret.index.isUndefined()) + if (tw.isUndefined()) log_error("no wire found for site '%s' pin '%s' \n", torc_info->bel_to_name(bel.index).c_str(), pin_name.c_str()); - + + ret.index = torc_info->tilewire_to_wire(tw); // NPNR_ASSERT(bel != BelId()); // @@ -592,8 +620,8 @@ DecalXY Arch::getWireDecal(WireId wire) const { DecalXY decalxy; decalxy.decal.type = DecalId::TYPE_WIRE; - //decalxy.decal.index = wire.index; - //decalxy.decal.active = wire_to_net.at(wire.index) != nullptr; + decalxy.decal.index = wire.index; + decalxy.decal.active = wire_to_net.at(wire.index) != nullptr; return decalxy; } diff --git a/xc7/arch.h b/xc7/arch.h index cb504016..47538501 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -239,6 +239,7 @@ struct TorcInfo { std::unique_ptr ddb; const Sites &sites; const Tiles &tiles; + const Segments &segments; const TileInfo& bel_to_tile_info(int32_t index) const { auto si = bel_to_site_index[index]; @@ -249,16 +250,32 @@ struct TorcInfo { auto si = bel_to_site_index[index]; return sites.getSite(si).getName(); } + std::string wire_to_name(int32_t index) const + { + const auto tw = wire_to_tilewire[index]; + ExtendedWireInfo ewi(*ddb, tw); + std::stringstream ss; + ss << ewi.mTileName << "/" << ewi.mWireName; + return ss.str(); + } + int32_t tilewire_to_wire(const Tilewire &tw) const + { + const auto& segment = segments.getTilewireSegment(tw); + return segment.getCompactSegmentIndex(); + } const std::vector bel_to_site_index; const int num_bels; const std::vector site_index_to_type; const std::vector bel_to_z; + const std::vector wire_to_tilewire; + const int num_wires; private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type); + static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles); }; extern std::unique_ptr torc_info; @@ -330,11 +347,10 @@ struct BelPinRange struct WireIterator { - Tilewire cursor; + int cursor = -1; - // TODO - void operator++() { /*cursor++;*/ } - bool operator!=(const WireIterator &other) const { return !(cursor == other.cursor); } + void operator++() { cursor++; } + bool operator!=(const WireIterator &other) const { return cursor != other.cursor; } WireId operator*() const { @@ -549,19 +565,18 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - //return id(chip_info->wire_data[wire.index].name.get()); - return IdString(); + return id(torc_info->wire_to_name(wire.index)); } IdString getWireType(WireId wire) const; - uint32_t getWireChecksum(WireId wire) const { return hash_value(wire.index); } + uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, NetInfo *net, PlaceStrength strength) { NPNR_ASSERT(wire != WireId()); - //NPNR_ASSERT(wire_to_net[wire.index] == nullptr); - //wire_to_net[wire.index] = net; + NPNR_ASSERT(wire_to_net[wire.index] == nullptr); + wire_to_net[wire.index] = net; net->wires[wire].pip = PipId(); net->wires[wire].strength = strength; refreshUiWire(wire); @@ -570,11 +585,11 @@ struct Arch : BaseCtx void unbindWire(WireId wire) { NPNR_ASSERT(wire != WireId()); - //NPNR_ASSERT(wire_to_net[wire.index] != nullptr); + NPNR_ASSERT(wire_to_net[wire.index] != nullptr); - //auto &net_wires = wire_to_net[wire.index]->wires; - //auto it = net_wires.find(wire); - //NPNR_ASSERT(it != net_wires.end()); + auto &net_wires = wire_to_net[wire.index]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); //auto pip = it->second.pip; //if (pip != PipId()) { @@ -582,29 +597,29 @@ struct Arch : BaseCtx // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; //} - //net_wires.erase(it); - //wire_to_net[wire.index] = nullptr; + net_wires.erase(it); + wire_to_net[wire.index] = nullptr; refreshUiWire(wire); } bool checkWireAvail(WireId wire) const { - //NPNR_ASSERT(wire != WireId()); - //return wire_to_net[wire.index] == nullptr; + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == nullptr; return true; } NetInfo *getBoundWireNet(WireId wire) const { - //NPNR_ASSERT(wire != WireId()); - //return wire_to_net[wire.index]; + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; return nullptr; } NetInfo *getConflictingWireNet(WireId wire) const { - //NPNR_ASSERT(wire != WireId()); - //return wire_to_net[wire.index]; + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; return nullptr; } @@ -631,8 +646,8 @@ struct Arch : BaseCtx WireRange getWires() const { WireRange range; - //range.b.cursor = 0; - //range.e.cursor = chip_info->num_wires; + range.b.cursor = 0; + range.e.cursor = torc_info->num_wires; return range; } @@ -651,8 +666,8 @@ struct Arch : BaseCtx WireId dst; //dst.index = chip_info->pip_data[pip.index].dst; - //NPNR_ASSERT(wire_to_net[dst.index] == nullptr); - //wire_to_net[dst.index] = net; + NPNR_ASSERT(wire_to_net[dst.index] == nullptr); + wire_to_net[dst.index] = net; //net->wires[dst].pip = pip; //net->wires[dst].strength = strength; refreshUiPip(pip); @@ -667,8 +682,8 @@ struct Arch : BaseCtx WireId dst; //dst.index = chip_info->pip_data[pip.index].dst; - //NPNR_ASSERT(wire_to_net[dst.index] != nullptr); - //wire_to_net[dst.index] = nullptr; + NPNR_ASSERT(wire_to_net[dst.index] != nullptr); + wire_to_net[dst.index] = nullptr; pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index] = nullptr; diff --git a/xc7/archdefs.h b/xc7/archdefs.h index 9f0f8382..571d76d3 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -74,10 +74,10 @@ struct BelId struct WireId { - Tilewire index; + int32_t index = -1; bool operator==(const WireId &other) const { return index == other.index; } - bool operator!=(const WireId &other) const { return !(index == other.index); } + bool operator!=(const WireId &other) const { return index != other.index; } }; struct PipId @@ -164,7 +164,7 @@ template <> struct hash { std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept { - return hash_value(wire.index); + return hash()(wire.index); } }; From 7e693ff27d57a41d9a710349f5ec55002cd57469 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Sep 2018 19:06:20 -0700 Subject: [PATCH 038/174] Precompute pips too --- xc7/arch.cc | 53 +++++++++++++++++++++- xc7/arch.h | 126 ++++++++++++++++++++++++++++++++-------------------- 2 files changed, 128 insertions(+), 51 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ee772408..eddcae87 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles)), num_wires(wire_to_tilewire.size()) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { } std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) @@ -125,6 +125,55 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme return wire_to_tilewire; } +std::vector TorcInfo::construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill) +{ + std::vector pip_to_arc; + wire_to_pips_downhill.resize(wire_to_tilewire.size()); + + auto arc_hash = [](const Arc& arc) { + size_t seed = 0; + boost::hash_combine(seed, hash_value(arc.getSourceTilewire())); + boost::hash_combine(seed, hash_value(arc.getSinkTilewire())); + return seed; + }; + std::unordered_map arc_to_pip(0, arc_hash); + + ArcVector arcs; + for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { + const auto &tw = wire_to_tilewire[i]; + if (tw.isUndefined()) continue; + arcs.clear(); + const_cast(ddb).expandSegmentSinks(tw, arcs); + + auto index = pip_to_arc.size(); + pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); + + auto &pips = wire_to_pips_downhill[i]; + pips.reserve(arcs.size()); + for (const auto& a : arcs) { + pips.push_back(index); + arc_to_pip.emplace(a, index); + ++index; + } + } + + pip_to_arc.shrink_to_fit(); + + wire_to_pips_uphill.resize(wire_to_tilewire.size()); + for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { + const auto &tw = wire_to_tilewire[i]; + if (tw.isUndefined()) continue; + arcs.clear(); + const_cast(ddb).expandSegmentSinks(tw, arcs); + + auto &pips = wire_to_pips_uphill[i]; + pips.reserve(arcs.size()); + for (const auto& a : arcs) + pips.push_back(arc_to_pip.at(a)); + } + + return pip_to_arc; +} // ----------------------------------------------------------------------- @@ -160,7 +209,7 @@ Arch::Arch(ArchArgs args) : args(args) //bel_carry.resize(chip_info->num_bels); bel_to_cell.resize(torc_info->num_bels); wire_to_net.resize(torc_info->num_wires); - //pip_to_net.resize(chip_info->num_pips); + pip_to_net.resize(torc_info->num_pips); //switches_locked.resize(chip_info->num_switches); } diff --git a/xc7/arch.h b/xc7/arch.h index 47538501..7df241ed 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -252,7 +252,7 @@ struct TorcInfo { } std::string wire_to_name(int32_t index) const { - const auto tw = wire_to_tilewire[index]; + const auto &tw = wire_to_tilewire[index]; ExtendedWireInfo ewi(*ddb, tw); std::stringstream ss; ss << ewi.mTileName << "/" << ewi.mWireName; @@ -260,9 +260,16 @@ struct TorcInfo { } int32_t tilewire_to_wire(const Tilewire &tw) const { - const auto& segment = segments.getTilewireSegment(tw); + const auto &segment = segments.getTilewireSegment(tw); return segment.getCompactSegmentIndex(); } + int32_t pip_to_wire(int32_t index) const + { + const auto &arc = pip_to_arc[index]; + const auto &segment = segments.getTilewireSegment(arc.getSourceTilewire()); + return segment.getCompactSegmentIndex(); + + } const std::vector bel_to_site_index; const int num_bels; @@ -270,12 +277,18 @@ struct TorcInfo { const std::vector bel_to_z; const std::vector wire_to_tilewire; const int num_wires; + std::vector> wire_to_pips_uphill; + std::vector> wire_to_pips_downhill; + const std::vector pip_to_arc; + const int num_pips; + private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type); static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles); + static std::vector construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); }; extern std::unique_ptr torc_info; @@ -435,11 +448,11 @@ struct Arch : BaseCtx mutable std::unordered_map pip_by_name; mutable std::unordered_map bel_by_loc; - std::vector bel_carry; + //std::vector bel_carry; std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; - std::vector switches_locked; + //std::vector switches_locked; ArchArgs args; Arch(ArchArgs args); @@ -533,7 +546,7 @@ struct Arch : BaseCtx Loc getBelLocation(BelId bel) const { - auto &tile_info = torc_info->bel_to_tile_info(bel.index); + const auto &tile_info = torc_info->bel_to_tile_info(bel.index); Loc loc; loc.x = tile_info.getCol(); @@ -591,11 +604,11 @@ struct Arch : BaseCtx auto it = net_wires.find(wire); NPNR_ASSERT(it != net_wires.end()); - //auto pip = it->second.pip; - //if (pip != PipId()) { - // pip_to_net[pip.index] = nullptr; - // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; - //} + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = nullptr; + //switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + } net_wires.erase(it); wire_to_net[wire.index] = nullptr; @@ -640,6 +653,7 @@ struct Arch : BaseCtx //NPNR_ASSERT(wire != WireId()); //range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); //range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; + throw; return range; } @@ -659,17 +673,16 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == nullptr); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); + //NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); pip_to_net[pip.index] = net; - switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + //switches_locked[chip_info->pip_data[pip.index].switch_index] = net; - WireId dst; - //dst.index = chip_info->pip_data[pip.index].dst; + WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] == nullptr); wire_to_net[dst.index] = net; - //net->wires[dst].pip = pip; - //net->wires[dst].strength = strength; + net->wires[dst].pip = pip; + net->wires[dst].strength = strength; refreshUiPip(pip); refreshUiWire(dst); } @@ -678,16 +691,15 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != nullptr); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); + //NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); - WireId dst; - //dst.index = chip_info->pip_data[pip.index].dst; + WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] != nullptr); wire_to_net[dst.index] = nullptr; pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index] = nullptr; - switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + //switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; refreshUiPip(pip); refreshUiWire(dst); } @@ -695,25 +707,26 @@ struct Arch : BaseCtx bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - auto &pi = chip_info->pip_data[pip.index]; - auto &si = chip_info->bits_info->switches[pi.switch_index]; + //auto &pi = chip_info->pip_data[pip.index]; + //auto &si = chip_info->bits_info->switches[pi.switch_index]; - if (switches_locked[pi.switch_index] != nullptr) - return false; + //if (switches_locked[pi.switch_index] != nullptr) + // return false; - if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { - NPNR_ASSERT(si.bel >= 0); - if (bel_to_cell[si.bel] != nullptr) - return false; - } + //if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { + // NPNR_ASSERT(si.bel >= 0); + // if (bel_to_cell[si.bel] != nullptr) + // return false; + //} - if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { - NPNR_ASSERT(si.bel >= 0); - if (bel_carry[si.bel]) - return false; - } + //if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { + // NPNR_ASSERT(si.bel >= 0); + // if (bel_carry[si.bel]) + // return false; + //} - return true; + //return true; + return getConflictingPipNet(pip); } NetInfo *getBoundPipNet(PipId pip) const @@ -725,22 +738,27 @@ struct Arch : BaseCtx NetInfo *getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; + //return switches_locked[chip_info->pip_data[pip.index].switch_index]; + return pip_to_net[pip.index]; } AllPipRange getPips() const { AllPipRange range; range.b.cursor = 0; - range.e.cursor = chip_info->num_pips; + range.e.cursor = torc_info->num_pips; return range; } Loc getPipLocation(PipId pip) const { + const auto &arc = torc_info->pip_to_arc[pip.index]; + const auto &tw = arc.getSourceTilewire(); + const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex()); + Loc loc; - loc.x = chip_info->pip_data[pip.index].x; - loc.y = chip_info->pip_data[pip.index].y; + loc.x = tile_info.getCol(); + loc.y = tile_info.getRow(); loc.z = 0; return loc; } @@ -755,7 +773,11 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - //wire.index = chip_info->pip_data[pip.index].src; + + const auto &arc = torc_info->pip_to_arc[pip.index]; + const auto &tw = arc.getSourceTilewire(); + wire.index = torc_info->tilewire_to_wire(tw); + return wire; } @@ -763,7 +785,11 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - //wire.index = chip_info->pip_data[pip.index].dst; + + const auto &arc = torc_info->pip_to_arc[pip.index]; + const auto &tw = arc.getSinkTilewire(); + wire.index = torc_info->tilewire_to_wire(tw); + return wire; } @@ -771,10 +797,10 @@ struct Arch : BaseCtx { DelayInfo delay; NPNR_ASSERT(pip != PipId()); - if (fast_part) - delay.delay = chip_info->pip_data[pip.index].fast_delay; - else - delay.delay = chip_info->pip_data[pip.index].slow_delay; + //if (fast_part) + // delay.delay = chip_info->pip_data[pip.index].fast_delay; + //else + // delay.delay = chip_info->pip_data[pip.index].slow_delay; return delay; } @@ -782,8 +808,9 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - //range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get(); - //range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill; + const auto &pips = torc_info->wire_to_pips_downhill[wire.index]; + range.b.cursor = pips.data(); + range.e.cursor = range.b.cursor + pips.size(); return range; } @@ -791,8 +818,9 @@ struct Arch : BaseCtx { PipRange range; NPNR_ASSERT(wire != WireId()); - //range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get(); - //range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill; + const auto &pips = torc_info->wire_to_pips_uphill[wire.index]; + range.b.cursor = pips.data(); + range.e.cursor = range.b.cursor + pips.size(); return range; } From 3f865f90492f99362c639c62d5b76e874d0c2e8b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Sep 2018 23:38:53 -0700 Subject: [PATCH 039/174] Fix Arch::estimateDelay() --- xc7/delay.cc | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index c85ec359..f6b74058 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -100,8 +100,12 @@ void ice40DelayFuzzerMain(Context *ctx) delay_t Arch::estimateDelay(WireId src, WireId dst) const { - //return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); - return 0; + const auto &src_tw = torc_info->wire_to_tilewire[src.index]; + const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); + const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; + const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); + + return 200 * (abs(src_info.getCol() - dst_info.getCol()) + abs(src_info.getRow() - dst_info.getRow())); } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const From d2597bcd8dc09386d1016f77c9a48a5ba19b5128 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 00:10:16 -0700 Subject: [PATCH 040/174] Fix segments --- xc7/arch.cc | 29 +++++++++++++------------ xc7/arch.h | 61 +++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 62 insertions(+), 28 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index eddcae87..0f5da9b4 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { } std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) @@ -102,9 +102,9 @@ std::vector TorcInfo::construct_bel_to_z(const Sites &sites, const int n } return bel_to_z; } -std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segments, const Tiles& tiles) +std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segments, const Tiles& tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire) { - std::vector wire_to_tilewire(segments.getCompactSegmentCount()); + std::vector wire_to_tilewire; Tilewire currentTilewire; for(TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { @@ -117,12 +117,19 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme currentTilewire.setWireIndex(wireIndex); const auto& currentSegment = segments.getTilewireSegment(currentTilewire); - if (currentSegment.getAnchorTileIndex() != tileIndex) continue; - wire_to_tilewire[currentSegment.getCompactSegmentIndex()] = currentTilewire; + if (!currentSegment.isTrivial()) { + if (currentSegment.getAnchorTileIndex() != tileIndex) continue; + segment_to_wire.emplace(currentSegment, wire_to_tilewire.size()); + } + else + trivial_to_wire.emplace(currentTilewire, wire_to_tilewire.size()); + + wire_to_tilewire.push_back(currentTilewire); } } + wire_to_tilewire.shrink_to_fit(); return wire_to_tilewire; } std::vector TorcInfo::construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill) @@ -130,20 +137,14 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir std::vector pip_to_arc; wire_to_pips_downhill.resize(wire_to_tilewire.size()); - auto arc_hash = [](const Arc& arc) { - size_t seed = 0; - boost::hash_combine(seed, hash_value(arc.getSourceTilewire())); - boost::hash_combine(seed, hash_value(arc.getSinkTilewire())); - return seed; - }; - std::unordered_map arc_to_pip(0, arc_hash); + std::unordered_map arc_to_pip; ArcVector arcs; for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { const auto &tw = wire_to_tilewire[i]; if (tw.isUndefined()) continue; arcs.clear(); - const_cast(ddb).expandSegmentSinks(tw, arcs); + const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); auto index = pip_to_arc.size(); pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); @@ -164,7 +165,7 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir const auto &tw = wire_to_tilewire[i]; if (tw.isUndefined()) continue; arcs.clear(); - const_cast(ddb).expandSegmentSinks(tw, arcs); + //const_cast(ddb).expandSegmentSources(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); auto &pips = wire_to_pips_uphill[i]; pips.reserve(arcs.size()); diff --git a/xc7/arch.h b/xc7/arch.h index 7df241ed..b74e4fdf 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -26,6 +26,44 @@ using namespace torc::architecture; using namespace torc::architecture::xilinx; +namespace std { + template <> struct hash + { + size_t operator()(const Segments::SegmentReference &s) const + { + size_t seed = 0; + boost::hash_combine(seed, hash()(s.getCompactSegmentIndex())); + boost::hash_combine(seed, hash()(s.getAnchorTileIndex())); + return seed; + } + }; + template <> struct equal_to + { + bool operator()(const Segments::SegmentReference &lhs, const Segments::SegmentReference &rhs) const + { + return lhs.getAnchorTileIndex() == rhs.getAnchorTileIndex() && lhs.getCompactSegmentIndex() == rhs.getCompactSegmentIndex(); + } + }; + template <> struct hash + { + size_t operator()(const Tilewire& t) const + { + return hash_value(t); + } + }; + + template <> struct hash + { + size_t operator()(const Arc &a) const + { + size_t seed = 0; + boost::hash_combine(seed, hash_value(a.getSourceTilewire())); + boost::hash_combine(seed, hash_value(a.getSinkTilewire())); + return seed; + } + }; +} + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -256,25 +294,23 @@ struct TorcInfo { ExtendedWireInfo ewi(*ddb, tw); std::stringstream ss; ss << ewi.mTileName << "/" << ewi.mWireName; + ss << "(" << tw.getWireIndex() << "@" << tw.getTileIndex() << ")"; return ss.str(); } int32_t tilewire_to_wire(const Tilewire &tw) const { const auto &segment = segments.getTilewireSegment(tw); - return segment.getCompactSegmentIndex(); - } - int32_t pip_to_wire(int32_t index) const - { - const auto &arc = pip_to_arc[index]; - const auto &segment = segments.getTilewireSegment(arc.getSourceTilewire()); - return segment.getCompactSegmentIndex(); - + if (!segment.isTrivial()) + return segment_to_wire.at(segment); + return trivial_to_wire.at(tw); } const std::vector bel_to_site_index; const int num_bels; const std::vector site_index_to_type; const std::vector bel_to_z; + std::unordered_map segment_to_wire; + std::unordered_map trivial_to_wire; const std::vector wire_to_tilewire; const int num_wires; std::vector> wire_to_pips_uphill; @@ -282,12 +318,11 @@ struct TorcInfo { const std::vector pip_to_arc; const int num_pips; - private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type); - static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles); + static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire); static std::vector construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); }; extern std::unique_ptr torc_info; @@ -619,21 +654,18 @@ struct Arch : BaseCtx { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index] == nullptr; - return true; } NetInfo *getBoundWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; - return nullptr; } NetInfo *getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); return wire_to_net[wire.index]; - return nullptr; } DelayInfo getWireDelay(WireId wire) const @@ -726,7 +758,7 @@ struct Arch : BaseCtx //} //return true; - return getConflictingPipNet(pip); + return pip_to_net[pip.index] == nullptr; } NetInfo *getBoundPipNet(PipId pip) const @@ -811,6 +843,7 @@ struct Arch : BaseCtx const auto &pips = torc_info->wire_to_pips_downhill[wire.index]; range.b.cursor = pips.data(); range.e.cursor = range.b.cursor + pips.size(); + return range; } From c128df127bea52d0fde7ef9de00b7d117580c8d1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 13:17:16 -0700 Subject: [PATCH 041/174] Do not consider route-through for CLB tiles --- xc7/arch.cc | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 0f5da9b4..1d0ead8c 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -115,7 +115,6 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme currentTilewire.setTileIndex(tileIndex); for(WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { currentTilewire.setWireIndex(wireIndex); - const auto& currentSegment = segments.getTilewireSegment(currentTilewire); if (!currentSegment.isTrivial()) { @@ -134,6 +133,8 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme } std::vector TorcInfo::construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill) { + const auto &tiles = ddb.getTiles(); + std::vector pip_to_arc; wire_to_pips_downhill.resize(wire_to_tilewire.size()); @@ -144,7 +145,12 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir const auto &tw = wire_to_tilewire[i]; if (tw.isUndefined()) continue; arcs.clear(); - const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); + + const auto& tileInfo = tiles.getTileInfo(tw.getTileIndex()); + const auto tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); + bool clb = boost::starts_with(tileTypeName, "CLB"); + + const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, !clb /* inUseRoutethrough */); auto index = pip_to_arc.size(); pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); From 6d17810ddeb42a871fce077d7feba5cbc94405f3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 13:20:19 -0700 Subject: [PATCH 042/174] Merge fixes --- xc7/arch.cc | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 1d0ead8c..d17bde6d 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -648,18 +648,9 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay // ----------------------------------------------------------------------- -bool Arch::place() -{ - Placer1Cfg cfg; - cfg.constraintWeight = placer_constraintWeight; - return placer1(getCtx(), cfg); -} +bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() -{ - Router1Cfg cfg; - return router1(getCtx(), cfg); -} +bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } // ----------------------------------------------------------------------- From bf5a4717f54780a7d4e36547d2cabb5c649746df Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 13:40:52 -0700 Subject: [PATCH 043/174] Add pips to XDL output --- xc7/xdl.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 612c3e12..c4435e4b 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -217,6 +217,15 @@ void write_xdl(const Context *ctx, std::ostream &out) auto b = designPtr->addNet(netPtr); assert(b); + + for (const auto& i : net.second->wires) { + const auto& pip_map = i.second; + if (pip_map.pip == PipId()) continue; + ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSourceTilewire()); + ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSinkTilewire()); + auto p = Factory::newPip(ewi_src.mTileName, ewi_src.mWireName, ewi_dst.mWireName, ePipUnidirectionalBuffered); + netPtr->addPip(p); + } } exporter(designPtr); From 7f1c1ecaf073d6b40c69c94ea0321fa7f890f09c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 19:22:39 -0700 Subject: [PATCH 044/174] blinky.v to instantiate BUFGCTRL correctly --- xc7/blinky.v | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/xc7/blinky.v b/xc7/blinky.v index 547209e8..dba94598 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -7,8 +7,10 @@ module blinky ( output led5 ); - BUFGCTRL #(.PRESELECT_I0("TRUE")) clk_gb ( + BUFGCTRL clk_gb ( .I0(clki), + .CE0(1'b1), + .S0(1'b1), .O(clk) ); From 86fa032b63aaf22c2f623ebdb3480ea9702bfc8b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 19:23:00 -0700 Subject: [PATCH 045/174] picorv32_top to instantiate BUFGCTRL, and picorv32.sh to use picorv32.ys script --- xc7/picorv32.sh | 7 ++++--- xc7/picorv32_top.v | 11 ++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/xc7/picorv32.sh b/xc7/picorv32.sh index d06786c5..0ccb217e 100755 --- a/xc7/picorv32.sh +++ b/xc7/picorv32.sh @@ -2,6 +2,7 @@ set -ex rm -f picorv32.v wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v -yosys -p 'synth_ice40 -json picorv32.json -top top' picorv32.v picorv32_top.v -../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -icetime -d hx8k -t picorv32.asc +yosys picorv32.ys +../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl +#../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json +#icetime -d hx8k -t picorv32.asc diff --git a/xc7/picorv32_top.v b/xc7/picorv32_top.v index 27f0ef0c..7e2bf488 100644 --- a/xc7/picorv32_top.v +++ b/xc7/picorv32_top.v @@ -11,13 +11,22 @@ module top ( output [ 3:0] mem_wstrb, input [31:0] mem_rdata ); + + wire gclk; + BUFGCTRL clk_gb ( + .I0(clk), + .CE0(1'b1), + .S0(1'b1), + .O(gclk) + ); + picorv32 #( .ENABLE_COUNTERS(0), .TWO_STAGE_SHIFT(0), .CATCH_MISALIGN(0), .CATCH_ILLINSN(0) ) cpu ( - .clk (clk ), + .clk (gclk ), .resetn (resetn ), .trap (trap ), .mem_valid(mem_valid), From 4f61d2dae7ff2598720489c3db5bf82384644aac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 19:23:36 -0700 Subject: [PATCH 046/174] Add yosys script --- xc7/picorv32.ys | 54 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 xc7/picorv32.ys diff --git a/xc7/picorv32.ys b/xc7/picorv32.ys new file mode 100644 index 00000000..61916173 --- /dev/null +++ b/xc7/picorv32.ys @@ -0,0 +1,54 @@ +read_verilog picorv32.v +read_verilog picorv32_top.v + +#synth_xilinx -top picorv32 + +#begin: + read_verilog -lib +/xilinx/cells_sim.v + read_verilog -lib +/xilinx/cells_xtra.v +# read_verilog -lib +/xilinx/brams_bb.v +# read_verilog -lib +/xilinx/drams_bb.v + hierarchy -check -top top + +#flatten: (only if -flatten) + proc + flatten + +#coarse: + synth -run coarse + +#bram: +# memory_bram -rules +/xilinx/brams.txt +# techmap -map +/xilinx/brams_map.v +# +#dram: +# memory_bram -rules +/xilinx/drams.txt +# techmap -map +/xilinx/drams_map.v + +fine: + opt -fast -full + memory_map + dffsr2dff +# dff2dffe + opt -full + techmap -map +/techmap.v #-map +/xilinx/arith_map.v + opt -fast + +map_luts: + abc -luts 2:2,3,6:5 #,10,20 [-dff] + clean + +map_cells: + techmap -map +/xilinx/cells_map.v + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT + clean + +check: + hierarchy -check + stat + check -noinit + +#edif: (only if -edif) +# write_edif + +write_json picorv32.json From 3a5665c1cb975094726cafa3f856866cd7b81ca4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 21:00:11 -0700 Subject: [PATCH 047/174] Speedup placement slightly using bel_to_loc --- xc7/arch.cc | 42 +++++++++++++++++++++++------------------- xc7/arch.h | 16 +++++----------- xc7/xdl.cc | 2 +- 3 files changed, 29 insertions(+), 31 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index d17bde6d..055f91c8 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_z(construct_bel_to_z(sites, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { } std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) @@ -74,33 +74,37 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si } return site_index_to_type; } -std::vector TorcInfo::construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type) +std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type) { - std::vector bel_to_z; - bel_to_z.resize(num_bels); + std::vector bel_to_loc; + bel_to_loc.resize(num_bels); int32_t bel_index = 0; for (SiteIndex i(0); i < site_index_to_type.size(); ++i) { + const auto &site = sites.getSite(i); + const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); + const auto x = tile_info.getCol(); + const auto y = tile_info.getRow(); + if (site_index_to_type[i] == id_SLICE_LUT6) { - auto site = sites.getSite(i); - auto site_name = site.getName(); - auto site_name_back = site_name.back(); + const auto site_name = site.getName(); + const auto site_name_back = site_name.back(); if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || site_name_back == '8') { - bel_to_z[bel_index++] = 0; - bel_to_z[bel_index++] = 1; - bel_to_z[bel_index++] = 2; - bel_to_z[bel_index++] = 3; + bel_to_loc[bel_index++] = Loc(x, y, 0); + bel_to_loc[bel_index++] = Loc(x, y, 1); + bel_to_loc[bel_index++] = Loc(x, y, 2); + bel_to_loc[bel_index++] = Loc(x, y, 3); } else { - bel_to_z[bel_index++] = 4; - bel_to_z[bel_index++] = 5; - bel_to_z[bel_index++] = 6; - bel_to_z[bel_index++] = 7; + bel_to_loc[bel_index++] = Loc(x, y, 4); + bel_to_loc[bel_index++] = Loc(x, y, 5); + bel_to_loc[bel_index++] = Loc(x, y, 6); + bel_to_loc[bel_index++] = Loc(x, y, 7); } } else - ++bel_index; + bel_to_loc[bel_index++] = Loc(x, y, 0); } - return bel_to_z; + return bel_to_loc; } std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segments, const Tiles& tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire) { @@ -324,7 +328,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const if (getBelType(bel) == id_SLICE_LUT6) { // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { - switch (torc_info->bel_to_z[bel.index]) { + switch (torc_info->bel_to_loc[bel.index].z) { case 0: case 4: pin_name[0] = 'A'; break; case 1: case 5: pin_name[0] = 'B'; break; case 2: case 6: pin_name[0] = 'C'; break; @@ -650,7 +654,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } +bool Arch::route() { return /*router1(getCtx(), Router1Cfg(getCtx()))*/ true; } // ----------------------------------------------------------------------- diff --git a/xc7/arch.h b/xc7/arch.h index b74e4fdf..bd91b79c 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -281,7 +281,7 @@ struct TorcInfo { const TileInfo& bel_to_tile_info(int32_t index) const { auto si = bel_to_site_index[index]; - auto &site = sites.getSite(si); + const auto &site = sites.getSite(si); return tiles.getTileInfo(site.getTileIndex()); } const std::string& bel_to_name(int32_t index) const { @@ -308,7 +308,7 @@ struct TorcInfo { const std::vector bel_to_site_index; const int num_bels; const std::vector site_index_to_type; - const std::vector bel_to_z; + const std::vector bel_to_loc; std::unordered_map segment_to_wire; std::unordered_map trivial_to_wire; const std::vector wire_to_tilewire; @@ -321,7 +321,7 @@ struct TorcInfo { private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); - static std::vector construct_bel_to_z(const Sites &sites, const int num_bels, const std::vector &site_index_to_type); + static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type); static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire); static std::vector construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); }; @@ -517,7 +517,7 @@ struct Arch : BaseCtx // Append LUT name to name name.reserve(name.size() + 2); name += "_"; - switch (torc_info->bel_to_z[bel.index]) { + switch (torc_info->bel_to_loc[bel.index].z) { case 0: case 4: name += 'A'; break; case 1: case 5: name += 'B'; break; case 2: case 6: name += 'C'; break; @@ -581,13 +581,7 @@ struct Arch : BaseCtx Loc getBelLocation(BelId bel) const { - const auto &tile_info = torc_info->bel_to_tile_info(bel.index); - - Loc loc; - loc.x = tile_info.getCol(); - loc.y = tile_info.getRow(); - loc.z = torc_info->bel_to_z[bel.index]; - return loc; + return torc_info->bel_to_loc[bel.index]; } BelId getBelByLocation(Loc loc) const; diff --git a/xc7/xdl.cc b/xc7/xdl.cc index c4435e4b..30a8921a 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -42,7 +42,7 @@ void write_xdl(const Context *ctx, std::ostream &out) lut_inputs.reserve(6); auto bel_to_lut = [](const BelId bel) { - switch (torc_info->bel_to_z[bel.index]) { + switch (torc_info->bel_to_loc[bel.index].z) { case 0: case 4: return "A"; break; case 1: case 5: return "B"; break; case 2: case 6: return "C"; break; From 2eeb59d9f13353fadbeb866b11938f04440b043f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 22:24:59 -0700 Subject: [PATCH 048/174] Re-enable routing --- xc7/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 055f91c8..1c4bc99e 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -654,7 +654,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() { return /*router1(getCtx(), Router1Cfg(getCtx()))*/ true; } +bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } // ----------------------------------------------------------------------- From 30fe1f229abdb407069e357bbe4d7c5063adf5c1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 22:25:05 -0700 Subject: [PATCH 049/174] Set CE0INV and S0INV for BUFGCTRL; PRESELECT_I0 to be TRUE if not set --- xc7/xdl.cc | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 30a8921a..a82d568d 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -174,12 +174,11 @@ void write_xdl(const Context *ctx, std::ostream &out) } } else if (cell.second->type == id_BUFGCTRL) { - static const char* params_whitelist[] = { "PRESELECT_I0", "PRESELECT_I1" }; - for (auto w : params_whitelist) { - auto it = cell.second->params.find(ctx->id(w)); - if (it != cell.second->params.end()) - instPtr->setConfig(it->first.c_str(ctx), "", it->second.c_str()); - } + auto it = cell.second->params.find(ctx->id("PRESELECT_I0")); + instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "TRUE"); + + instPtr->setConfig("CE0INV", "", "CE0_B"); + instPtr->setConfig("S0INV", "", "S0_B"); } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From d78f5a1d5b3e1dcc87767519ed9661fafce34885 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 3 Sep 2018 22:59:34 -0700 Subject: [PATCH 050/174] Build a pip_to_dst_wire lookup to speedup routing --- xc7/arch.cc | 13 +++++++++++++ xc7/arch.h | 7 ++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 1c4bc99e..7d9a4e78 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -37,6 +37,12 @@ std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { + pip_to_dst_wire.reserve(num_pips); + + for (const auto& arc : pip_to_arc) { + const auto &tw = arc.getSinkTilewire(); + pip_to_dst_wire.push_back(tilewire_to_wire(tw)); + } } std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) { @@ -186,6 +192,13 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir return pip_to_arc; } +std::vector +construct_pip_to_dst_wire(const std::vector& pip_to_arc) +{ + std::vector pip_to_wire; + return pip_to_wire; +} + // ----------------------------------------------------------------------- diff --git a/xc7/arch.h b/xc7/arch.h index bd91b79c..37523bb8 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -317,6 +317,7 @@ struct TorcInfo { std::vector> wire_to_pips_downhill; const std::vector pip_to_arc; const int num_pips; + std::vector pip_to_dst_wire; private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); @@ -811,11 +812,7 @@ struct Arch : BaseCtx { WireId wire; NPNR_ASSERT(pip != PipId()); - - const auto &arc = torc_info->pip_to_arc[pip.index]; - const auto &tw = arc.getSinkTilewire(); - wire.index = torc_info->tilewire_to_wire(tw); - + wire.index = torc_info->pip_to_dst_wire[pip.index]; return wire; } From 24d702d0beb87d4fb7ff0ac19f9e06f1cdaa3203 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 4 Sep 2018 09:05:53 -0700 Subject: [PATCH 051/174] Save a lookup for router1 --- common/router1.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 5cd4414c..7f852dca 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -197,8 +197,9 @@ struct Router NPNR_ASSERT(next_delay >= 0); - if (visited.count(next_wire)) { - if (visited.at(next_wire).delay <= next_delay + ctx->getDelayEpsilon()) + auto it = visited.find(next_wire); + if (it != visited.end()) { + if (it->second.delay <= next_delay + ctx->getDelayEpsilon()) continue; #if 0 // FIXME if (ctx->debug) From 7da5e2b525e967b4d4cfeecfbc598b059258a5fc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 4 Sep 2018 10:10:27 -0700 Subject: [PATCH 052/174] Reduce predictDelay/estimateDelay to 100ps per tile --- xc7/delay.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index f6b74058..0c420694 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -105,7 +105,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - return 200 * (abs(src_info.getCol() - dst_info.getCol()) + abs(src_info.getRow() - dst_info.getRow())); + return 100 * (abs(src_info.getCol() - dst_info.getCol()) + abs(src_info.getRow() - dst_info.getRow())); } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const @@ -114,7 +114,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto driver_loc = getBelLocation(driver.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel); - return 200 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); + return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); } NEXTPNR_NAMESPACE_END From db6e81d6c3bf63e235a9beab18311808bcbed1dc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 4 Sep 2018 10:11:10 -0700 Subject: [PATCH 053/174] Populate Arch::getWireDelay() --- xc7/arch.cc | 39 +++++++++++++++++++++++++++++++++++++-- xc7/arch.h | 10 +++------- 2 files changed, 40 insertions(+), 9 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 7d9a4e78..868b9ee1 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { pip_to_dst_wire.reserve(num_pips); @@ -141,6 +141,41 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme wire_to_tilewire.shrink_to_fit(); return wire_to_tilewire; } +std::vector TorcInfo::construct_wire_to_delay(const std::vector& wire_to_tilewire, const DDB &ddb) +{ + std::vector wire_to_delay; + wire_to_delay.reserve(wire_to_tilewire.size()); + + const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)BEG(_[NS])?\\d"); + const boost::regex re_L = boost::regex("L(H|V|VB)(_L)?\\d+"); + boost::cmatch what; + DelayInfo d; + ExtendedWireInfo ewi(ddb); + for (const auto &tw : wire_to_tilewire) + { + ewi.set(tw); + if (boost::regex_match(ewi.mWireName, what, re_124)) { + std::string l(what[1]); + switch (l[0]) { + case '1': d.delay = 150; break; + case '2': d.delay = 170; break; + case '4': d.delay = 210; break; + case '6': d.delay = 210; break; + default: throw; + } + } + else if (boost::regex_match(ewi.mWireName, what, re_L)) { + std::string l(what[1]); + if (l == "H") d.delay = 360; + else if (l == "VB") d.delay = 300; + else if (l == "V") d.delay = 350; + else throw; + } + wire_to_delay.emplace_back(d); + } + + return wire_to_delay; +} std::vector TorcInfo::construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill) { const auto &tiles = ddb.getTiles(); @@ -667,7 +702,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } +bool Arch::route() { getCtx()->debug = true; return router1(getCtx(), Router1Cfg(getCtx())); } // ----------------------------------------------------------------------- diff --git a/xc7/arch.h b/xc7/arch.h index 37523bb8..a179139e 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -313,6 +313,7 @@ struct TorcInfo { std::unordered_map trivial_to_wire; const std::vector wire_to_tilewire; const int num_wires; + const std::vector wire_to_delay; std::vector> wire_to_pips_uphill; std::vector> wire_to_pips_downhill; const std::vector pip_to_arc; @@ -324,6 +325,7 @@ private: static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type); static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire); + static std::vector construct_wire_to_delay(const std::vector& wire_to_tilewire, const DDB &ddb); static std::vector construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); }; extern std::unique_ptr torc_info; @@ -665,13 +667,7 @@ struct Arch : BaseCtx DelayInfo getWireDelay(WireId wire) const { - DelayInfo delay; - //NPNR_ASSERT(wire != WireId()); - //if (fast_part) - // delay.delay = chip_info->wire_data[wire.index].fast_delay; - //else - // delay.delay = chip_info->wire_data[wire.index].slow_delay; - return delay; + return torc_info->wire_to_delay[wire.index]; } BelPinRange getWireBelPins(WireId wire) const From c7f0bdfc1bd7443ada1bebce873fdc7a87c63610 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 4 Sep 2018 10:35:12 -0700 Subject: [PATCH 054/174] Move DelayInfo into loop --- xc7/arch.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 868b9ee1..8be5d7a4 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -149,11 +149,11 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector TorcInfo::construct_wire_to_delay(const std::vector Date: Tue, 4 Sep 2018 10:35:30 -0700 Subject: [PATCH 055/174] Convert path delay to NS --- common/router1.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/router1.cc b/common/router1.cc index 7f852dca..fb618297 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -367,7 +367,7 @@ struct Router if (ctx->debug) { log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); - log(" Path delay estimate: %.2f\n", float(ctx->estimateDelay(src_wire, dst_wire))); + log(" Path delay estimate: %.2f\n", ctx->getDelayNS(ctx->estimateDelay(src_wire, dst_wire))); } route(src_wires, dst_wire); From d0916943c570292c84d04644f28f2e5b812a57b3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 4 Sep 2018 10:41:32 -0700 Subject: [PATCH 056/174] Extend delays to cover BYP and FAN --- xc7/arch.cc | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 8be5d7a4..3e5b7c06 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -146,8 +146,13 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector wire_to_delay; wire_to_delay.reserve(wire_to_tilewire.size()); - const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)BEG(_[NS])?\\d"); - const boost::regex re_L = boost::regex("L(H|V|VB)(_L)?\\d+"); + const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)BEG(_[NS])?\\d"); + const boost::regex re_L = boost::regex("L(H|V|VB)(_L)?\\d+"); + const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); + const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); + const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d"); + const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d"); + boost::cmatch what; ExtendedWireInfo ewi(ddb); for (const auto &tw : wire_to_tilewire) @@ -171,6 +176,14 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector Date: Tue, 4 Sep 2018 11:05:03 -0700 Subject: [PATCH 057/174] Segment anchors may not be beginning of wires --- xc7/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 3e5b7c06..e1af6434 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -146,7 +146,7 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector wire_to_delay; wire_to_delay.reserve(wire_to_tilewire.size()); - const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)BEG(_[NS])?\\d"); + const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)((BEG(_[NS])?)|END|[A-E])?\\d"); const boost::regex re_L = boost::regex("L(H|V|VB)(_L)?\\d+"); const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); From 834f5f58c28f417086bbff9b01fcdd00e9fe7e04 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 5 Sep 2018 22:24:46 -0700 Subject: [PATCH 058/174] Fix wire delays, disable BUFG I->O routethrough --- xc7/arch.cc | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index e1af6434..9b51b125 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -146,8 +146,8 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector wire_to_delay; wire_to_delay.reserve(wire_to_tilewire.size()); - const boost::regex re_124 = boost::regex("[NESW][NESWLR](\\d)((BEG(_[NS])?)|END|[A-E])?\\d"); - const boost::regex re_L = boost::regex("L(H|V|VB)(_L)?\\d+"); + const boost::regex re_124 = boost::regex("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); + const boost::regex re_L = boost::regex("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d"); @@ -160,8 +160,7 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector TorcInfo::construct_wire_to_delay(const std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir std::unordered_map arc_to_pip; ArcVector arcs; + ExtendedWireInfo ewi(ddb); for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { const auto &tw = wire_to_tilewire[i]; if (tw.isUndefined()) continue; @@ -206,16 +206,29 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir const auto& tileInfo = tiles.getTileInfo(tw.getTileIndex()); const auto tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); - bool clb = boost::starts_with(tileTypeName, "CLB"); + const bool clb = boost::starts_with(tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, !clb /* inUseRoutethrough */); auto index = pip_to_arc.size(); pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); + const boost::regex bufg_i("(CMT|CLK)_BUFG_BUFGCTRL\\d+_I0"); + const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); + auto &pips = wire_to_pips_downhill[i]; pips.reserve(arcs.size()); + const bool clk_tile = boost::starts_with(tileTypeName, "CMT") || boost::starts_with(tileTypeName, "CLK"); for (const auto& a : arcs) { + // Disable BUFG I0 -> O routethrough + if (clk_tile) { + ewi.set(a.getSourceTilewire()); + if (boost::regex_match(ewi.mWireName, bufg_i)) { + ewi.set(a.getSinkTilewire()); + if (boost::regex_match(ewi.mWireName, bufg_o)) + continue; + } + } pips.push_back(index); arc_to_pip.emplace(a, index); ++index; @@ -715,7 +728,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() { getCtx()->debug = true; return router1(getCtx(), Router1Cfg(getCtx())); } +bool Arch::route() { getCtx()->debug = true; getCtx()->verbose = true; return router1(getCtx(), Router1Cfg(getCtx())); } // ----------------------------------------------------------------------- From 735c7c7c9c096f20058b941c0c32a54cf73748a9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 11:41:36 -0700 Subject: [PATCH 059/174] torc now expected to be /opt/torc --- torc | 1 - xc7/family.cmake | 118 +++++++++++++++++++++++------------------------ 2 files changed, 59 insertions(+), 60 deletions(-) delete mode 120000 torc diff --git a/torc b/torc deleted file mode 120000 index bfd9e8f8..00000000 --- a/torc +++ /dev/null @@ -1 +0,0 @@ -../torc/src/torc \ No newline at end of file diff --git a/xc7/family.cmake b/xc7/family.cmake index 6da9fe48..4c835e38 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,69 +1,69 @@ -include_directories(.) +include_directories(/opt/torc/src) #include_directories(torc/externals/zlib) target_link_libraries( nextpnr-${family} - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Arc.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/ArcUsage.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Array.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDB.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDBConsoleStreams.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DDBStreamHelper.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/DigestStream.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/ExtendedWireInfo.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/InstancePin.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/OutputStreamHelpers.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Package.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Pad.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveConn.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveDef.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveElement.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitiveElementPin.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/PrimitivePin.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Segments.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Site.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Sites.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Tiles.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/TileInfo.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Tilewire.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/Versions.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/VprExporter.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/WireInfo.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/WireUsage.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/XdlImporter.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/architecture/XilinxDatabaseTypes.o + PRIVATE /opt/torc/src/torc/architecture/Arc.o + PRIVATE /opt/torc/src/torc/architecture/ArcUsage.o + PRIVATE /opt/torc/src/torc/architecture/Array.o + PRIVATE /opt/torc/src/torc/architecture/DDB.o + PRIVATE /opt/torc/src/torc/architecture/DDBConsoleStreams.o + PRIVATE /opt/torc/src/torc/architecture/DDBStreamHelper.o + PRIVATE /opt/torc/src/torc/architecture/DigestStream.o + PRIVATE /opt/torc/src/torc/architecture/ExtendedWireInfo.o + PRIVATE /opt/torc/src/torc/architecture/InstancePin.o + PRIVATE /opt/torc/src/torc/architecture/OutputStreamHelpers.o + PRIVATE /opt/torc/src/torc/architecture/Package.o + PRIVATE /opt/torc/src/torc/architecture/Pad.o + PRIVATE /opt/torc/src/torc/architecture/PrimitiveConn.o + PRIVATE /opt/torc/src/torc/architecture/PrimitiveDef.o + PRIVATE /opt/torc/src/torc/architecture/PrimitiveElement.o + PRIVATE /opt/torc/src/torc/architecture/PrimitiveElementPin.o + PRIVATE /opt/torc/src/torc/architecture/PrimitivePin.o + PRIVATE /opt/torc/src/torc/architecture/Segments.o + PRIVATE /opt/torc/src/torc/architecture/Site.o + PRIVATE /opt/torc/src/torc/architecture/Sites.o + PRIVATE /opt/torc/src/torc/architecture/Tiles.o + PRIVATE /opt/torc/src/torc/architecture/TileInfo.o + PRIVATE /opt/torc/src/torc/architecture/Tilewire.o + PRIVATE /opt/torc/src/torc/architecture/Versions.o + PRIVATE /opt/torc/src/torc/architecture/VprExporter.o + PRIVATE /opt/torc/src/torc/architecture/WireInfo.o + PRIVATE /opt/torc/src/torc/architecture/WireUsage.o + PRIVATE /opt/torc/src/torc/architecture/XdlImporter.o + PRIVATE /opt/torc/src/torc/architecture/XilinxDatabaseTypes.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/Annotated.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DeviceDesignator.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/Devices.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DirectoryTree.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/DottedVersion.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/common/NullOutputStream.o + PRIVATE /opt/torc/src/torc/common/Annotated.o + PRIVATE /opt/torc/src/torc/common/DeviceDesignator.o + PRIVATE /opt/torc/src/torc/common/Devices.o + PRIVATE /opt/torc/src/torc/common/DirectoryTree.o + PRIVATE /opt/torc/src/torc/common/DottedVersion.o + PRIVATE /opt/torc/src/torc/common/NullOutputStream.o PRIVATE boost_regex - PRIVATE ${CMAKE_SOURCE_DIR}/torc/externals/zlib/zfstream.o + PRIVATE /opt/torc/src/torc/externals/zlib/zfstream.o PRIVATE z - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Circuit.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/ConfigMap.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Config.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Design.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Factory.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Instance.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/InstancePin.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/InstanceReference.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Module.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/ModuleTransformer.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Named.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Net.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/OutputStreamHelpers.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Pip.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Port.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Progenitor.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Progeny.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Renamable.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/Routethrough.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/TilewirePlaceholder.o - PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/XdlExporter.o -# PRIVATE ${CMAKE_SOURCE_DIR}/torc/physical/XdlImporter.o + PRIVATE /opt/torc/src/torc/physical/Circuit.o + PRIVATE /opt/torc/src/torc/physical/ConfigMap.o + PRIVATE /opt/torc/src/torc/physical/Config.o + PRIVATE /opt/torc/src/torc/physical/Design.o + PRIVATE /opt/torc/src/torc/physical/Factory.o + PRIVATE /opt/torc/src/torc/physical/Instance.o + PRIVATE /opt/torc/src/torc/physical/InstancePin.o + PRIVATE /opt/torc/src/torc/physical/InstanceReference.o + PRIVATE /opt/torc/src/torc/physical/Module.o + PRIVATE /opt/torc/src/torc/physical/ModuleTransformer.o + PRIVATE /opt/torc/src/torc/physical/Named.o + PRIVATE /opt/torc/src/torc/physical/Net.o + PRIVATE /opt/torc/src/torc/physical/OutputStreamHelpers.o + PRIVATE /opt/torc/src/torc/physical/Pip.o + PRIVATE /opt/torc/src/torc/physical/Port.o + PRIVATE /opt/torc/src/torc/physical/Progenitor.o + PRIVATE /opt/torc/src/torc/physical/Progeny.o + PRIVATE /opt/torc/src/torc/physical/Renamable.o + PRIVATE /opt/torc/src/torc/physical/Routethrough.o + PRIVATE /opt/torc/src/torc/physical/TilewirePlaceholder.o + PRIVATE /opt/torc/src/torc/physical/XdlExporter.o +# PRIVATE /opt/torc/src/torc/physical/XdlImporter.o ) From 324ff41f1365ee2b659c404da69365a8bbe568bc Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 12:10:21 -0700 Subject: [PATCH 060/174] Fix Torc path --- xc7/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 9b51b125..042fb689 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -274,7 +274,7 @@ void IdString::initialize_arch(const BaseCtx *ctx) Arch::Arch(ArchArgs args) : args(args) { - torc::common::DirectoryTree directoryTree("../../torc/src/torc"); + torc::common::DirectoryTree directoryTree("/opt/torc/src/torc"); if (args.type == ArchArgs::Z020) { torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", "clg484")); } else { From 5d9019994eff79c355a37d3ab35d2f57f9f340b2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 12:55:36 -0700 Subject: [PATCH 061/174] [xc7] Fix getPortTimingClass for IOBs --- xc7/arch.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 042fb689..ec37edc7 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -945,9 +945,9 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id } else if (cell->type == id_IOB33) { if (port == id_I) - return TMG_STARTPOINT; - else if (port == id_O) return TMG_ENDPOINT; + else if (port == id_O) + return TMG_STARTPOINT; } else if (cell->type == id_BUFGCTRL) { if (port == id_O) From e758d8befec13dd5827d8adb6c6cbe2b00f18e86 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 12:56:46 -0700 Subject: [PATCH 062/174] Add *.xdl and *.bit to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 32fe798d..90b605c0 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ install_manifest.txt /ImportExecutables.cmake *-coverage/ *-coverage.info +*.xdl +*.bit From 0e1c23a07b2d6f59d074a17bef7d0c6a64006e20 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 13:27:39 -0700 Subject: [PATCH 063/174] [xc7] blinky.v to only have 4 LEDs --- xc7/blinky.v | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/xc7/blinky.v b/xc7/blinky.v index dba94598..179cb58c 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -4,7 +4,6 @@ module blinky ( output led2, output led3, output led4, - output led5 ); BUFGCTRL clk_gb ( @@ -14,7 +13,7 @@ module blinky ( .O(clk) ); - localparam BITS = 5; + localparam BITS = 4; localparam LOG2DELAY = 21; reg [BITS+LOG2DELAY-1:0] counter = 0; @@ -25,5 +24,5 @@ module blinky ( outcnt <= counter >> LOG2DELAY; end - assign {led1, led2, led3, led4, led5} = outcnt ^ (outcnt >> 1); + assign {led1, led2, led3, led4} = outcnt ^ (outcnt >> 1); endmodule From 8f1c91151bbeb7d02b9771266e19c4bfc8bffd19 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 13:30:58 -0700 Subject: [PATCH 064/174] Revert "[xc7] Fix getPortTimingClass for IOBs" This reverts commit 5d9019994eff79c355a37d3ab35d2f57f9f340b2. --- xc7/arch.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ec37edc7..042fb689 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -945,9 +945,9 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id } else if (cell->type == id_IOB33) { if (port == id_I) - return TMG_ENDPOINT; - else if (port == id_O) return TMG_STARTPOINT; + else if (port == id_O) + return TMG_ENDPOINT; } else if (cell->type == id_BUFGCTRL) { if (port == id_O) From c6bf8aff430b68f8a476f7559776f12c3bd74fdf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 14:24:29 -0700 Subject: [PATCH 065/174] [xc7] Fix timing analysis for constant drivers --- xc7/arch.cc | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 042fb689..cc755254 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -929,14 +929,19 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_CLOCK_INPUT; if (port == id_CIN) return TMG_COMB_INPUT; - if (port == id_COUT || port == id_O) + if (port == id_COUT) return TMG_COMB_OUTPUT; + if (port == id_O) { + // LCs with no inputs are constant drivers + if (cell->lcInfo.inputCount == 0) + return TMG_IGNORE; + return TMG_COMB_OUTPUT; + } if (cell->lcInfo.dffEnable) { clockPort = id_CLK; if (port == id_OQ) return TMG_REGISTER_OUTPUT; - else - return TMG_REGISTER_INPUT; + return TMG_REGISTER_INPUT; } else { return TMG_COMB_INPUT; } @@ -996,15 +1001,19 @@ void Arch::assignCellInfo(CellInfo *cell) cell->lcInfo.clk = get_net_or_empty(cell, id_CLK); cell->lcInfo.cen = get_net_or_empty(cell, id_CEN); cell->lcInfo.sr = get_net_or_empty(cell, id_SR); -// cell->lcInfo.inputCount = 0; -// if (get_net_or_empty(cell, id_I0)) -// cell->lcInfo.inputCount++; -// if (get_net_or_empty(cell, id_I1)) -// cell->lcInfo.inputCount++; -// if (get_net_or_empty(cell, id_I2)) -// cell->lcInfo.inputCount++; -// if (get_net_or_empty(cell, id_I3)) -// cell->lcInfo.inputCount++; + cell->lcInfo.inputCount = 0; + if (get_net_or_empty(cell, id_I1)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I2)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I3)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I4)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I5)) + cell->lcInfo.inputCount++; + if (get_net_or_empty(cell, id_I6)) + cell->lcInfo.inputCount++; } } From ac919421f01512105c2466fa0297f353b25bda0d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 14:25:20 -0700 Subject: [PATCH 066/174] Add more ISE output to .gitignore --- .gitignore | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index 90b605c0..643416f4 100644 --- a/.gitignore +++ b/.gitignore @@ -30,5 +30,17 @@ install_manifest.txt /ImportExecutables.cmake *-coverage/ *-coverage.info + +# nextpnr-xc7 *.xdl *.bit + +# ise +_xmsgs/ +*.bgn +*.drc +*.ncd +*.xwbt +usage_statistics_webtalk.html +webtalk.log +xilinx_device_details.xml From 4239e3668a3778f94918d12968f3594e7a351f37 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 15:02:09 -0700 Subject: [PATCH 067/174] [xc7] Make clg400 the default package (Zybo) --- xc7/arch.cc | 2 +- xc7/main.cc | 8 ++++---- xc7/xdl.cc | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index cc755254..9cc635ea 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -276,7 +276,7 @@ Arch::Arch(ArchArgs args) : args(args) { torc::common::DirectoryTree directoryTree("/opt/torc/src/torc"); if (args.type == ArchArgs::Z020) { - torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", "clg484")); + torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", args.package)); } else { log_error("Unsupported XC7 chip type.\n"); } diff --git a/xc7/main.cc b/xc7/main.cc index ec73c940..01e736c8 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -94,16 +94,16 @@ std::unique_ptr Xc7CommandHandler::createContext() { if (vm.count("z020")) { chipArgs.type = ArchArgs::Z020; - chipArgs.package = "clg484"; + chipArgs.package = "clg400"; } if (chipArgs.type == ArchArgs::NONE) { chipArgs.type = ArchArgs::Z020; - chipArgs.package = "clg484"; + chipArgs.package = "clg400"; } -// if (vm.count("package")) -// chipArgs.package = vm["package"].as(); + if (vm.count("package")) + chipArgs.package = vm["package"].as(); return std::unique_ptr(new Context(chipArgs)); } diff --git a/xc7/xdl.cc b/xc7/xdl.cc index a82d568d..21a1ccf5 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -35,7 +35,7 @@ NEXTPNR_NAMESPACE_BEGIN void write_xdl(const Context *ctx, std::ostream &out) { XdlExporter exporter(out); - auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), "clg484", "-1", ""); + auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), ctx->args.package, "-1", ""); std::unordered_map site_to_instance; std::vector> lut_inputs; From d80b63cc5509a1f850c11daaba485a47ab6c2c5d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 15:17:53 -0700 Subject: [PATCH 068/174] [xc7] Re-enable PCF reading --- xc7/main.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xc7/main.cc b/xc7/main.cc index 01e736c8..c24ce488 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -69,10 +69,10 @@ void Xc7CommandHandler::validate() void Xc7CommandHandler::customAfterLoad(Context *ctx) { if (vm.count("pcf")) { -// std::string filename = vm["pcf"].as(); -// std::ifstream pcf(filename); -// if (!apply_pcf(ctx, filename, pcf)) -// log_error("Loading PCF failed.\n"); + std::string filename = vm["pcf"].as(); + std::ifstream pcf(filename); + if (!apply_pcf(ctx, filename, pcf)) + log_error("Loading PCF failed.\n"); } } void Xc7CommandHandler::customBitstream(Context *ctx) From aa7f7d6a97db7e191e7f56ac63f814f2ee783615 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 15:18:26 -0700 Subject: [PATCH 069/174] clangformat --- common/timing.cc | 3 +- gui/ecp5/mainwindow.cc | 6 +- gui/fpgaviewwidget.cc | 86 +++++----- gui/fpgaviewwidget.h | 4 +- gui/lineshader.cc | 7 +- gui/lineshader.h | 12 +- ice40/arch.cc | 9 +- ice40/gfx.cc | 4 +- ice40/pack.cc | 3 +- xc7/arch.cc | 357 ++++++++++++++++++++++------------------- xc7/arch.h | 147 +++++++++-------- xc7/arch_place.cc | 190 +++++++++++----------- xc7/blinky.pcf | 12 +- xc7/cells.cc | 338 +++++++++++++++++++------------------- xc7/cells.h | 6 +- xc7/chains.cc | 3 +- xc7/delay.cc | 138 ++++++++-------- xc7/main.cc | 14 +- xc7/pack.cc | 20 ++- xc7/pcf.cc | 8 +- xc7/xdl.cc | 103 +++++++----- 21 files changed, 764 insertions(+), 706 deletions(-) diff --git a/common/timing.cc b/common/timing.cc index d1a85779..81ce7b73 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -212,7 +212,8 @@ struct Timing for (auto net : boost::adaptors::reverse(topographical_order)) { auto &nd = net_data.at(net); // Ignore false startpoints - if (nd.false_startpoint) continue; + if (nd.false_startpoint) + continue; const delay_t net_length_plus_one = nd.max_path_length + 1; auto &net_min_remaining_budget = nd.min_remaining_budget; for (auto &usr : net->users) { diff --git a/gui/ecp5/mainwindow.cc b/gui/ecp5/mainwindow.cc index fe2f9e57..c6c7bc97 100644 --- a/gui/ecp5/mainwindow.cc +++ b/gui/ecp5/mainwindow.cc @@ -18,9 +18,9 @@ */ #include "mainwindow.h" +#include #include "bitstream.h" #include "log.h" -#include #include #include @@ -150,7 +150,7 @@ void MainWindow::open_lpf() { QString fileName = QFileDialog::getOpenFileName(this, QString("Open LPF"), QString(), QString("*.lpf")); if (!fileName.isEmpty()) { - std::ifstream in(fileName.toStdString()); + std::ifstream in(fileName.toStdString()); if (ctx->applyLPF(fileName.toStdString(), in)) { log("Loading LPF successful.\n"); actionPack->setEnabled(true); @@ -158,7 +158,7 @@ void MainWindow::open_lpf() } else { actionLoadLPF->setEnabled(true); log("Loading LPF failed.\n"); - } + } } } diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 24fbc35d..e6f68d22 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -107,9 +107,8 @@ void FPGAViewWidget::initializeGL() } initializeOpenGLFunctions(); QtImGui::initialize(this); - glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, - colors_.background.blue() / 255, 0.0); - + glClearColor(colors_.background.red() / 255, colors_.background.green() / 255, colors_.background.blue() / 255, + 0.0); { QMutexLocker locker(&rendererDataLock_); @@ -321,30 +320,22 @@ void FPGAViewWidget::paintGL() } // Render the grid. - lineShader_.draw(GraphicElement::STYLE_GRID, colors_.grid, thick1Px, - matrix); + lineShader_.draw(GraphicElement::STYLE_GRID, colors_.grid, thick1Px, matrix); // Render Arch graphics. - lineShader_.draw(GraphicElement::STYLE_FRAME, colors_.frame, thick11Px, - matrix); - lineShader_.draw(GraphicElement::STYLE_HIDDEN, colors_.hidden, thick11Px, - matrix); - lineShader_.draw(GraphicElement::STYLE_INACTIVE, colors_.inactive, - thick11Px, matrix); - lineShader_.draw(GraphicElement::STYLE_ACTIVE, colors_.active, thick11Px, - matrix); + lineShader_.draw(GraphicElement::STYLE_FRAME, colors_.frame, thick11Px, matrix); + lineShader_.draw(GraphicElement::STYLE_HIDDEN, colors_.hidden, thick11Px, matrix); + lineShader_.draw(GraphicElement::STYLE_INACTIVE, colors_.inactive, thick11Px, matrix); + lineShader_.draw(GraphicElement::STYLE_ACTIVE, colors_.active, thick11Px, matrix); // Draw highlighted items. for (int i = 0; i < 8; i++) { - GraphicElement::style_t style = (GraphicElement::style_t)( - GraphicElement::STYLE_HIGHLIGHTED0 + i); + GraphicElement::style_t style = (GraphicElement::style_t)(GraphicElement::STYLE_HIGHLIGHTED0 + i); lineShader_.draw(style, colors_.highlight[i], thick11Px, matrix); } - lineShader_.draw(GraphicElement::STYLE_SELECTED, colors_.selected, - thick11Px, matrix); - lineShader_.draw(GraphicElement::STYLE_HOVER, colors_.hovered, - thick2Px, matrix); + lineShader_.draw(GraphicElement::STYLE_SELECTED, colors_.selected, thick11Px, matrix); + lineShader_.draw(GraphicElement::STYLE_HOVER, colors_.hovered, thick2Px, matrix); // Flags from pipeline. PassthroughFlags flags = rendererData_->flags; @@ -364,8 +355,7 @@ void FPGAViewWidget::paintGL() } QtImGui::newFrame(); QMutexLocker lock(&rendererArgsLock_); - if (!(rendererArgs_->hoveredDecal == DecalXY()) && rendererArgs_->hintText.size() > 0) - { + if (!(rendererArgs_->hoveredDecal == DecalXY()) && rendererArgs_->hintText.size() > 0) { ImGui::SetNextWindowPos(ImVec2(rendererArgs_->x, rendererArgs_->y)); ImGui::BeginTooltip(); ImGui::PushTextWrapPos(ImGui::GetFontSize() * 35.0f); @@ -373,7 +363,7 @@ void FPGAViewWidget::paintGL() ImGui::PopTextWrapPos(); ImGui::EndTooltip(); } - ImGui::Render(); + ImGui::Render(); } void FPGAViewWidget::pokeRenderer(void) { renderRunner_->poke(); } @@ -465,10 +455,10 @@ void FPGAViewWidget::renderLines(void) int last_render[GraphicElement::STYLE_HIGHLIGHTED0]; { QMutexLocker locker(&rendererDataLock_); - for(int i =0; igfxByStyle[(enum GraphicElement::style_t)i].last_render; } - + auto data = std::unique_ptr(new FPGAViewWidget::RendererData); // Reset bounding box. data->bbGlobal.clear(); @@ -534,7 +524,7 @@ void FPGAViewWidget::renderLines(void) for (int i = 0; i < 8; i++) data->gfxHighlighted[i] = rendererData_->gfxHighlighted[i]; } - for(int i =0; igfxByStyle[(enum GraphicElement::style_t)i].last_render = ++last_render[i]; rendererData_ = std::move(data); } @@ -545,7 +535,7 @@ void FPGAViewWidget::renderLines(void) // Whether the currently being hovered decal is also selected. bool hoveringSelected = false; - // Render selected. + // Render selected. rendererData_->bbSelected.clear(); rendererData_->gfxSelected.clear(); for (auto &decal : selectedDecals) { @@ -655,7 +645,8 @@ boost::optional FPGAViewWidget::pickElement(float void FPGAViewWidget::mousePressEvent(QMouseEvent *event) { ImGuiIO &io = ImGui::GetIO(); - if (io.WantCaptureMouse) return; + if (io.WantCaptureMouse) + return; if (event->buttons() & Qt::RightButton || event->buttons() & Qt::MidButton) { lastDragPos_ = event->pos(); @@ -691,7 +682,8 @@ void FPGAViewWidget::mousePressEvent(QMouseEvent *event) void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event) { ImGuiIO &io = ImGui::GetIO(); - if (io.WantCaptureMouse) return; + if (io.WantCaptureMouse) + return; if (event->buttons() & Qt::RightButton || event->buttons() & Qt::MidButton) { const int dx = event->x() - lastDragPos_.x(); @@ -728,22 +720,23 @@ void FPGAViewWidget::mouseMoveEvent(QMouseEvent *event) if (closest.type == ElementType::BEL) { rendererArgs_->hintText = std::string("BEL\n") + ctx_->getBelName(closest.bel).c_str(ctx_); CellInfo *cell = ctx_->getBoundBelCell(closest.bel); - if (cell!=nullptr) - rendererArgs_->hintText += std::string("\nCELL\n") +ctx_->nameOf(cell); + if (cell != nullptr) + rendererArgs_->hintText += std::string("\nCELL\n") + ctx_->nameOf(cell); } else if (closest.type == ElementType::WIRE) { rendererArgs_->hintText = std::string("WIRE\n") + ctx_->getWireName(closest.wire).c_str(ctx_); NetInfo *net = ctx_->getBoundWireNet(closest.wire); - if (net!=nullptr) - rendererArgs_->hintText += std::string("\nNET\n") +ctx_->nameOf(net); + if (net != nullptr) + rendererArgs_->hintText += std::string("\nNET\n") + ctx_->nameOf(net); } else if (closest.type == ElementType::PIP) { rendererArgs_->hintText = std::string("PIP\n") + ctx_->getPipName(closest.pip).c_str(ctx_); NetInfo *net = ctx_->getBoundPipNet(closest.pip); - if (net!=nullptr) - rendererArgs_->hintText += std::string("\nNET\n") +ctx_->nameOf(net); + if (net != nullptr) + rendererArgs_->hintText += std::string("\nNET\n") + ctx_->nameOf(net); } else if (closest.type == ElementType::GROUP) { rendererArgs_->hintText = std::string("GROUP\n") + ctx_->getGroupName(closest.group).c_str(ctx_); - } else rendererArgs_->hintText = ""; - + } else + rendererArgs_->hintText = ""; + pokeRenderer(); } update(); @@ -793,8 +786,9 @@ QVector4D FPGAViewWidget::mouseToWorldDimensions(float x, float y) void FPGAViewWidget::wheelEvent(QWheelEvent *event) { ImGuiIO &io = ImGui::GetIO(); - if (io.WantCaptureMouse) return; - + if (io.WantCaptureMouse) + return; + QPoint degree = event->angleDelta() / 8; if (!degree.isNull()) @@ -876,23 +870,17 @@ void FPGAViewWidget::leaveEvent(QEvent *event) void FPGAViewWidget::update_vbos() { - for (int style = GraphicElement::STYLE_FRAME; style - < GraphicElement::STYLE_HIGHLIGHTED0; - style++) { - lineShader_.update_vbos((enum GraphicElement::style_t)(style), - rendererData_->gfxByStyle[style]); + for (int style = GraphicElement::STYLE_FRAME; style < GraphicElement::STYLE_HIGHLIGHTED0; style++) { + lineShader_.update_vbos((enum GraphicElement::style_t)(style), rendererData_->gfxByStyle[style]); } for (int i = 0; i < 8; i++) { - GraphicElement::style_t style = (GraphicElement::style_t)( - GraphicElement::STYLE_HIGHLIGHTED0 + i); + GraphicElement::style_t style = (GraphicElement::style_t)(GraphicElement::STYLE_HIGHLIGHTED0 + i); lineShader_.update_vbos(style, rendererData_->gfxHighlighted[i]); } - lineShader_.update_vbos(GraphicElement::STYLE_SELECTED, - rendererData_->gfxSelected); - lineShader_.update_vbos(GraphicElement::STYLE_HOVER, - rendererData_->gfxHovered); + lineShader_.update_vbos(GraphicElement::STYLE_SELECTED, rendererData_->gfxSelected); + lineShader_.update_vbos(GraphicElement::STYLE_HOVER, rendererData_->gfxHovered); } NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index e76e6f32..a4830898 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -127,7 +127,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions private: const float zoomNear_ = 0.1f; // do not zoom closer than this - float zoomFar_ = 10.0f; // do not zoom further than this + float zoomFar_ = 10.0f; // do not zoom further than this const float zoomLvl1_ = 1.0f; const float zoomLvl2_ = 5.0f; @@ -271,7 +271,7 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions // Hint text std::string hintText; // cursor pos - int x,y; + int x, y; }; std::unique_ptr rendererArgs_; QMutex rendererArgsLock_; diff --git a/gui/lineshader.cc b/gui/lineshader.cc index fc726df5..eded1689 100644 --- a/gui/lineshader.cc +++ b/gui/lineshader.cc @@ -206,8 +206,7 @@ bool LineShader::compile(void) return true; } -void LineShader::update_vbos(enum GraphicElement::style_t style, - const LineShaderData &line) +void LineShader::update_vbos(enum GraphicElement::style_t style, const LineShaderData &line) { if (buffers_[style].last_vbo_update == line.last_render) return; @@ -230,8 +229,8 @@ void LineShader::update_vbos(enum GraphicElement::style_t style, buffers_[style].index.allocate(&line.indices[0], sizeof(GLuint) * line.indices.size()); } -void LineShader::draw(enum GraphicElement::style_t style, const QColor &color, - float thickness, const QMatrix4x4 &projection) +void LineShader::draw(enum GraphicElement::style_t style, const QColor &color, float thickness, + const QMatrix4x4 &projection) { auto gl = QOpenGLContext::currentContext()->functions(); if (buffers_[style].indices == 0) diff --git a/gui/lineshader.h b/gui/lineshader.h index eb0f9e09..98042051 100644 --- a/gui/lineshader.h +++ b/gui/lineshader.h @@ -20,12 +20,12 @@ #ifndef LINESHADER_H #define LINESHADER_H -#include #include #include #include #include #include +#include #include "log.h" #include "nextpnr.h" @@ -169,9 +169,7 @@ class LineShader } uniforms_; public: - LineShader(QObject *parent) : parent_(parent), program_(nullptr) - { - } + LineShader(QObject *parent) : parent_(parent), program_(nullptr) {} static constexpr const char *vertexShaderSource_ = "#version 110\n" @@ -194,12 +192,10 @@ class LineShader // Must be called on initialization. bool compile(void); - void update_vbos(enum GraphicElement::style_t style, - const LineShaderData &line); + void update_vbos(enum GraphicElement::style_t style, const LineShaderData &line); // Render a LineShaderData with a given M/V/P transformation. - void draw(enum GraphicElement::style_t style, const QColor &color, - float thickness, const QMatrix4x4 &projection); + void draw(enum GraphicElement::style_t style, const QColor &color, float thickness, const QMatrix4x4 &projection); }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.cc b/ice40/arch.cc index eb26ae5a..d940e773 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -872,16 +872,13 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id if (cell->lcInfo.dffEnable) { clockPort = id_CLK; return TMG_REGISTER_OUTPUT; - } - else + } else return TMG_COMB_OUTPUT; - } - else { + } else { if (cell->lcInfo.dffEnable) { clockPort = id_CLK; return TMG_REGISTER_INPUT; - } - else + } else return TMG_COMB_INPUT; } } else if (cell->type == id_ICESTORM_RAM) { diff --git a/ice40/gfx.cc b/ice40/gfx.cc index c41c424b..7ef43663 100644 --- a/ice40/gfx.cc +++ b/ice40/gfx.cc @@ -972,11 +972,11 @@ void gfxTilePip(std::vector &g, int x, int y, GfxTileWireId src, return; } - if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2)) { + if (getWireXY_local(src, x1, y1) && getWireXY_local(dst, x2, y2)) { pipGfx(g, x, y, x1, y1, x2, y2, local_swbox_x1, local_swbox_y1, local_swbox_x2, local_swbox_y2, style); return; } - + if (TILE_WIRE_LUTFF_0_IN_0_LUT <= src && src <= TILE_WIRE_LUTFF_7_IN_3_LUT && TILE_WIRE_LUTFF_0_OUT <= dst && dst <= TILE_WIRE_LUTFF_7_OUT) { int lut_idx = (src - TILE_WIRE_LUTFF_0_IN_0_LUT) / 4; diff --git a/ice40/pack.cc b/ice40/pack.cc index edd12f92..b9360b74 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -462,7 +462,8 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) { - log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "", is_logic ? " [logic]" : ""); + log_info("promoting %s%s%s%s\n", net->name.c_str(ctx), is_reset ? " [reset]" : "", is_cen ? " [cen]" : "", + is_logic ? " [logic]" : ""); std::string glb_name = net->name.str(ctx) + std::string("_$glb_") + (is_reset ? "sr" : (is_cen ? "ce" : "clk")); std::unique_ptr gb = create_ice_cell(ctx, ctx->id("SB_GB"), "$gbuf_" + glb_name); diff --git a/xc7/arch.cc b/xc7/arch.cc index 9cc635ea..18f5b64e 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -32,19 +32,25 @@ NEXTPNR_NAMESPACE_BEGIN - std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), + segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), + num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), + bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), + wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), + num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)), + pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), + num_pips(pip_to_arc.size()) { pip_to_dst_wire.reserve(num_pips); - for (const auto& arc : pip_to_arc) { + for (const auto &arc : pip_to_arc) { const auto &tw = arc.getSinkTilewire(); pip_to_dst_wire.push_back(tilewire_to_wire(tw)); } } -std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Sites &sites) +std::vector TorcInfo::construct_bel_to_site_index(Arch *ctx, const Sites &sites) { std::vector bel_to_site_index; bel_to_site_index.reserve(sites.getSiteCount()); @@ -57,13 +63,12 @@ std::vector TorcInfo::construct_bel_to_site_index(Arch* ctx, const Si bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); - } - else + } else bel_to_site_index.push_back(i); } return bel_to_site_index; } -std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Sites &sites) +std::vector TorcInfo::construct_site_index_to_type(Arch *ctx, const Sites &sites) { std::vector site_index_to_type; site_index_to_type.resize(sites.getSiteCount()); @@ -80,7 +85,8 @@ std::vector TorcInfo::construct_site_index_to_type(Arch* ctx, const Si } return site_index_to_type; } -std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type) +std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, + const std::vector &site_index_to_type) { std::vector bel_to_loc; bel_to_loc.resize(num_bels); @@ -94,44 +100,46 @@ std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles if (site_index_to_type[i] == id_SLICE_LUT6) { const auto site_name = site.getName(); const auto site_name_back = site_name.back(); - if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || site_name_back == '8') { + if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || + site_name_back == '8') { bel_to_loc[bel_index++] = Loc(x, y, 0); bel_to_loc[bel_index++] = Loc(x, y, 1); bel_to_loc[bel_index++] = Loc(x, y, 2); bel_to_loc[bel_index++] = Loc(x, y, 3); - } - else { + } else { bel_to_loc[bel_index++] = Loc(x, y, 4); bel_to_loc[bel_index++] = Loc(x, y, 5); bel_to_loc[bel_index++] = Loc(x, y, 6); bel_to_loc[bel_index++] = Loc(x, y, 7); } - } - else + } else bel_to_loc[bel_index++] = Loc(x, y, 0); } return bel_to_loc; } -std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segments, const Tiles& tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire) +std::vector +TorcInfo::construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, + std::unordered_map &segment_to_wire, + std::unordered_map &trivial_to_wire) { std::vector wire_to_tilewire; Tilewire currentTilewire; - for(TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { + for (TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { // iterate over every wire in the tile - const auto& tileInfo = tiles.getTileInfo(tileIndex); + const auto &tileInfo = tiles.getTileInfo(tileIndex); auto tileTypeIndex = tileInfo.getTypeIndex(); auto wireCount = tiles.getWireCount(tileTypeIndex); currentTilewire.setTileIndex(tileIndex); - for(WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { + for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { currentTilewire.setWireIndex(wireIndex); - const auto& currentSegment = segments.getTilewireSegment(currentTilewire); + const auto ¤tSegment = segments.getTilewireSegment(currentTilewire); if (!currentSegment.isTrivial()) { - if (currentSegment.getAnchorTileIndex() != tileIndex) continue; + if (currentSegment.getAnchorTileIndex() != tileIndex) + continue; segment_to_wire.emplace(currentSegment, wire_to_tilewire.size()); - } - else + } else trivial_to_wire.emplace(currentTilewire, wire_to_tilewire.size()); wire_to_tilewire.push_back(currentTilewire); @@ -141,46 +149,54 @@ std::vector TorcInfo::construct_wire_to_tilewire(const Segments& segme wire_to_tilewire.shrink_to_fit(); return wire_to_tilewire; } -std::vector TorcInfo::construct_wire_to_delay(const std::vector& wire_to_tilewire, const DDB &ddb) +std::vector TorcInfo::construct_wire_to_delay(const std::vector &wire_to_tilewire, const DDB &ddb) { std::vector wire_to_delay; wire_to_delay.reserve(wire_to_tilewire.size()); - const boost::regex re_124 = boost::regex("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); - const boost::regex re_L = boost::regex("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); - const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); - const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); + const boost::regex re_124 = boost::regex("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); + const boost::regex re_L = boost::regex("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); + const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); + const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d"); - const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d"); + const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d"); boost::cmatch what; ExtendedWireInfo ewi(ddb); - for (const auto &tw : wire_to_tilewire) - { + for (const auto &tw : wire_to_tilewire) { ewi.set(tw); DelayInfo d; if (boost::regex_match(ewi.mWireName, what, re_124)) { switch (what.str(2)[0]) { - case '1': d.delay = 150; break; - case '2': d.delay = 170; break; - case '4': d.delay = 210; break; - case '6': d.delay = 210; break; - default: throw; + case '1': + d.delay = 150; + break; + case '2': + d.delay = 170; + break; + case '4': + d.delay = 210; + break; + case '6': + d.delay = 210; + break; + default: + throw; } - } - else if (boost::regex_match(ewi.mWireName, what, re_L)) { + } else if (boost::regex_match(ewi.mWireName, what, re_L)) { std::string l(what[2]); - if (l == "H") d.delay = 360; - else if (l == "VB") d.delay = 300; - else if (l == "V") d.delay = 350; - else throw; - } - else if (boost::regex_match(ewi.mWireName, what, re_BYP)) { + if (l == "H") + d.delay = 360; + else if (l == "VB") + d.delay = 300; + else if (l == "V") + d.delay = 350; + else + throw; + } else if (boost::regex_match(ewi.mWireName, what, re_BYP)) { d.delay = 190; - } - else if (boost::regex_match(ewi.mWireName, what, re_BYP_B)) { - } - else if (boost::regex_match(ewi.mWireName, what, re_FAN)) { + } else if (boost::regex_match(ewi.mWireName, what, re_BYP_B)) { + } else if (boost::regex_match(ewi.mWireName, what, re_FAN)) { d.delay = 190; } wire_to_delay.emplace_back(std::move(d)); @@ -188,7 +204,9 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector TorcInfo::construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill) +std::vector TorcInfo::construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, + std::vector> &wire_to_pips_uphill, + std::vector> &wire_to_pips_downhill) { const auto &tiles = ddb.getTiles(); @@ -201,14 +219,18 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir ExtendedWireInfo ewi(ddb); for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { const auto &tw = wire_to_tilewire[i]; - if (tw.isUndefined()) continue; + if (tw.isUndefined()) + continue; arcs.clear(); - const auto& tileInfo = tiles.getTileInfo(tw.getTileIndex()); + const auto &tileInfo = tiles.getTileInfo(tw.getTileIndex()); const auto tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); - const bool clb = boost::starts_with(tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) + const bool clb = boost::starts_with( + tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) - const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, !clb /* inUseRoutethrough */); + const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, + true /*inUseRegular */, true /* inUseIrregular */, + !clb /* inUseRoutethrough */); auto index = pip_to_arc.size(); pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); @@ -219,7 +241,7 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir auto &pips = wire_to_pips_downhill[i]; pips.reserve(arcs.size()); const bool clk_tile = boost::starts_with(tileTypeName, "CMT") || boost::starts_with(tileTypeName, "CLK"); - for (const auto& a : arcs) { + for (const auto &a : arcs) { // Disable BUFG I0 -> O routethrough if (clk_tile) { ewi.set(a.getSourceTilewire()); @@ -240,27 +262,27 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector& wir wire_to_pips_uphill.resize(wire_to_tilewire.size()); for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { const auto &tw = wire_to_tilewire[i]; - if (tw.isUndefined()) continue; + if (tw.isUndefined()) + continue; arcs.clear(); - //const_cast(ddb).expandSegmentSources(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); + // const_cast(ddb).expandSegmentSources(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true + // /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); auto &pips = wire_to_pips_uphill[i]; pips.reserve(arcs.size()); - for (const auto& a : arcs) + for (const auto &a : arcs) pips.push_back(arc_to_pip.at(a)); } return pip_to_arc; } -std::vector -construct_pip_to_dst_wire(const std::vector& pip_to_arc) +std::vector construct_pip_to_dst_wire(const std::vector &pip_to_arc) { std::vector pip_to_wire; return pip_to_wire; } - // ----------------------------------------------------------------------- void IdString::initialize_arch(const BaseCtx *ctx) @@ -281,21 +303,21 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported XC7 chip type.\n"); } -// package_info = nullptr; -// for (int i = 0; i < chip_info->num_packages; i++) { -// if (chip_info->packages_data[i].name.get() == args.package) { -// package_info = &(chip_info->packages_data[i]); -// break; -// } -// } -// if (package_info == nullptr) -// log_error("Unsupported package '%s'.\n", args.package.c_str()); + // package_info = nullptr; + // for (int i = 0; i < chip_info->num_packages; i++) { + // if (chip_info->packages_data[i].name.get() == 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_carry.resize(chip_info->num_bels); + // bel_carry.resize(chip_info->num_bels); bel_to_cell.resize(torc_info->num_bels); wire_to_net.resize(torc_info->num_wires); pip_to_net.resize(torc_info->num_pips); - //switches_locked.resize(chip_info->num_switches); + // switches_locked.resize(chip_info->num_switches); } // ----------------------------------------------------------------------- @@ -403,11 +425,24 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { switch (torc_info->bel_to_loc[bel.index].z) { - case 0: case 4: pin_name[0] = 'A'; break; - case 1: case 5: pin_name[0] = 'B'; break; - case 2: case 6: pin_name[0] = 'C'; break; - case 3: case 7: pin_name[0] = 'D'; break; - default: throw; + case 0: + case 4: + pin_name[0] = 'A'; + break; + case 1: + case 5: + pin_name[0] = 'B'; + break; + case 2: + case 6: + pin_name[0] = 'C'; + break; + case 3: + case 7: + pin_name[0] = 'D'; + break; + default: + throw; } } } @@ -416,36 +451,37 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const auto &tw = site.getPinTilewire(pin_name); if (tw.isUndefined()) - log_error("no wire found for site '%s' pin '%s' \n", torc_info->bel_to_name(bel.index).c_str(), pin_name.c_str()); + log_error("no wire found for site '%s' pin '%s' \n", torc_info->bel_to_name(bel.index).c_str(), + pin_name.c_str()); ret.index = torc_info->tilewire_to_wire(tw); -// NPNR_ASSERT(bel != BelId()); -// -// int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; -// const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); -// -// if (num_bel_wires < 7) { -// for (int i = 0; i < num_bel_wires; i++) { -// if (bel_wires[i].port == pin.index) { -// ret.index = bel_wires[i].wire_index; -// break; -// } -// } -// } else { -// int b = 0, e = num_bel_wires - 1; -// while (b <= e) { -// int i = (b + e) / 2; -// if (bel_wires[i].port == pin.index) { -// ret.index = bel_wires[i].wire_index; -// break; -// } -// if (bel_wires[i].port > pin.index) -// e = i - 1; -// else -// b = i + 1; -// } -// } + // NPNR_ASSERT(bel != BelId()); + // + // int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + // const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + // + // if (num_bel_wires < 7) { + // for (int i = 0; i < num_bel_wires; i++) { + // if (bel_wires[i].port == pin.index) { + // ret.index = bel_wires[i].wire_index; + // break; + // } + // } + // } else { + // int b = 0, e = num_bel_wires - 1; + // while (b <= e) { + // int i = (b + e) / 2; + // if (bel_wires[i].port == pin.index) { + // ret.index = bel_wires[i].wire_index; + // break; + // } + // if (bel_wires[i].port > pin.index) + // e = i - 1; + // else + // b = i + 1; + // } + // } return ret; } @@ -476,8 +512,8 @@ WireId Arch::getWireByName(IdString name) const wire_by_name[id(chip_info->wire_data[i].name.get())] = i; } - //auto it = wire_by_name.find(name); - //if (it != wire_by_name.end()) + // auto it = wire_by_name.find(name); + // if (it != wire_by_name.end()) // ret.index = it->second; return ret; @@ -486,38 +522,38 @@ WireId Arch::getWireByName(IdString name) const IdString Arch::getWireType(WireId wire) const { NPNR_ASSERT(wire != WireId()); -// switch (chip_info->wire_data[wire.index].type) { -// case WireInfoPOD::WIRE_TYPE_NONE: -// return IdString(); -// case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: -// return id("GLB2LOCAL"); -// case WireInfoPOD::WIRE_TYPE_GLB_NETWK: -// return id("GLB_NETWK"); -// case WireInfoPOD::WIRE_TYPE_LOCAL: -// return id("LOCAL"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_IN: -// return id("LUTFF_IN"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: -// return id("LUTFF_IN_LUT"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: -// return id("LUTFF_LOUT"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: -// return id("LUTFF_OUT"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: -// return id("LUTFF_COUT"); -// case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: -// return id("LUTFF_GLOBAL"); -// case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: -// return id("CARRY_IN_MUX"); -// case WireInfoPOD::WIRE_TYPE_SP4_V: -// return id("SP4_V"); -// case WireInfoPOD::WIRE_TYPE_SP4_H: -// return id("SP4_H"); -// case WireInfoPOD::WIRE_TYPE_SP12_V: -// return id("SP12_V"); -// case WireInfoPOD::WIRE_TYPE_SP12_H: -// return id("SP12_H"); -// } + // switch (chip_info->wire_data[wire.index].type) { + // case WireInfoPOD::WIRE_TYPE_NONE: + // return IdString(); + // case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: + // return id("GLB2LOCAL"); + // case WireInfoPOD::WIRE_TYPE_GLB_NETWK: + // return id("GLB_NETWK"); + // case WireInfoPOD::WIRE_TYPE_LOCAL: + // return id("LOCAL"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_IN: + // return id("LUTFF_IN"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: + // return id("LUTFF_IN_LUT"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: + // return id("LUTFF_LOUT"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: + // return id("LUTFF_OUT"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: + // return id("LUTFF_COUT"); + // case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: + // return id("LUTFF_GLOBAL"); + // case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: + // return id("CARRY_IN_MUX"); + // case WireInfoPOD::WIRE_TYPE_SP4_V: + // return id("SP4_V"); + // case WireInfoPOD::WIRE_TYPE_SP4_H: + // return id("SP4_H"); + // case WireInfoPOD::WIRE_TYPE_SP12_V: + // return id("SP12_V"); + // case WireInfoPOD::WIRE_TYPE_SP12_H: + // return id("SP12_H"); + // } return IdString(); } @@ -566,23 +602,23 @@ IdString Arch::getPipName(PipId pip) const BelId Arch::getPackagePinBel(const std::string &pin) const { -// for (int i = 0; i < package_info->num_pins; i++) { -// if (package_info->pins[i].name.get() == pin) { -// BelId id; -// id.index = package_info->pins[i].bel_index; -// return id; -// } -// } + // for (int i = 0; i < package_info->num_pins; i++) { + // if (package_info->pins[i].name.get() == pin) { + // BelId id; + // id.index = package_info->pins[i].bel_index; + // return id; + // } + // } return BelId(); } std::string Arch::getBelPackagePin(BelId bel) const { -// for (int i = 0; i < package_info->num_pins; i++) { -// if (package_info->pins[i].bel_index == bel.index) { -// return std::string(package_info->pins[i].name.get()); -// } -// } + // for (int i = 0; i < package_info->num_pins; i++) { + // if (package_info->pins[i].bel_index == bel.index) { + // return std::string(package_info->pins[i].name.get()); + // } + // } return ""; } @@ -719,16 +755,18 @@ std::vector Arch::getGroupGroups(GroupId group) const // ----------------------------------------------------------------------- -bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const -{ - return false; -} +bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; } // ----------------------------------------------------------------------- bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() { getCtx()->debug = true; getCtx()->verbose = true; return router1(getCtx(), Router1Cfg(getCtx())); } +bool Arch::route() +{ + getCtx()->debug = true; + getCtx()->verbose = true; + return router1(getCtx(), Router1Cfg(getCtx())); +} // ----------------------------------------------------------------------- @@ -909,13 +947,10 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { - if (cell->type == id_SLICE_LUT6) - { + if (cell->type == id_SLICE_LUT6) { if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) return toPort == id_O || toPort == id_OQ; - } - else if (cell->type == id_BUFGCTRL) - { + } else if (cell->type == id_BUFGCTRL) { return true; } return false; @@ -946,15 +981,13 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_COMB_INPUT; } // TODO - //if (port == id_OMUX) - } - else if (cell->type == id_IOB33) { + // if (port == id_OMUX) + } else if (cell->type == id_IOB33) { if (port == id_I) return TMG_STARTPOINT; else if (port == id_O) return TMG_ENDPOINT; - } - else if (cell->type == id_BUFGCTRL) { + } else if (cell->type == id_BUFGCTRL) { if (port == id_O) return TMG_COMB_OUTPUT; return TMG_COMB_INPUT; diff --git a/xc7/arch.h b/xc7/arch.h index a179139e..b5721552 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -27,8 +27,8 @@ using namespace torc::architecture; using namespace torc::architecture::xilinx; namespace std { - template <> struct hash - { +template <> struct hash +{ size_t operator()(const Segments::SegmentReference &s) const { size_t seed = 0; @@ -36,24 +36,22 @@ namespace std { boost::hash_combine(seed, hash()(s.getAnchorTileIndex())); return seed; } - }; - template <> struct equal_to - { +}; +template <> struct equal_to +{ bool operator()(const Segments::SegmentReference &lhs, const Segments::SegmentReference &rhs) const { - return lhs.getAnchorTileIndex() == rhs.getAnchorTileIndex() && lhs.getCompactSegmentIndex() == rhs.getCompactSegmentIndex(); + return lhs.getAnchorTileIndex() == rhs.getAnchorTileIndex() && + lhs.getCompactSegmentIndex() == rhs.getCompactSegmentIndex(); } - }; - template <> struct hash - { - size_t operator()(const Tilewire& t) const - { - return hash_value(t); - } - }; +}; +template <> struct hash +{ + size_t operator()(const Tilewire &t) const { return hash_value(t); } +}; - template <> struct hash - { +template <> struct hash +{ size_t operator()(const Arc &a) const { size_t seed = 0; @@ -61,8 +59,8 @@ namespace std { boost::hash_combine(seed, hash_value(a.getSinkTilewire())); return seed; } - }; -} +}; +} // namespace std NEXTPNR_NAMESPACE_BEGIN @@ -270,21 +268,23 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { RelPtr cell_timing; }); - struct Arch; -struct TorcInfo { +struct TorcInfo +{ TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName); std::unique_ptr ddb; const Sites &sites; const Tiles &tiles; const Segments &segments; - const TileInfo& bel_to_tile_info(int32_t index) const { + const TileInfo &bel_to_tile_info(int32_t index) const + { auto si = bel_to_site_index[index]; const auto &site = sites.getSite(si); return tiles.getTileInfo(site.getTileIndex()); } - const std::string& bel_to_name(int32_t index) const { + const std::string &bel_to_name(int32_t index) const + { auto si = bel_to_site_index[index]; return sites.getSite(si).getName(); } @@ -309,8 +309,8 @@ struct TorcInfo { const int num_bels; const std::vector site_index_to_type; const std::vector bel_to_loc; - std::unordered_map segment_to_wire; - std::unordered_map trivial_to_wire; + std::unordered_map segment_to_wire; + std::unordered_map trivial_to_wire; const std::vector wire_to_tilewire; const int num_wires; const std::vector wire_to_delay; @@ -320,17 +320,23 @@ struct TorcInfo { const int num_pips; std::vector pip_to_dst_wire; -private: + private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); - static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type); - static std::vector construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map& segment_to_wire, std::unordered_map& trivial_to_wire); - static std::vector construct_wire_to_delay(const std::vector& wire_to_tilewire, const DDB &ddb); - static std::vector construct_pip_to_arc(const std::vector& wire_to_tilewire, const DDB& ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); + static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, + const std::vector &site_index_to_type); + static std::vector + construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, + std::unordered_map &segment_to_wire, + std::unordered_map &trivial_to_wire); + static std::vector construct_wire_to_delay(const std::vector &wire_to_tilewire, + const DDB &ddb); + static std::vector construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, + std::vector> &wire_to_pips_uphill, + std::vector> &wire_to_pips_downhill); }; extern std::unique_ptr torc_info; - /************************ End of chipdb section. ************************/ struct BelIterator @@ -486,11 +492,11 @@ struct Arch : BaseCtx mutable std::unordered_map pip_by_name; mutable std::unordered_map bel_by_loc; - //std::vector bel_carry; + // std::vector bel_carry; std::vector bel_to_cell; std::vector wire_to_net; std::vector pip_to_net; - //std::vector switches_locked; + // std::vector switches_locked; ArchArgs args; Arch(ArchArgs args); @@ -521,11 +527,24 @@ struct Arch : BaseCtx name.reserve(name.size() + 2); name += "_"; switch (torc_info->bel_to_loc[bel.index].z) { - case 0: case 4: name += 'A'; break; - case 1: case 5: name += 'B'; break; - case 2: case 6: name += 'C'; break; - case 3: case 7: name += 'D'; break; - default: throw; + case 0: + case 4: + name += 'A'; + break; + case 1: + case 5: + name += 'B'; + break; + case 2: + case 6: + name += 'C'; + break; + case 3: + case 7: + name += 'D'; + break; + default: + throw; } } return id(name); @@ -539,7 +558,7 @@ struct Arch : BaseCtx NPNR_ASSERT(bel_to_cell[bel.index] == nullptr); bel_to_cell[bel.index] = cell; - //bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable); + // bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable); cell->bel = bel; cell->belStrength = strength; refreshUiBel(bel); @@ -552,7 +571,7 @@ struct Arch : BaseCtx bel_to_cell[bel.index]->bel = BelId(); bel_to_cell[bel.index]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = nullptr; - //bel_carry[bel.index] = false; + // bel_carry[bel.index] = false; refreshUiBel(bel); } @@ -582,10 +601,7 @@ struct Arch : BaseCtx return range; } - Loc getBelLocation(BelId bel) const - { - return torc_info->bel_to_loc[bel.index]; - } + Loc getBelLocation(BelId bel) const { return torc_info->bel_to_loc[bel.index]; } BelId getBelByLocation(Loc loc) const; BelRange getBelsByTile(int x, int y) const; @@ -639,7 +655,7 @@ struct Arch : BaseCtx auto pip = it->second.pip; if (pip != PipId()) { pip_to_net[pip.index] = nullptr; - //switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; } net_wires.erase(it); @@ -665,17 +681,14 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } - DelayInfo getWireDelay(WireId wire) const - { - return torc_info->wire_to_delay[wire.index]; - } + DelayInfo getWireDelay(WireId wire) const { return torc_info->wire_to_delay[wire.index]; } BelPinRange getWireBelPins(WireId wire) const { BelPinRange range; - //NPNR_ASSERT(wire != WireId()); - //range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); - //range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; + // NPNR_ASSERT(wire != WireId()); + // range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); + // range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; throw; return range; } @@ -696,10 +709,10 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == nullptr); - //NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); + // NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); pip_to_net[pip.index] = net; - //switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + // switches_locked[chip_info->pip_data[pip.index].switch_index] = net; WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] == nullptr); @@ -714,7 +727,7 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != nullptr); - //NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); + // NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] != nullptr); @@ -722,7 +735,7 @@ struct Arch : BaseCtx pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index] = nullptr; - //switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; + // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; refreshUiPip(pip); refreshUiWire(dst); } @@ -730,25 +743,25 @@ struct Arch : BaseCtx bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - //auto &pi = chip_info->pip_data[pip.index]; - //auto &si = chip_info->bits_info->switches[pi.switch_index]; + // auto &pi = chip_info->pip_data[pip.index]; + // auto &si = chip_info->bits_info->switches[pi.switch_index]; - //if (switches_locked[pi.switch_index] != nullptr) + // if (switches_locked[pi.switch_index] != nullptr) // return false; - //if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { + // if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { // NPNR_ASSERT(si.bel >= 0); // if (bel_to_cell[si.bel] != nullptr) // return false; //} - //if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { + // if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { // NPNR_ASSERT(si.bel >= 0); // if (bel_carry[si.bel]) // return false; //} - //return true; + // return true; return pip_to_net[pip.index] == nullptr; } @@ -761,7 +774,7 @@ struct Arch : BaseCtx NetInfo *getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - //return switches_locked[chip_info->pip_data[pip.index].switch_index]; + // return switches_locked[chip_info->pip_data[pip.index].switch_index]; return pip_to_net[pip.index]; } @@ -780,7 +793,7 @@ struct Arch : BaseCtx const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex()); Loc loc; - loc.x = tile_info.getCol(); + loc.x = tile_info.getCol(); loc.y = tile_info.getRow(); loc.z = 0; return loc; @@ -816,9 +829,9 @@ struct Arch : BaseCtx { DelayInfo delay; NPNR_ASSERT(pip != PipId()); - //if (fast_part) + // if (fast_part) // delay.delay = chip_info->pip_data[pip.index].fast_delay; - //else + // else // delay.delay = chip_info->pip_data[pip.index].slow_delay; return delay; } @@ -915,7 +928,7 @@ struct Arch : BaseCtx bool isBelLocationValid(BelId bel) const; // Helper function for above - bool logicCellsCompatible(const CellInfo** it, const size_t size) const; + bool logicCellsCompatible(const CellInfo **it, const size_t size) const; // ------------------------------------------------- // Assign architecure-specific arguments to nets and cells, which must be @@ -939,6 +952,6 @@ struct Arch : BaseCtx float placer_constraintWeight = 10; }; -//void ice40DelayFuzzerMain(Context *ctx); +// void ice40DelayFuzzerMain(Context *ctx); NEXTPNR_NAMESPACE_END diff --git a/xc7/arch_place.cc b/xc7/arch_place.cc index 463e8312..fd09006e 100644 --- a/xc7/arch_place.cc +++ b/xc7/arch_place.cc @@ -27,38 +27,38 @@ NEXTPNR_NAMESPACE_BEGIN -bool Arch::logicCellsCompatible(const CellInfo** it, const size_t size) const +bool Arch::logicCellsCompatible(const CellInfo **it, const size_t size) const { -// bool dffs_exist = false, dffs_neg = false; -// const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; -// -// for (auto cell : boost::make_iterator_range(it, it+size)) { -// NPNR_ASSERT(cell->belType == id_ICESTORM_LC); -// if (cell->lcInfo.dffEnable) { -// if (!dffs_exist) { -// dffs_exist = true; -// cen = cell->lcInfo.cen; -// clk = cell->lcInfo.clk; -// sr = cell->lcInfo.sr; -// -// if (cell->lcInfo.negClk) { -// dffs_neg = true; -// } -// } else { -// if (cen != cell->lcInfo.cen) -// return false; -// if (clk != cell->lcInfo.clk) -// return false; -// if (sr != cell->lcInfo.sr) -// return false; -// if (dffs_neg != cell->lcInfo.negClk) -// return false; -// } -// } -// locals_count += cell->lcInfo.inputCount; -// } -// -// return locals_count <= 32; + // bool dffs_exist = false, dffs_neg = false; + // const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; + // + // for (auto cell : boost::make_iterator_range(it, it+size)) { + // NPNR_ASSERT(cell->belType == id_ICESTORM_LC); + // if (cell->lcInfo.dffEnable) { + // if (!dffs_exist) { + // dffs_exist = true; + // cen = cell->lcInfo.cen; + // clk = cell->lcInfo.clk; + // sr = cell->lcInfo.sr; + // + // if (cell->lcInfo.negClk) { + // dffs_neg = true; + // } + // } else { + // if (cen != cell->lcInfo.cen) + // return false; + // if (clk != cell->lcInfo.clk) + // return false; + // if (sr != cell->lcInfo.sr) + // return false; + // if (dffs_neg != cell->lcInfo.negClk) + // return false; + // } + // } + // locals_count += cell->lcInfo.inputCount; + // } + // + // return locals_count <= 32; return true; } @@ -85,70 +85,70 @@ bool Arch::isBelLocationValid(BelId bel) const bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { -// if (cell->type == id_ICESTORM_LC) { -// NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); -// -// std::array bel_cells; -// size_t num_cells = 0; -// -// Loc bel_loc = getBelLocation(bel); -// for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { -// CellInfo *ci_other = getBoundBelCell(bel_other); -// if (ci_other != nullptr && bel_other != bel) -// bel_cells[num_cells++] = ci_other; -// } -// -// bel_cells[num_cells++] = cell; -// return logicCellsCompatible(bel_cells.data(), num_cells); -// } else if (cell->type == id_SB_IO) { -// // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. -// -// // Find shared PLL by looking for driving bel siblings from D_IN_0 -// // that are a PLL clock output. -// auto wire = getBelPinWire(bel, id_D_IN_0); -// IdString pll_bel_pin; -// BelId pll_bel; -// for (auto pin : getWireBelPins(wire)) { -// if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { -// pll_bel = pin.bel; -// pll_bel_pin = pin.pin; -// break; -// } -// } -// // Is there a PLL that shares this IO buffer? -// if (pll_bel.index != -1) { -// auto pll_cell = getBoundBelCell(pll_bel); -// // Is a PLL placed in this PLL bel? -// if (pll_cell != nullptr) { -// // Is the shared port driving a net? -// auto pi = pll_cell->ports[pll_bel_pin]; -// if (pi.net != nullptr) { -// // Are we perhaps a PAD INPUT Bel that can be placed here? -// if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { -// return true; -// } -// return false; -// } -// } -// } -// return getBelPackagePin(bel) != ""; -// } else if (cell->type == id_SB_GB) { -// NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); -// const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; -// IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); -// int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); -// if (net->is_reset && net->is_enable) -// return false; -// else if (net->is_reset) -// return (glb_id % 2) == 0; -// else if (net->is_enable) -// return (glb_id % 2) == 1; -// else -// return true; -// } else { -// // TODO: IO cell clock checks - return true; -// } + // if (cell->type == id_ICESTORM_LC) { + // NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); + // + // std::array bel_cells; + // size_t num_cells = 0; + // + // Loc bel_loc = getBelLocation(bel); + // for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { + // CellInfo *ci_other = getBoundBelCell(bel_other); + // if (ci_other != nullptr && bel_other != bel) + // bel_cells[num_cells++] = ci_other; + // } + // + // bel_cells[num_cells++] = cell; + // return logicCellsCompatible(bel_cells.data(), num_cells); + // } else if (cell->type == id_SB_IO) { + // // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. + // + // // Find shared PLL by looking for driving bel siblings from D_IN_0 + // // that are a PLL clock output. + // auto wire = getBelPinWire(bel, id_D_IN_0); + // IdString pll_bel_pin; + // BelId pll_bel; + // for (auto pin : getWireBelPins(wire)) { + // if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { + // pll_bel = pin.bel; + // pll_bel_pin = pin.pin; + // break; + // } + // } + // // Is there a PLL that shares this IO buffer? + // if (pll_bel.index != -1) { + // auto pll_cell = getBoundBelCell(pll_bel); + // // Is a PLL placed in this PLL bel? + // if (pll_cell != nullptr) { + // // Is the shared port driving a net? + // auto pi = pll_cell->ports[pll_bel_pin]; + // if (pi.net != nullptr) { + // // Are we perhaps a PAD INPUT Bel that can be placed here? + // if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { + // return true; + // } + // return false; + // } + // } + // } + // return getBelPackagePin(bel) != ""; + // } else if (cell->type == id_SB_GB) { + // NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); + // const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; + // IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); + // int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); + // if (net->is_reset && net->is_enable) + // return false; + // else if (net->is_reset) + // return (glb_id % 2) == 0; + // else if (net->is_enable) + // return (glb_id % 2) == 1; + // else + // return true; + // } else { + // // TODO: IO cell clock checks + return true; + // } } NEXTPNR_NAMESPACE_END diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 141dfcc8..98bd5071 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -1,6 +1,6 @@ -set_io led1 99 -set_io led2 98 -set_io led3 97 -set_io led4 96 -set_io led5 95 -set_io clki 21 +COMP "led1" LOCATE = SITE "M14" LEVEL 1; +COMP "led2" LOCATE = SITE "M15" LEVEL 1; +COMP "led3" LOCATE = SITE "G14" LEVEL 1; +COMP "led4" LOCATE = SITE "D18" LEVEL 1; +COMP "clki" LOCATE = SITE "L16" LEVEL 1; + diff --git a/xc7/cells.cc b/xc7/cells.cc index 01109b96..e1588516 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -76,180 +76,180 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; -// add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); -// -// add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); -// add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); -// add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); -// add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); -// -// add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); -// add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); -// add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); -// -// add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); -// add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); + // add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); + // + // add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); + // add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); + // add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); + // add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); + // + // add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); + // add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); + // add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); + // + // add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); + // add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); add_port(ctx, new_cell.get(), "I", PORT_OUT); add_port(ctx, new_cell.get(), "O", PORT_IN); -// } else if (type == ctx->id("ICESTORM_RAM")) { -// new_cell->params[ctx->id("NEG_CLK_W")] = "0"; -// new_cell->params[ctx->id("NEG_CLK_R")] = "0"; -// new_cell->params[ctx->id("WRITE_MODE")] = "0"; -// new_cell->params[ctx->id("READ_MODE")] = "0"; -// -// add_port(ctx, new_cell.get(), "RCLK", PORT_IN); -// add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); -// add_port(ctx, new_cell.get(), "RE", PORT_IN); -// -// add_port(ctx, new_cell.get(), "WCLK", PORT_IN); -// add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); -// add_port(ctx, new_cell.get(), "WE", PORT_IN); -// -// for (int i = 0; i < 16; i++) { -// add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); -// } -// -// for (int i = 0; i < 11; i++) { -// add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); -// } -// } else if (type == ctx->id("ICESTORM_LFOSC")) { -// add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); -// add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); -// add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); -// add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); -// } else if (type == ctx->id("ICESTORM_HFOSC")) { -// new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; -// new_cell->params[ctx->id("TRIM_EN")] = "0b0"; -// -// add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); -// add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); -// add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); -// add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); -// for (int i = 0; i < 10; i++) -// add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); + // } else if (type == ctx->id("ICESTORM_RAM")) { + // new_cell->params[ctx->id("NEG_CLK_W")] = "0"; + // new_cell->params[ctx->id("NEG_CLK_R")] = "0"; + // new_cell->params[ctx->id("WRITE_MODE")] = "0"; + // new_cell->params[ctx->id("READ_MODE")] = "0"; + // + // add_port(ctx, new_cell.get(), "RCLK", PORT_IN); + // add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); + // add_port(ctx, new_cell.get(), "RE", PORT_IN); + // + // add_port(ctx, new_cell.get(), "WCLK", PORT_IN); + // add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); + // add_port(ctx, new_cell.get(), "WE", PORT_IN); + // + // for (int i = 0; i < 16; i++) { + // add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); + // } + // + // for (int i = 0; i < 11; i++) { + // add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); + // } + // } else if (type == ctx->id("ICESTORM_LFOSC")) { + // add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); + // add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); + // add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); + // add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); + // } else if (type == ctx->id("ICESTORM_HFOSC")) { + // new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; + // new_cell->params[ctx->id("TRIM_EN")] = "0b0"; + // + // add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); + // add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); + // add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); + // add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); + // for (int i = 0; i < 10; i++) + // add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); } else if (type == id_BUFGCTRL) { add_port(ctx, new_cell.get(), "I0", PORT_IN); add_port(ctx, new_cell.get(), "O", PORT_OUT); -// } else if (type == ctx->id("ICESTORM_SPRAM")) { -// add_port(ctx, new_cell.get(), "WREN", PORT_IN); -// add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); -// add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); -// add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); -// add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); -// add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); -// -// for (int i = 0; i < 16; i++) { -// add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); -// } -// for (int i = 0; i < 14; i++) { -// add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); -// } -// for (int i = 0; i < 4; i++) { -// add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); -// } -// } else if (type == ctx->id("ICESTORM_DSP")) { -// new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; -// -// new_cell->params[ctx->id("C_REG")] = "0"; -// new_cell->params[ctx->id("A_REG")] = "0"; -// new_cell->params[ctx->id("B_REG")] = "0"; -// new_cell->params[ctx->id("D_REG")] = "0"; -// new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; -// new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; -// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; -// new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; -// -// new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; -// new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; -// new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; -// new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; -// -// new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; -// new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; -// new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; -// new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; -// -// new_cell->params[ctx->id("MODE_8x8")] = "0"; -// new_cell->params[ctx->id("A_SIGNED")] = "0"; -// new_cell->params[ctx->id("B_SIGNED")] = "0"; -// -// add_port(ctx, new_cell.get(), "CLK", PORT_IN); -// add_port(ctx, new_cell.get(), "CE", PORT_IN); -// for (int i = 0; i < 16; i++) { -// add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); -// add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); -// } -// add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); -// add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); -// add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); -// add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); -// -// add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); -// add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); -// add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); -// add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); -// -// add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); -// add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); -// -// add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); -// add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); -// -// add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); -// add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); -// -// add_port(ctx, new_cell.get(), "CI", PORT_IN); -// add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); -// add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); -// -// for (int i = 0; i < 32; i++) { -// add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); -// } -// -// add_port(ctx, new_cell.get(), "CO", PORT_OUT); -// add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); -// add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); -// -// } else if (type == ctx->id("ICESTORM_PLL")) { -// new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; -// new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; -// -// new_cell->params[ctx->id("DIVF")] = "0"; -// new_cell->params[ctx->id("DIVQ")] = "0"; -// new_cell->params[ctx->id("DIVR")] = "0"; -// -// new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; -// new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; -// new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; -// new_cell->params[ctx->id("FILTER_RANGE")] = "0"; -// -// new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; -// new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; -// -// new_cell->params[ctx->id("PLLTYPE")] = "0"; -// new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; -// new_cell->params[ctx->id("TEST_MODE")] = "0"; -// -// add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); -// add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); -// add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); -// add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); -// add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); -// add_port(ctx, new_cell.get(), "RESETB", PORT_IN); -// -// add_port(ctx, new_cell.get(), "SCLK", PORT_IN); -// add_port(ctx, new_cell.get(), "SDI", PORT_IN); -// add_port(ctx, new_cell.get(), "SDI", PORT_OUT); -// -// add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); -// add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); -// add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); + // } else if (type == ctx->id("ICESTORM_SPRAM")) { + // add_port(ctx, new_cell.get(), "WREN", PORT_IN); + // add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); + // add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); + // add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); + // add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); + // add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); + // + // for (int i = 0; i < 16; i++) { + // add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); + // } + // for (int i = 0; i < 14; i++) { + // add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); + // } + // for (int i = 0; i < 4; i++) { + // add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); + // } + // } else if (type == ctx->id("ICESTORM_DSP")) { + // new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + // + // new_cell->params[ctx->id("C_REG")] = "0"; + // new_cell->params[ctx->id("A_REG")] = "0"; + // new_cell->params[ctx->id("B_REG")] = "0"; + // new_cell->params[ctx->id("D_REG")] = "0"; + // new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; + // new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; + // new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; + // new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; + // + // new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; + // new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; + // new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; + // new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; + // + // new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; + // new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; + // new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; + // new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; + // + // new_cell->params[ctx->id("MODE_8x8")] = "0"; + // new_cell->params[ctx->id("A_SIGNED")] = "0"; + // new_cell->params[ctx->id("B_SIGNED")] = "0"; + // + // add_port(ctx, new_cell.get(), "CLK", PORT_IN); + // add_port(ctx, new_cell.get(), "CE", PORT_IN); + // for (int i = 0; i < 16; i++) { + // add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); + // add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); + // } + // add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); + // add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); + // add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); + // add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); + // + // add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); + // add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); + // add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); + // add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); + // + // add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); + // add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); + // + // add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); + // add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); + // + // add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); + // add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); + // + // add_port(ctx, new_cell.get(), "CI", PORT_IN); + // add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); + // add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); + // + // for (int i = 0; i < 32; i++) { + // add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); + // } + // + // add_port(ctx, new_cell.get(), "CO", PORT_OUT); + // add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); + // add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); + // + // } else if (type == ctx->id("ICESTORM_PLL")) { + // new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; + // new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; + // + // new_cell->params[ctx->id("DIVF")] = "0"; + // new_cell->params[ctx->id("DIVQ")] = "0"; + // new_cell->params[ctx->id("DIVR")] = "0"; + // + // new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; + // new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; + // new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; + // new_cell->params[ctx->id("FILTER_RANGE")] = "0"; + // + // new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; + // new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; + // + // new_cell->params[ctx->id("PLLTYPE")] = "0"; + // new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; + // new_cell->params[ctx->id("TEST_MODE")] = "0"; + // + // add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); + // add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); + // add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); + // add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); + // add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); + // add_port(ctx, new_cell.get(), "RESETB", PORT_IN); + // + // add_port(ctx, new_cell.get(), "SCLK", PORT_IN); + // add_port(ctx, new_cell.get(), "SDI", PORT_IN); + // add_port(ctx, new_cell.get(), "SDI", PORT_OUT); + // + // add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); + // add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); + // add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); } else { log_error("unable to create XC7 cell of type %s\n", type.c_str(ctx)); } diff --git a/xc7/cells.h b/xc7/cells.h index de323b36..c5956eb8 100644 --- a/xc7/cells.h +++ b/xc7/cells.h @@ -30,7 +30,11 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::string name = ""); // Return true if a cell is a LUT -inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_LUT1 || cell->type == id_LUT2 || cell->type == id_LUT3 || cell->type == id_LUT4 || cell->type == id_LUT5 || cell->type == id_LUT6; } +inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) +{ + return cell->type == id_LUT1 || cell->type == id_LUT2 || cell->type == id_LUT3 || cell->type == id_LUT4 || + cell->type == id_LUT5 || cell->type == id_LUT6; +} // Return true if a cell is a flipflop inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell) diff --git a/xc7/chains.cc b/xc7/chains.cc index 407b72ff..be1d6762 100644 --- a/xc7/chains.cc +++ b/xc7/chains.cc @@ -97,7 +97,8 @@ class ChainConstrainer } tile.push_back(cell); chains.back().cells.push_back(cell); - bool split_chain = (!ctx->logicCellsCompatible(tile.data(), tile.size())) || (int(chains.back().cells.size()) > max_length); + bool split_chain = (!ctx->logicCellsCompatible(tile.data(), tile.size())) || + (int(chains.back().cells.size()) > max_length); if (split_chain) { CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); tile.pop_back(); diff --git a/xc7/delay.cc b/xc7/delay.cc index 0c420694..fe14a5ce 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -27,75 +27,75 @@ NEXTPNR_NAMESPACE_BEGIN void ice40DelayFuzzerMain(Context *ctx) { -// std::vector srcWires, dstWires; -// -// for (int i = 0; i < ctx->chip_info->num_wires; i++) { -// WireId wire; -// wire.index = i; -// -// switch (ctx->chip_info->wire_data[i].type) { -// case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: -// srcWires.push_back(wire); -// break; -// -// case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: -// dstWires.push_back(wire); -// break; -// -// default: -// break; -// } -// } -// -// ctx->shuffle(srcWires); -// ctx->shuffle(dstWires); -// -// int index = 0; -// int cnt = 0; -// -// while (cnt < NUM_FUZZ_ROUTES) { -// if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { -// index = 0; -// ctx->shuffle(srcWires); -// ctx->shuffle(dstWires); -// } -// -// WireId src = srcWires[index]; -// WireId dst = dstWires[index++]; -// std::unordered_map route; -// -//#if NUM_FUZZ_ROUTES <= 1000 -// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) -// continue; -//#else -// if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) -// continue; -//#endif -// -// WireId cursor = dst; -// delay_t delay = 0; -// -// while (1) { -// delay += ctx->getWireDelay(cursor).maxDelay(); -// -// printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", -// int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), -// ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), -// int(ctx->estimateDelay(cursor, dst))); -// -// if (cursor == src) -// break; -// -// PipId pip = route.at(cursor); -// delay += ctx->getPipDelay(pip).maxDelay(); -// cursor = ctx->getPipSrcWire(pip); -// } -// -// cnt++; -// -// if (cnt % 100 == 0) -// fprintf(stderr, "Fuzzed %d arcs.\n", cnt); -// } + // std::vector srcWires, dstWires; + // + // for (int i = 0; i < ctx->chip_info->num_wires; i++) { + // WireId wire; + // wire.index = i; + // + // switch (ctx->chip_info->wire_data[i].type) { + // case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: + // srcWires.push_back(wire); + // break; + // + // case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: + // dstWires.push_back(wire); + // break; + // + // default: + // break; + // } + // } + // + // ctx->shuffle(srcWires); + // ctx->shuffle(dstWires); + // + // int index = 0; + // int cnt = 0; + // + // while (cnt < NUM_FUZZ_ROUTES) { + // if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { + // index = 0; + // ctx->shuffle(srcWires); + // ctx->shuffle(dstWires); + // } + // + // WireId src = srcWires[index]; + // WireId dst = dstWires[index++]; + // std::unordered_map route; + // + //#if NUM_FUZZ_ROUTES <= 1000 + // if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) + // continue; + //#else + // if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) + // continue; + //#endif + // + // WireId cursor = dst; + // delay_t delay = 0; + // + // while (1) { + // delay += ctx->getWireDelay(cursor).maxDelay(); + // + // printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", + // int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), + // ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), + // int(ctx->estimateDelay(cursor, dst))); + // + // if (cursor == src) + // break; + // + // PipId pip = route.at(cursor); + // delay += ctx->getPipDelay(pip).maxDelay(); + // cursor = ctx->getPipSrcWire(pip); + // } + // + // cnt++; + // + // if (cnt % 100 == 0) + // fprintf(stderr, "Fuzzed %d arcs.\n", cnt); + // } } delay_t Arch::estimateDelay(WireId src, WireId dst) const diff --git a/xc7/main.cc b/xc7/main.cc index c24ce488..65fabff4 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -52,18 +52,18 @@ po::options_description Xc7CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); specific.add_options()("xc7z020", "set device type to xc7z020"); -// specific.add_options()("package", po::value(), "set device package"); + // specific.add_options()("package", po::value(), "set device package"); specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); -// specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); + // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); return specific; } void Xc7CommandHandler::validate() { conflicting_options(vm, "read", "json"); -// if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + -// vm.count("up5k")) > 1) -// log_error("Only one device type can be set\n"); + // if ((vm.count("lp384") + vm.count("lp1k") + vm.count("lp8k") + vm.count("hx1k") + vm.count("hx8k") + + // vm.count("up5k")) > 1) + // log_error("Only one device type can be set\n"); } void Xc7CommandHandler::customAfterLoad(Context *ctx) @@ -86,8 +86,8 @@ void Xc7CommandHandler::customBitstream(Context *ctx) void Xc7CommandHandler::setupArchContext(Context *ctx) { -// if (vm.count("tmfuzz")) -// ice40DelayFuzzerMain(ctx); + // if (vm.count("tmfuzz")) + // ice40DelayFuzzerMain(ctx); } std::unique_ptr Xc7CommandHandler::createContext() diff --git a/xc7/pack.cc b/xc7/pack.cc index 05404fdb..7d7eb34d 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -96,8 +96,7 @@ static void pack_nonlut_ffs(Context *ctx) for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_ff(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_DFFLC"); + std::unique_ptr packed = create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); if (ctx->verbose) log_info("packed cell %s into %s\n", ci->name.c_str(ctx), packed->name.c_str(ctx)); @@ -422,8 +421,7 @@ static void pack_io(Context *ctx) } } else { // Create a IOBUF buffer - std::unique_ptr ice_cell = - create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); + std::unique_ptr ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); nxio_to_sb(ctx, ci, ice_cell.get()); new_cells.push_back(std::move(ice_cell)); sb = new_cells.back().get(); @@ -582,8 +580,8 @@ static std::unique_ptr spliceLUT(Context *ctx, CellInfo *ci, IdString NPNR_ASSERT(port.net != nullptr); // Create pass-through LUT. - std::unique_ptr pt = create_xc7_cell(ctx, ctx->id("XC7_LC"), - ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); + std::unique_ptr pt = + create_xc7_cell(ctx, ctx->id("XC7_LC"), ci->name.str(ctx) + "$nextpnr_" + portId.str(ctx) + "_lut_through"); pt->params[ctx->id("INIT")] = "65280"; // output is always I3 // Create LUT output net. @@ -851,10 +849,10 @@ static void pack_special(Context *ctx) // Now, constrain all LUTs on the output of the signal to be at // the correct Bel relative to the PLL Bel. - //int x = ctx->chip_info->wire_data[pll_out_wire.index].x; - //int y = ctx->chip_info->wire_data[pll_out_wire.index].y; - //int z = 0; - //for (const auto &user : port.net->users) { + // int x = ctx->chip_info->wire_data[pll_out_wire.index].x; + // int y = ctx->chip_info->wire_data[pll_out_wire.index].y; + // int z = 0; + // for (const auto &user : port.net->users) { // NPNR_ASSERT(user.cell != nullptr); // NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC")); @@ -888,7 +886,7 @@ bool Arch::pack() log_break(); pack_constants(ctx); // TODO - //promote_globals(ctx); + // promote_globals(ctx); pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); diff --git a/xc7/pcf.cc b/xc7/pcf.cc index d9fc4e68..7327b252 100644 --- a/xc7/pcf.cc +++ b/xc7/pcf.cc @@ -22,6 +22,8 @@ #include #include "log.h" +#include + NEXTPNR_NAMESPACE_BEGIN // Read a w @@ -45,12 +47,14 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) if (words.size() == 0) continue; std::string cmd = words.at(0); - if (cmd == "set_io") { + if (cmd == "COMP") { 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); + boost::trim_if(cell, boost::is_any_of("\"")); + std::string pin = words.at(args_end + 4); + boost::trim_if(pin, boost::is_any_of("\"")); auto fnd_cell = ctx->cells.find(ctx->id(cell)); if (fnd_cell == ctx->cells.end()) { log_warning("unmatched pcf constraint %s\n", cell.c_str()); diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 21a1ccf5..1bee3029 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -18,12 +18,12 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ -#include "nextpnr.h" #include "xdl.h" #include #include #include "cells.h" #include "log.h" +#include "nextpnr.h" #include "util.h" #include "torc/Physical.hpp" @@ -37,25 +37,41 @@ void write_xdl(const Context *ctx, std::ostream &out) XdlExporter exporter(out); auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), ctx->args.package, "-1", ""); - std::unordered_map site_to_instance; - std::vector> lut_inputs; + std::unordered_map site_to_instance; + std::vector> lut_inputs; lut_inputs.reserve(6); auto bel_to_lut = [](const BelId bel) { switch (torc_info->bel_to_loc[bel.index].z) { - case 0: case 4: return "A"; break; - case 1: case 5: return "B"; break; - case 2: case 6: return "C"; break; - case 3: case 7: return "D"; break; - default: throw; + case 0: + case 4: + return "A"; + break; + case 1: + case 5: + return "B"; + break; + case 2: + case 6: + return "C"; + break; + case 3: + case 7: + return "D"; + break; + default: + throw; } }; - for (const auto& cell : ctx->cells) { - const char* type; - if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL) type = cell.second->type.c_str(ctx); - else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); + for (const auto &cell : ctx->cells) { + const char *type; + if (cell.second->type == id_SLICE_LUT6) + type = "SLICEL"; + else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL) + type = cell.second->type.c_str(ctx); + else + log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); auto site_index = torc_info->bel_to_site_index[cell.second->bel.index]; auto ret = site_to_instance.emplace(site_index, nullptr); @@ -66,11 +82,10 @@ void write_xdl(const Context *ctx, std::ostream &out) assert(b); ret.first->second = instPtr; - const auto& tile_info = torc_info->bel_to_tile_info(cell.second->bel.index); + const auto &tile_info = torc_info->bel_to_tile_info(cell.second->bel.index); instPtr->setTile(tile_info.getName()); instPtr->setSite(torc_info->bel_to_name(cell.second->bel.index)); - } - else + } else instPtr = ret.first->second; if (cell.second->type == id_SLICE_LUT6) { @@ -80,13 +95,19 @@ void write_xdl(const Context *ctx, std::ostream &out) setting = lut + "6LUT"; value = "#LUT:O6="; lut_inputs.clear(); - if (get_net_or_empty(cell.second.get(), id_I1)) lut_inputs.emplace_back("A1", "~A1"); - if (get_net_or_empty(cell.second.get(), id_I2)) lut_inputs.emplace_back("A2", "~A2"); - if (get_net_or_empty(cell.second.get(), id_I3)) lut_inputs.emplace_back("A3", "~A3"); - if (get_net_or_empty(cell.second.get(), id_I4)) lut_inputs.emplace_back("A4", "~A4"); - if (get_net_or_empty(cell.second.get(), id_I5)) lut_inputs.emplace_back("A5", "~A5"); - if (get_net_or_empty(cell.second.get(), id_I6)) lut_inputs.emplace_back("A6", "~A6"); - const auto& init = cell.second->params[ctx->id("INIT")]; + if (get_net_or_empty(cell.second.get(), id_I1)) + lut_inputs.emplace_back("A1", "~A1"); + if (get_net_or_empty(cell.second.get(), id_I2)) + lut_inputs.emplace_back("A2", "~A2"); + if (get_net_or_empty(cell.second.get(), id_I3)) + lut_inputs.emplace_back("A3", "~A3"); + if (get_net_or_empty(cell.second.get(), id_I4)) + lut_inputs.emplace_back("A4", "~A4"); + if (get_net_or_empty(cell.second.get(), id_I5)) + lut_inputs.emplace_back("A5", "~A5"); + if (get_net_or_empty(cell.second.get(), id_I6)) + lut_inputs.emplace_back("A6", "~A6"); + const auto &init = cell.second->params[ctx->id("INIT")]; // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t if (lut_inputs.size() < 6) { auto init_as_uint = boost::lexical_cast(init); @@ -96,8 +117,10 @@ void write_xdl(const Context *ctx, std::ostream &out) else { unsigned n = 0; for (unsigned o = 0; o < (1u << lut_inputs.size()); ++o) { - if ((init_as_uint >> o) & 0x1) continue; - if (n++ > 0) value += "+"; + if ((init_as_uint >> o) & 0x1) + continue; + if (n++ > 0) + value += "+"; value += "("; value += (o & 1) ? lut_inputs[0].first : lut_inputs[0].second; for (unsigned i = 1; i < lut_inputs.size(); ++i) { @@ -113,8 +136,10 @@ void write_xdl(const Context *ctx, std::ostream &out) NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); unsigned n = 0; for (unsigned i = 0; i < (1u << lut_inputs.size()); ++i) { - if (init[i] == '0') continue; - if (n++ > 0) value += "+"; + if (init[i] == '0') + continue; + if (n++ > 0) + value += "+"; value += "("; value += (i & 1) ? lut_inputs[0].first : lut_inputs[0].second; for (unsigned j = 1; j < lut_inputs.size(); ++j) { @@ -159,28 +184,25 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("CEUSEDMUX", "", "IN"); instPtr->setConfig("SYNC_ATTR", "", "ASYNC"); } - } - else if (cell.second->type == id_IOB33) { + } else if (cell.second->type == id_IOB33) { if (get_net_or_empty(cell.second.get(), id_I)) { instPtr->setConfig("IUSED", "", "0"); instPtr->setConfig("IBUF_LOW_PWR", "", "TRUE"); instPtr->setConfig("ISTANDARD", "", "LVCMOS33"); - } - else { + } else { instPtr->setConfig("OUSED", "", "0"); instPtr->setConfig("OSTANDARD", "", "LVCMOS33"); instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } - } - else if (cell.second->type == id_BUFGCTRL) { + } else if (cell.second->type == id_BUFGCTRL) { auto it = cell.second->params.find(ctx->id("PRESELECT_I0")); instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "TRUE"); instPtr->setConfig("CE0INV", "", "CE0_B"); instPtr->setConfig("S0INV", "", "S0_B"); - } - else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); + } else + log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } for (const auto &net : ctx->nets) { @@ -217,18 +239,19 @@ void write_xdl(const Context *ctx, std::ostream &out) auto b = designPtr->addNet(netPtr); assert(b); - for (const auto& i : net.second->wires) { - const auto& pip_map = i.second; - if (pip_map.pip == PipId()) continue; + for (const auto &i : net.second->wires) { + const auto &pip_map = i.second; + if (pip_map.pip == PipId()) + continue; ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSourceTilewire()); ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSinkTilewire()); - auto p = Factory::newPip(ewi_src.mTileName, ewi_src.mWireName, ewi_dst.mWireName, ePipUnidirectionalBuffered); + auto p = Factory::newPip(ewi_src.mTileName, ewi_src.mWireName, ewi_dst.mWireName, + ePipUnidirectionalBuffered); netPtr->addPip(p); } } exporter(designPtr); - } NEXTPNR_NAMESPACE_END From 5c56fab0abe05f78f2f2b7fd4c2c2b2dfe9f4f1a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 15:56:06 -0700 Subject: [PATCH 070/174] [xc7] Add torc_info->site_index_to_bel lookup; also fix Arch::getBelByName() --- xc7/arch.cc | 32 ++++++++++++++++++-------------- xc7/arch.h | 2 ++ 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 18f5b64e..65c8bee1 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -36,7 +36,9 @@ std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), - num_bels(bel_to_site_index.size()), site_index_to_type(construct_site_index_to_type(ctx, sites)), + num_bels(bel_to_site_index.size()), + site_index_to_bel(construct_site_index_to_bel(ctx, sites, bel_to_site_index)), + site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)), @@ -68,6 +70,18 @@ std::vector TorcInfo::construct_bel_to_site_index(Arch *ctx, const Si } return bel_to_site_index; } +std::vector TorcInfo::construct_site_index_to_bel(Arch *ctx, const Sites &sites, const std::vector &bel_to_site_index) +{ + std::vector site_index_to_bel; + site_index_to_bel.resize(sites.getSiteCount()); + BelId b; + b.index = 0; + for (auto i : bel_to_site_index) { + site_index_to_bel[i] = b; + ++b.index; + } + return site_index_to_bel; +} std::vector TorcInfo::construct_site_index_to_type(Arch *ctx, const Sites &sites) { std::vector site_index_to_type; @@ -344,13 +358,10 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { - BelId ret; - auto it = torc_info->sites.findSiteIndex(name.str(this)); if (it != SiteIndex(-1)) - ret.index = it; - - return ret; + return torc_info->site_index_to_bel.at(it); + return BelId(); } BelId Arch::getBelByLocation(Loc loc) const @@ -602,14 +613,7 @@ IdString Arch::getPipName(PipId pip) const BelId Arch::getPackagePinBel(const std::string &pin) const { - // for (int i = 0; i < package_info->num_pins; i++) { - // if (package_info->pins[i].name.get() == pin) { - // BelId id; - // id.index = package_info->pins[i].bel_index; - // return id; - // } - // } - return BelId(); + return getBelByName(id(pin)); } std::string Arch::getBelPackagePin(BelId bel) const diff --git a/xc7/arch.h b/xc7/arch.h index b5721552..9d8c4251 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -307,6 +307,7 @@ struct TorcInfo const std::vector bel_to_site_index; const int num_bels; + const std::vector site_index_to_bel; const std::vector site_index_to_type; const std::vector bel_to_loc; std::unordered_map segment_to_wire; @@ -322,6 +323,7 @@ struct TorcInfo private: static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); + static std::vector construct_site_index_to_bel(Arch *ctx, const Sites &sites, const std::vector &bel_to_site_index); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type); From 1e41183c5ef9011e99618ee5c04a96ab7e86d689 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 16:11:56 -0700 Subject: [PATCH 071/174] Update .gitignore with *_fpga_editor.log --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 643416f4..714657aa 100644 --- a/.gitignore +++ b/.gitignore @@ -44,3 +44,4 @@ _xmsgs/ usage_statistics_webtalk.html webtalk.log xilinx_device_details.xml +*_fpga_editor.log From e137a9c5072f0f02a99bc68a46f6ca854da9783c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 3 Nov 2018 16:12:11 -0700 Subject: [PATCH 072/174] [xc7] Add xdl and bitgen to blinky.sh --- xc7/blinky.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index eeff875f..d28fb77f 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -2,6 +2,8 @@ set -ex yosys blinky.ys ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl +xdl -xdl2ncd blinky.xdl +bitgen -w blinky.ncd -g UnconstrainedPins:Allow #icepack blinky.asc blinky.bin #icebox_vlog blinky.asc > blinky_chip.v #iverilog -o blinky_tb blinky_chip.v blinky_tb.v From 42a1b1a750783b25548d2805e4b13bacff532de8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 4 Nov 2018 22:12:43 -0800 Subject: [PATCH 073/174] [xc7] Add NET PERIOD constraint to blinky.pcf (for trce) --- xc7/blinky.pcf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 98bd5071..7208a89d 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -1,6 +1,6 @@ -COMP "led1" LOCATE = SITE "M14" LEVEL 1; -COMP "led2" LOCATE = SITE "M15" LEVEL 1; -COMP "led3" LOCATE = SITE "G14" LEVEL 1; -COMP "led4" LOCATE = SITE "D18" LEVEL 1; -COMP "clki" LOCATE = SITE "L16" LEVEL 1; - +COMP "led0" LOCATE = SITE "M14" LEVEL 1; +COMP "led1" LOCATE = SITE "M15" LEVEL 1; +COMP "led2" LOCATE = SITE "G14" LEVEL 1; +COMP "led3" LOCATE = SITE "D18" LEVEL 1; +COMP "clki" LOCATE = SITE "K17" LEVEL 1; +NET "clki" PERIOD = 8 nS ; From f1b454b96ccc6a8799aedd15c1aa67fedf9dff76 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 4 Nov 2018 22:13:24 -0800 Subject: [PATCH 074/174] [xc7] blinky.v to use led0-3, and just to be safe, set BUFGCTRL control inputs too --- xc7/blinky.v | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/xc7/blinky.v b/xc7/blinky.v index 179cb58c..7b5aae53 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -1,15 +1,19 @@ module blinky ( input clki, + output led0, output led1, output led2, - output led3, - output led4, + output led3 ); BUFGCTRL clk_gb ( .I0(clki), .CE0(1'b1), + .CE1(1'b0), .S0(1'b1), + .S1(1'b0), + .IGNORE0(1'b0), + .IGNORE1(1'b0), .O(clk) ); @@ -24,5 +28,5 @@ module blinky ( outcnt <= counter >> LOG2DELAY; end - assign {led1, led2, led3, led4} = outcnt ^ (outcnt >> 1); + assign {led0, led1, led2, led3} = outcnt ^ (outcnt >> 1); endmodule From 61939dca1107723074df3f86a59bf2cccb17b17c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 4 Nov 2018 22:13:51 -0800 Subject: [PATCH 075/174] [xc7] blinky.sh to set freq 125 MHz and run trce --- xc7/blinky.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index d28fb77f..9a247c62 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,8 +1,9 @@ #!/bin/bash set -ex yosys blinky.ys -../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 250 xdl -xdl2ncd blinky.xdl +trce blinky.ncd -v 10 bitgen -w blinky.ncd -g UnconstrainedPins:Allow #icepack blinky.asc blinky.bin #icebox_vlog blinky.asc > blinky_chip.v From f67cf32d0d389d262204939d74c722811ecee0d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 4 Nov 2018 22:14:10 -0800 Subject: [PATCH 076/174] [xc7] PCF reader to ignore lines with NET token --- xc7/pcf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xc7/pcf.cc b/xc7/pcf.cc index 7327b252..f82a21ab 100644 --- a/xc7/pcf.cc +++ b/xc7/pcf.cc @@ -66,6 +66,8 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) log_info("constrained '%s' to bel '%s'\n", cell.c_str(), fnd_cell->second->attrs[ctx->id("BEL")].c_str()); } + } else if (cmd == "NET") { + // TODO } else { log_error("unsupported pcf command '%s'\n", cmd.c_str()); } From 1ee041e63f2a9b576172b4d6d507eebfa608888e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 4 Nov 2018 22:15:06 -0800 Subject: [PATCH 077/174] Add more ISE stuff to .gitignore --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 714657aa..2510da04 100644 --- a/.gitignore +++ b/.gitignore @@ -44,4 +44,6 @@ _xmsgs/ usage_statistics_webtalk.html webtalk.log xilinx_device_details.xml -*_fpga_editor.log +*_fpga_editor.* +*.twr +*.twx From e53f8364ec433039ca4721458d04777df3c3e1f3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 5 Nov 2018 08:21:14 -0800 Subject: [PATCH 078/174] [xc7] Also ignore PIN token lines for PCF --- xc7/pcf.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xc7/pcf.cc b/xc7/pcf.cc index f82a21ab..f56a177b 100644 --- a/xc7/pcf.cc +++ b/xc7/pcf.cc @@ -68,6 +68,8 @@ bool apply_pcf(Context *ctx, std::string filename, std::istream &in) } } else if (cmd == "NET") { // TODO + } else if (cmd == "PIN") { + // TODO } else { log_error("unsupported pcf command '%s'\n", cmd.c_str()); } From a5be1bbe6ea74d17a25db855462a368ed15498a1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Mon, 5 Nov 2018 08:21:32 -0800 Subject: [PATCH 079/174] [xc7] Fix LUT mask logic; also add attributes for IGNORE0 and {CE,S,IGNORE}1 --- xc7/xdl.cc | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 1bee3029..a83297d8 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -117,7 +117,7 @@ void write_xdl(const Context *ctx, std::ostream &out) else { unsigned n = 0; for (unsigned o = 0; o < (1u << lut_inputs.size()); ++o) { - if ((init_as_uint >> o) & 0x1) + if (!((init_as_uint >> o) & 1)) continue; if (n++ > 0) value += "+"; @@ -135,8 +135,8 @@ void write_xdl(const Context *ctx, std::ostream &out) else { NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); unsigned n = 0; - for (unsigned i = 0; i < (1u << lut_inputs.size()); ++i) { - if (init[i] == '0') + for (unsigned i = 0; i < init.size(); ++i) { + if (init[init.size()-1-i] == '0') continue; if (n++ > 0) value += "+"; @@ -197,10 +197,14 @@ void write_xdl(const Context *ctx, std::ostream &out) } } else if (cell.second->type == id_BUFGCTRL) { auto it = cell.second->params.find(ctx->id("PRESELECT_I0")); - instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "TRUE"); + instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "FALSE"); - instPtr->setConfig("CE0INV", "", "CE0_B"); - instPtr->setConfig("S0INV", "", "S0_B"); + instPtr->setConfig("CE0INV", "", "CE0"); + instPtr->setConfig("S0INV", "", "S0"); + instPtr->setConfig("IGNORE0INV", "", "IGNORE0"); + instPtr->setConfig("CE1INV", "", "CE1"); + instPtr->setConfig("S1INV", "", "S1"); + instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From c6f66b4468d1b5f5762deae3e74e062f98f6fc18 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Nov 2018 17:05:55 -0800 Subject: [PATCH 080/174] Adapt blinky for xc7 --- xc7/blinky.pcf | 2 ++ xc7/blinky.sh | 9 ++++----- xc7/blinky_tb.v | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 7208a89d..1afc0f32 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -4,3 +4,5 @@ COMP "led2" LOCATE = SITE "G14" LEVEL 1; COMP "led3" LOCATE = SITE "D18" LEVEL 1; COMP "clki" LOCATE = SITE "K17" LEVEL 1; NET "clki" PERIOD = 8 nS ; +PIN "clki_pin" = BEL "clki$iob.PAD" PINNAME PAD; +PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/blinky.sh b/xc7/blinky.sh index 9a247c62..cccc6c24 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -3,9 +3,8 @@ set -ex yosys blinky.ys ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 250 xdl -xdl2ncd blinky.xdl -trce blinky.ncd -v 10 bitgen -w blinky.ncd -g UnconstrainedPins:Allow -#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 +trce blinky.ncd -v 10 +netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky +iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ -insert_glbl true +vvp -N ./blinky_tb diff --git a/xc7/blinky_tb.v b/xc7/blinky_tb.v index f80b5e64..0378b679 100644 --- a/xc7/blinky_tb.v +++ b/xc7/blinky_tb.v @@ -2,24 +2,24 @@ module blinky_tb; reg clk; always #5 clk = (clk === 1'b0); - wire led1, led2, led3, led4, led5; + wire led0, led1, led2, led3; chip uut ( - .io_0_8_1(clk), - .io_13_12_1(led1), - .io_13_12_0(led2), - .io_13_11_1(led3), - .io_13_11_0(led4), - .io_13_9_1(led5) + .\clki$iob.PAD.PAD (clk), + .\led0$iob.OUTBUF.OUT (led0), + .\led1$iob.OUTBUF.OUT (led1), + .\led2$iob.OUTBUF.OUT (led2), + .\led3$iob.OUTBUF.OUT (led3) ); initial begin // $dumpfile("blinky_tb.vcd"); // $dumpvars(0, blinky_tb); - repeat (10) begin - repeat (900000) @(posedge clk); - $display(led1, led2, led3, led4, led5); - end - $finish; + $monitor(led0, led1, led2, led3); + //repeat (10) begin + // repeat (900000) @(posedge clk); + // $display(led0, led1, led2, led3); + //end + //$finish; end endmodule From 31ae470414d9696547cef0d247daac44ac4422eb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Nov 2018 17:05:55 -0800 Subject: [PATCH 081/174] Adapt blinky for xc7 --- xc7/blinky.pcf | 2 ++ xc7/blinky.sh | 9 ++++----- xc7/blinky_tb.v | 24 ++++++++++++------------ 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 7208a89d..1afc0f32 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -4,3 +4,5 @@ COMP "led2" LOCATE = SITE "G14" LEVEL 1; COMP "led3" LOCATE = SITE "D18" LEVEL 1; COMP "clki" LOCATE = SITE "K17" LEVEL 1; NET "clki" PERIOD = 8 nS ; +PIN "clki_pin" = BEL "clki$iob.PAD" PINNAME PAD; +PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/blinky.sh b/xc7/blinky.sh index 9a247c62..cccc6c24 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -3,9 +3,8 @@ set -ex yosys blinky.ys ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 250 xdl -xdl2ncd blinky.xdl -trce blinky.ncd -v 10 bitgen -w blinky.ncd -g UnconstrainedPins:Allow -#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 +trce blinky.ncd -v 10 +netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky +iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ -insert_glbl true +vvp -N ./blinky_tb diff --git a/xc7/blinky_tb.v b/xc7/blinky_tb.v index f80b5e64..0378b679 100644 --- a/xc7/blinky_tb.v +++ b/xc7/blinky_tb.v @@ -2,24 +2,24 @@ module blinky_tb; reg clk; always #5 clk = (clk === 1'b0); - wire led1, led2, led3, led4, led5; + wire led0, led1, led2, led3; chip uut ( - .io_0_8_1(clk), - .io_13_12_1(led1), - .io_13_12_0(led2), - .io_13_11_1(led3), - .io_13_11_0(led4), - .io_13_9_1(led5) + .\clki$iob.PAD.PAD (clk), + .\led0$iob.OUTBUF.OUT (led0), + .\led1$iob.OUTBUF.OUT (led1), + .\led2$iob.OUTBUF.OUT (led2), + .\led3$iob.OUTBUF.OUT (led3) ); initial begin // $dumpfile("blinky_tb.vcd"); // $dumpvars(0, blinky_tb); - repeat (10) begin - repeat (900000) @(posedge clk); - $display(led1, led2, led3, led4, led5); - end - $finish; + $monitor(led0, led1, led2, led3); + //repeat (10) begin + // repeat (900000) @(posedge clk); + // $display(led0, led1, led2, led3); + //end + //$finish; end endmodule From 4619b2d82f1ee2e3e467672528d36186d53ee3d2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 9 Nov 2018 17:09:25 -0800 Subject: [PATCH 082/174] Disable debug/verbose flag before routing --- xc7/arch.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 65c8bee1..1dffcb9d 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -767,8 +767,6 @@ bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } bool Arch::route() { - getCtx()->debug = true; - getCtx()->verbose = true; return router1(getCtx(), Router1Cfg(getCtx())); } From 35765096849b7aacfde1bc69e68f12f525762ba2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 12:51:56 -0800 Subject: [PATCH 083/174] Add support for PS7 blocks --- xc7/arch.cc | 13 ++++++++++++- xc7/constids.inc | 2 ++ xc7/xdl.cc | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 65c8bee1..06b138ac 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -432,7 +432,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const WireId ret; auto pin_name = pin.str(this); - if (getBelType(bel) == id_SLICE_LUT6) { + auto bel_type = getBelType(bel); + if (bel_type == id_SLICE_LUT6) { // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { switch (torc_info->bel_to_loc[bel.index].z) { @@ -457,6 +458,12 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const } } } + else if (bel_type == id_PS7) { + // e.g. Convert DDRARB[0] -> DDRARB0 + boost::erase_all(pin_name, "["); + boost::erase_all(pin_name, "]"); + } + auto site_index = torc_info->bel_to_site_index[bel.index]; const auto &site = torc_info->sites.getSite(site_index); auto &tw = site.getPinTilewire(pin_name); @@ -996,6 +1003,10 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_COMB_OUTPUT; return TMG_COMB_INPUT; } + else if (cell->type == id_PS7) { + // TODO + return TMG_IGNORE; + } log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } diff --git a/xc7/constids.inc b/xc7/constids.inc index 0be998f6..bf0e7114 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -440,6 +440,7 @@ X(DFF_ENABLE) X(CARRY_ENABLE) X(NEG_CLK) +// XC7 X(I) X(LUT1) @@ -457,3 +458,4 @@ X(FDPE) X(BUFGCTRL) X(SLICE_LUT6) X(IOB33) +X(PS7) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index a83297d8..97a18538 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -68,7 +68,7 @@ void write_xdl(const Context *ctx, std::ostream &out) const char *type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL) + else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7) type = cell.second->type.c_str(ctx); else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -205,6 +205,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("CE1INV", "", "CE1"); instPtr->setConfig("S1INV", "", "S1"); instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); + } else if (cell.second->type == id_PS7) { } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From 3b86c3a3819657e84f8091a320fc07aafbeee84a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 12:52:52 -0800 Subject: [PATCH 084/174] blinky to instantiate PS7 so that reconfiguring from Linux doesn't kill PS --- xc7/blinky.v | 1 + xc7/ps7.vh | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 xc7/ps7.vh diff --git a/xc7/blinky.v b/xc7/blinky.v index 7b5aae53..cab84984 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -5,6 +5,7 @@ module blinky ( output led2, output led3 ); + `include "ps7.vh" BUFGCTRL clk_gb ( .I0(clki), diff --git a/xc7/ps7.vh b/xc7/ps7.vh new file mode 100644 index 00000000..445e67aa --- /dev/null +++ b/xc7/ps7.vh @@ -0,0 +1,328 @@ +(* keep *) +PS7 ps7_stub( + .DDRARB ('b0), + .DMA0ACLK ('b0), + .DMA0DAREADY ('b0), + .DMA0DRLAST ('b0), + .DMA0DRTYPE ('b0), + .DMA0DRVALID ('b0), + .DMA1ACLK ('b0), + .DMA1DAREADY ('b0), + .DMA1DRLAST ('b0), + .DMA1DRTYPE ('b0), + .DMA1DRVALID ('b0), + .DMA2ACLK ('b0), + .DMA2DAREADY ('b0), + .DMA2DRLAST ('b0), + .DMA2DRTYPE ('b0), + .DMA2DRVALID ('b0), + .DMA3ACLK ('b0), + .DMA3DAREADY ('b0), + .DMA3DRLAST ('b0), + .DMA3DRTYPE ('b0), + .DMA3DRVALID ('b0), + .EMIOCAN0PHYRX ('b0), + .EMIOCAN1PHYRX ('b0), + .EMIOENET0EXTINTIN ('b0), + .EMIOENET0GMIICOL ('b0), + .EMIOENET0GMIICRS ('b0), + .EMIOENET0GMIIRXCLK ('b0), + .EMIOENET0GMIIRXD ('b0), + .EMIOENET0GMIIRXDV ('b0), + .EMIOENET0GMIIRXER ('b0), + .EMIOENET0GMIITXCLK ('b0), + .EMIOENET0MDIOI ('b0), + .EMIOENET1EXTINTIN ('b0), + .EMIOENET1GMIICOL ('b0), + .EMIOENET1GMIICRS ('b0), + .EMIOENET1GMIIRXCLK ('b0), + .EMIOENET1GMIIRXD ('b0), + .EMIOENET1GMIIRXDV ('b0), + .EMIOENET1GMIIRXER ('b0), + .EMIOENET1GMIITXCLK ('b0), + .EMIOENET1MDIOI ('b0), + .EMIOGPIOI ('b0), + .EMIOI2C0SCLI ('b0), + .EMIOI2C0SDAI ('b0), + .EMIOI2C1SCLI ('b0), + .EMIOI2C1SDAI ('b0), + .EMIOPJTAGTCK ('b0), + .EMIOPJTAGTDI ('b0), + .EMIOPJTAGTMS ('b0), + .EMIOSDIO0CDN ('b0), + .EMIOSDIO0CLKFB ('b0), + .EMIOSDIO0CMDI ('b0), + .EMIOSDIO0DATAI ('b0), + .EMIOSDIO0WP ('b0), + .EMIOSDIO1CDN ('b0), + .EMIOSDIO1CLKFB ('b0), + .EMIOSDIO1CMDI ('b0), + .EMIOSDIO1DATAI ('b0), + .EMIOSDIO1WP ('b0), + .EMIOSPI0MI ('b0), + .EMIOSPI0SCLKI ('b0), + .EMIOSPI0SI ('b0), + .EMIOSPI0SSIN ('b0), + .EMIOSPI1MI ('b0), + .EMIOSPI1SCLKI ('b0), + .EMIOSPI1SI ('b0), + .EMIOSPI1SSIN ('b0), + .EMIOSRAMINTIN ('b0), + .EMIOTRACECLK ('b0), + .EMIOTTC0CLKI ('b0), + .EMIOTTC1CLKI ('b0), + .EMIOUART0CTSN ('b0), + .EMIOUART0DCDN ('b0), + .EMIOUART0DSRN ('b0), + .EMIOUART0RIN ('b0), + .EMIOUART0RX ('b0), + .EMIOUART1CTSN ('b0), + .EMIOUART1DCDN ('b0), + .EMIOUART1DSRN ('b0), + .EMIOUART1RIN ('b0), + .EMIOUART1RX ('b0), + .EMIOUSB0VBUSPWRFAULT ('b0), + .EMIOUSB1VBUSPWRFAULT ('b0), + .EMIOWDTCLKI ('b0), + .EVENTEVENTI ('b0), + .FCLKCLKTRIGN ('b0), + .FPGAIDLEN ('b0), + .FTMDTRACEINATID ('b0), + .FTMDTRACEINCLOCK ('b0), + .FTMDTRACEINDATA ('b0), + .FTMDTRACEINVALID ('b0), + .FTMTF2PDEBUG ('b0), + .FTMTF2PTRIG ('b0), + .FTMTP2FTRIGACK ('b0), + .IRQF2P ('b0), + .MAXIGP0ACLK ('b0), + .MAXIGP0ARREADY ('b0), + .MAXIGP0AWREADY ('b0), + .MAXIGP0BID ('b0), + .MAXIGP0BRESP ('b0), + .MAXIGP0BVALID ('b0), + .MAXIGP0RDATA ('b0), + .MAXIGP0RID ('b0), + .MAXIGP0RLAST ('b0), + .MAXIGP0RRESP ('b0), + .MAXIGP0RVALID ('b0), + .MAXIGP0WREADY ('b0), + .MAXIGP1ACLK ('b0), + .MAXIGP1ARREADY ('b0), + .MAXIGP1AWREADY ('b0), + .MAXIGP1BID ('b0), + .MAXIGP1BRESP ('b0), + .MAXIGP1BVALID ('b0), + .MAXIGP1RDATA ('b0), + .MAXIGP1RID ('b0), + .MAXIGP1RLAST ('b0), + .MAXIGP1RRESP ('b0), + .MAXIGP1RVALID ('b0), + .MAXIGP1WREADY ('b0), + .SAXIACPACLK ('b0), + .SAXIACPARADDR ('b0), + .SAXIACPARBURST ('b0), + .SAXIACPARCACHE ('b0), + .SAXIACPARID ('b0), + .SAXIACPARLEN ('b0), + .SAXIACPARLOCK ('b0), + .SAXIACPARPROT ('b0), + .SAXIACPARQOS ('b0), + .SAXIACPARSIZE ('b0), + .SAXIACPARUSER ('b0), + .SAXIACPARVALID ('b0), + .SAXIACPAWADDR ('b0), + .SAXIACPAWBURST ('b0), + .SAXIACPAWCACHE ('b0), + .SAXIACPAWID ('b0), + .SAXIACPAWLEN ('b0), + .SAXIACPAWLOCK ('b0), + .SAXIACPAWPROT ('b0), + .SAXIACPAWQOS ('b0), + .SAXIACPAWSIZE ('b0), + .SAXIACPAWUSER ('b0), + .SAXIACPAWVALID ('b0), + .SAXIACPBREADY ('b0), + .SAXIACPRREADY ('b0), + .SAXIACPWDATA ('b0), + .SAXIACPWID ('b0), + .SAXIACPWLAST ('b0), + .SAXIACPWSTRB ('b0), + .SAXIACPWVALID ('b0), + .SAXIGP0ACLK ('b0), + .SAXIGP0ARADDR ('b0), + .SAXIGP0ARBURST ('b0), + .SAXIGP0ARCACHE ('b0), + .SAXIGP0ARID ('b0), + .SAXIGP0ARLEN ('b0), + .SAXIGP0ARLOCK ('b0), + .SAXIGP0ARPROT ('b0), + .SAXIGP0ARQOS ('b0), + .SAXIGP0ARSIZE ('b0), + .SAXIGP0ARVALID ('b0), + .SAXIGP0AWADDR ('b0), + .SAXIGP0AWBURST ('b0), + .SAXIGP0AWCACHE ('b0), + .SAXIGP0AWID ('b0), + .SAXIGP0AWLEN ('b0), + .SAXIGP0AWLOCK ('b0), + .SAXIGP0AWPROT ('b0), + .SAXIGP0AWQOS ('b0), + .SAXIGP0AWSIZE ('b0), + .SAXIGP0AWVALID ('b0), + .SAXIGP0BREADY ('b0), + .SAXIGP0RREADY ('b0), + .SAXIGP0WDATA ('b0), + .SAXIGP0WID ('b0), + .SAXIGP0WLAST ('b0), + .SAXIGP0WSTRB ('b0), + .SAXIGP0WVALID ('b0), + .SAXIGP1ACLK ('b0), + .SAXIGP1ARADDR ('b0), + .SAXIGP1ARBURST ('b0), + .SAXIGP1ARCACHE ('b0), + .SAXIGP1ARID ('b0), + .SAXIGP1ARLEN ('b0), + .SAXIGP1ARLOCK ('b0), + .SAXIGP1ARPROT ('b0), + .SAXIGP1ARQOS ('b0), + .SAXIGP1ARSIZE ('b0), + .SAXIGP1ARVALID ('b0), + .SAXIGP1AWADDR ('b0), + .SAXIGP1AWBURST ('b0), + .SAXIGP1AWCACHE ('b0), + .SAXIGP1AWID ('b0), + .SAXIGP1AWLEN ('b0), + .SAXIGP1AWLOCK ('b0), + .SAXIGP1AWPROT ('b0), + .SAXIGP1AWQOS ('b0), + .SAXIGP1AWSIZE ('b0), + .SAXIGP1AWVALID ('b0), + .SAXIGP1BREADY ('b0), + .SAXIGP1RREADY ('b0), + .SAXIGP1WDATA ('b0), + .SAXIGP1WID ('b0), + .SAXIGP1WLAST ('b0), + .SAXIGP1WSTRB ('b0), + .SAXIGP1WVALID ('b0), + .SAXIHP0ACLK ('b0), + .SAXIHP0ARADDR ('b0), + .SAXIHP0ARBURST ('b0), + .SAXIHP0ARCACHE ('b0), + .SAXIHP0ARID ('b0), + .SAXIHP0ARLEN ('b0), + .SAXIHP0ARLOCK ('b0), + .SAXIHP0ARPROT ('b0), + .SAXIHP0ARQOS ('b0), + .SAXIHP0ARSIZE ('b0), + .SAXIHP0ARVALID ('b0), + .SAXIHP0AWADDR ('b0), + .SAXIHP0AWBURST ('b0), + .SAXIHP0AWCACHE ('b0), + .SAXIHP0AWID ('b0), + .SAXIHP0AWLEN ('b0), + .SAXIHP0AWLOCK ('b0), + .SAXIHP0AWPROT ('b0), + .SAXIHP0AWQOS ('b0), + .SAXIHP0AWSIZE ('b0), + .SAXIHP0AWVALID ('b0), + .SAXIHP0BREADY ('b0), + .SAXIHP0RDISSUECAP1EN ('b0), + .SAXIHP0RREADY ('b0), + .SAXIHP0WDATA ('b0), + .SAXIHP0WID ('b0), + .SAXIHP0WLAST ('b0), + .SAXIHP0WRISSUECAP1EN ('b0), + .SAXIHP0WSTRB ('b0), + .SAXIHP0WVALID ('b0), + .SAXIHP1ACLK ('b0), + .SAXIHP1ARADDR ('b0), + .SAXIHP1ARBURST ('b0), + .SAXIHP1ARCACHE ('b0), + .SAXIHP1ARID ('b0), + .SAXIHP1ARLEN ('b0), + .SAXIHP1ARLOCK ('b0), + .SAXIHP1ARPROT ('b0), + .SAXIHP1ARQOS ('b0), + .SAXIHP1ARSIZE ('b0), + .SAXIHP1ARVALID ('b0), + .SAXIHP1AWADDR ('b0), + .SAXIHP1AWBURST ('b0), + .SAXIHP1AWCACHE ('b0), + .SAXIHP1AWID ('b0), + .SAXIHP1AWLEN ('b0), + .SAXIHP1AWLOCK ('b0), + .SAXIHP1AWPROT ('b0), + .SAXIHP1AWQOS ('b0), + .SAXIHP1AWSIZE ('b0), + .SAXIHP1AWVALID ('b0), + .SAXIHP1BREADY ('b0), + .SAXIHP1RDISSUECAP1EN ('b0), + .SAXIHP1RREADY ('b0), + .SAXIHP1WDATA ('b0), + .SAXIHP1WID ('b0), + .SAXIHP1WLAST ('b0), + .SAXIHP1WRISSUECAP1EN ('b0), + .SAXIHP1WSTRB ('b0), + .SAXIHP1WVALID ('b0), + .SAXIHP2ACLK ('b0), + .SAXIHP2ARADDR ('b0), + .SAXIHP2ARBURST ('b0), + .SAXIHP2ARCACHE ('b0), + .SAXIHP2ARID ('b0), + .SAXIHP2ARLEN ('b0), + .SAXIHP2ARLOCK ('b0), + .SAXIHP2ARPROT ('b0), + .SAXIHP2ARQOS ('b0), + .SAXIHP2ARSIZE ('b0), + .SAXIHP2ARVALID ('b0), + .SAXIHP2AWADDR ('b0), + .SAXIHP2AWBURST ('b0), + .SAXIHP2AWCACHE ('b0), + .SAXIHP2AWID ('b0), + .SAXIHP2AWLEN ('b0), + .SAXIHP2AWLOCK ('b0), + .SAXIHP2AWPROT ('b0), + .SAXIHP2AWQOS ('b0), + .SAXIHP2AWSIZE ('b0), + .SAXIHP2AWVALID ('b0), + .SAXIHP2BREADY ('b0), + .SAXIHP2RDISSUECAP1EN ('b0), + .SAXIHP2RREADY ('b0), + .SAXIHP2WDATA ('b0), + .SAXIHP2WID ('b0), + .SAXIHP2WLAST ('b0), + .SAXIHP2WRISSUECAP1EN ('b0), + .SAXIHP2WSTRB ('b0), + .SAXIHP2WVALID ('b0), + .SAXIHP3ACLK ('b0), + .SAXIHP3ARADDR ('b0), + .SAXIHP3ARBURST ('b0), + .SAXIHP3ARCACHE ('b0), + .SAXIHP3ARID ('b0), + .SAXIHP3ARLEN ('b0), + .SAXIHP3ARLOCK ('b0), + .SAXIHP3ARPROT ('b0), + .SAXIHP3ARQOS ('b0), + .SAXIHP3ARSIZE ('b0), + .SAXIHP3ARVALID ('b0), + .SAXIHP3AWADDR ('b0), + .SAXIHP3AWBURST ('b0), + .SAXIHP3AWCACHE ('b0), + .SAXIHP3AWID ('b0), + .SAXIHP3AWLEN ('b0), + .SAXIHP3AWLOCK ('b0), + .SAXIHP3AWPROT ('b0), + .SAXIHP3AWQOS ('b0), + .SAXIHP3AWSIZE ('b0), + .SAXIHP3AWVALID ('b0), + .SAXIHP3BREADY ('b0), + .SAXIHP3RDISSUECAP1EN ('b0), + .SAXIHP3RREADY ('b0), + .SAXIHP3WDATA ('b0), + .SAXIHP3WID ('b0), + .SAXIHP3WLAST ('b0), + .SAXIHP3WRISSUECAP1EN ('b0), + .SAXIHP3WSTRB ('b0), + .SAXIHP3WVALID ('b0) +); From 2b2254f514da530d6e5572104e68f795895d23d8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 12:51:56 -0800 Subject: [PATCH 085/174] Add support for PS7 blocks --- xc7/arch.cc | 13 ++++++++++++- xc7/constids.inc | 2 ++ xc7/xdl.cc | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 1dffcb9d..e9c6d725 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -432,7 +432,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const WireId ret; auto pin_name = pin.str(this); - if (getBelType(bel) == id_SLICE_LUT6) { + auto bel_type = getBelType(bel); + if (bel_type == id_SLICE_LUT6) { // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT if (pin_name[0] == 'I' || pin_name[0] == 'O') { switch (torc_info->bel_to_loc[bel.index].z) { @@ -457,6 +458,12 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const } } } + else if (bel_type == id_PS7) { + // e.g. Convert DDRARB[0] -> DDRARB0 + boost::erase_all(pin_name, "["); + boost::erase_all(pin_name, "]"); + } + auto site_index = torc_info->bel_to_site_index[bel.index]; const auto &site = torc_info->sites.getSite(site_index); auto &tw = site.getPinTilewire(pin_name); @@ -994,6 +1001,10 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_COMB_OUTPUT; return TMG_COMB_INPUT; } + else if (cell->type == id_PS7) { + // TODO + return TMG_IGNORE; + } log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } diff --git a/xc7/constids.inc b/xc7/constids.inc index 0be998f6..bf0e7114 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -440,6 +440,7 @@ X(DFF_ENABLE) X(CARRY_ENABLE) X(NEG_CLK) +// XC7 X(I) X(LUT1) @@ -457,3 +458,4 @@ X(FDPE) X(BUFGCTRL) X(SLICE_LUT6) X(IOB33) +X(PS7) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index a83297d8..97a18538 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -68,7 +68,7 @@ void write_xdl(const Context *ctx, std::ostream &out) const char *type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL) + else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7) type = cell.second->type.c_str(ctx); else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -205,6 +205,7 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("CE1INV", "", "CE1"); instPtr->setConfig("S1INV", "", "S1"); instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); + } else if (cell.second->type == id_PS7) { } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From 3d8b88deef3340e49bfab182e9e3561cb5251a37 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 12:52:52 -0800 Subject: [PATCH 086/174] blinky to instantiate PS7 so that reconfiguring from Linux doesn't kill PS --- xc7/blinky.v | 1 + xc7/ps7.vh | 328 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 329 insertions(+) create mode 100644 xc7/ps7.vh diff --git a/xc7/blinky.v b/xc7/blinky.v index 7b5aae53..cab84984 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -5,6 +5,7 @@ module blinky ( output led2, output led3 ); + `include "ps7.vh" BUFGCTRL clk_gb ( .I0(clki), diff --git a/xc7/ps7.vh b/xc7/ps7.vh new file mode 100644 index 00000000..445e67aa --- /dev/null +++ b/xc7/ps7.vh @@ -0,0 +1,328 @@ +(* keep *) +PS7 ps7_stub( + .DDRARB ('b0), + .DMA0ACLK ('b0), + .DMA0DAREADY ('b0), + .DMA0DRLAST ('b0), + .DMA0DRTYPE ('b0), + .DMA0DRVALID ('b0), + .DMA1ACLK ('b0), + .DMA1DAREADY ('b0), + .DMA1DRLAST ('b0), + .DMA1DRTYPE ('b0), + .DMA1DRVALID ('b0), + .DMA2ACLK ('b0), + .DMA2DAREADY ('b0), + .DMA2DRLAST ('b0), + .DMA2DRTYPE ('b0), + .DMA2DRVALID ('b0), + .DMA3ACLK ('b0), + .DMA3DAREADY ('b0), + .DMA3DRLAST ('b0), + .DMA3DRTYPE ('b0), + .DMA3DRVALID ('b0), + .EMIOCAN0PHYRX ('b0), + .EMIOCAN1PHYRX ('b0), + .EMIOENET0EXTINTIN ('b0), + .EMIOENET0GMIICOL ('b0), + .EMIOENET0GMIICRS ('b0), + .EMIOENET0GMIIRXCLK ('b0), + .EMIOENET0GMIIRXD ('b0), + .EMIOENET0GMIIRXDV ('b0), + .EMIOENET0GMIIRXER ('b0), + .EMIOENET0GMIITXCLK ('b0), + .EMIOENET0MDIOI ('b0), + .EMIOENET1EXTINTIN ('b0), + .EMIOENET1GMIICOL ('b0), + .EMIOENET1GMIICRS ('b0), + .EMIOENET1GMIIRXCLK ('b0), + .EMIOENET1GMIIRXD ('b0), + .EMIOENET1GMIIRXDV ('b0), + .EMIOENET1GMIIRXER ('b0), + .EMIOENET1GMIITXCLK ('b0), + .EMIOENET1MDIOI ('b0), + .EMIOGPIOI ('b0), + .EMIOI2C0SCLI ('b0), + .EMIOI2C0SDAI ('b0), + .EMIOI2C1SCLI ('b0), + .EMIOI2C1SDAI ('b0), + .EMIOPJTAGTCK ('b0), + .EMIOPJTAGTDI ('b0), + .EMIOPJTAGTMS ('b0), + .EMIOSDIO0CDN ('b0), + .EMIOSDIO0CLKFB ('b0), + .EMIOSDIO0CMDI ('b0), + .EMIOSDIO0DATAI ('b0), + .EMIOSDIO0WP ('b0), + .EMIOSDIO1CDN ('b0), + .EMIOSDIO1CLKFB ('b0), + .EMIOSDIO1CMDI ('b0), + .EMIOSDIO1DATAI ('b0), + .EMIOSDIO1WP ('b0), + .EMIOSPI0MI ('b0), + .EMIOSPI0SCLKI ('b0), + .EMIOSPI0SI ('b0), + .EMIOSPI0SSIN ('b0), + .EMIOSPI1MI ('b0), + .EMIOSPI1SCLKI ('b0), + .EMIOSPI1SI ('b0), + .EMIOSPI1SSIN ('b0), + .EMIOSRAMINTIN ('b0), + .EMIOTRACECLK ('b0), + .EMIOTTC0CLKI ('b0), + .EMIOTTC1CLKI ('b0), + .EMIOUART0CTSN ('b0), + .EMIOUART0DCDN ('b0), + .EMIOUART0DSRN ('b0), + .EMIOUART0RIN ('b0), + .EMIOUART0RX ('b0), + .EMIOUART1CTSN ('b0), + .EMIOUART1DCDN ('b0), + .EMIOUART1DSRN ('b0), + .EMIOUART1RIN ('b0), + .EMIOUART1RX ('b0), + .EMIOUSB0VBUSPWRFAULT ('b0), + .EMIOUSB1VBUSPWRFAULT ('b0), + .EMIOWDTCLKI ('b0), + .EVENTEVENTI ('b0), + .FCLKCLKTRIGN ('b0), + .FPGAIDLEN ('b0), + .FTMDTRACEINATID ('b0), + .FTMDTRACEINCLOCK ('b0), + .FTMDTRACEINDATA ('b0), + .FTMDTRACEINVALID ('b0), + .FTMTF2PDEBUG ('b0), + .FTMTF2PTRIG ('b0), + .FTMTP2FTRIGACK ('b0), + .IRQF2P ('b0), + .MAXIGP0ACLK ('b0), + .MAXIGP0ARREADY ('b0), + .MAXIGP0AWREADY ('b0), + .MAXIGP0BID ('b0), + .MAXIGP0BRESP ('b0), + .MAXIGP0BVALID ('b0), + .MAXIGP0RDATA ('b0), + .MAXIGP0RID ('b0), + .MAXIGP0RLAST ('b0), + .MAXIGP0RRESP ('b0), + .MAXIGP0RVALID ('b0), + .MAXIGP0WREADY ('b0), + .MAXIGP1ACLK ('b0), + .MAXIGP1ARREADY ('b0), + .MAXIGP1AWREADY ('b0), + .MAXIGP1BID ('b0), + .MAXIGP1BRESP ('b0), + .MAXIGP1BVALID ('b0), + .MAXIGP1RDATA ('b0), + .MAXIGP1RID ('b0), + .MAXIGP1RLAST ('b0), + .MAXIGP1RRESP ('b0), + .MAXIGP1RVALID ('b0), + .MAXIGP1WREADY ('b0), + .SAXIACPACLK ('b0), + .SAXIACPARADDR ('b0), + .SAXIACPARBURST ('b0), + .SAXIACPARCACHE ('b0), + .SAXIACPARID ('b0), + .SAXIACPARLEN ('b0), + .SAXIACPARLOCK ('b0), + .SAXIACPARPROT ('b0), + .SAXIACPARQOS ('b0), + .SAXIACPARSIZE ('b0), + .SAXIACPARUSER ('b0), + .SAXIACPARVALID ('b0), + .SAXIACPAWADDR ('b0), + .SAXIACPAWBURST ('b0), + .SAXIACPAWCACHE ('b0), + .SAXIACPAWID ('b0), + .SAXIACPAWLEN ('b0), + .SAXIACPAWLOCK ('b0), + .SAXIACPAWPROT ('b0), + .SAXIACPAWQOS ('b0), + .SAXIACPAWSIZE ('b0), + .SAXIACPAWUSER ('b0), + .SAXIACPAWVALID ('b0), + .SAXIACPBREADY ('b0), + .SAXIACPRREADY ('b0), + .SAXIACPWDATA ('b0), + .SAXIACPWID ('b0), + .SAXIACPWLAST ('b0), + .SAXIACPWSTRB ('b0), + .SAXIACPWVALID ('b0), + .SAXIGP0ACLK ('b0), + .SAXIGP0ARADDR ('b0), + .SAXIGP0ARBURST ('b0), + .SAXIGP0ARCACHE ('b0), + .SAXIGP0ARID ('b0), + .SAXIGP0ARLEN ('b0), + .SAXIGP0ARLOCK ('b0), + .SAXIGP0ARPROT ('b0), + .SAXIGP0ARQOS ('b0), + .SAXIGP0ARSIZE ('b0), + .SAXIGP0ARVALID ('b0), + .SAXIGP0AWADDR ('b0), + .SAXIGP0AWBURST ('b0), + .SAXIGP0AWCACHE ('b0), + .SAXIGP0AWID ('b0), + .SAXIGP0AWLEN ('b0), + .SAXIGP0AWLOCK ('b0), + .SAXIGP0AWPROT ('b0), + .SAXIGP0AWQOS ('b0), + .SAXIGP0AWSIZE ('b0), + .SAXIGP0AWVALID ('b0), + .SAXIGP0BREADY ('b0), + .SAXIGP0RREADY ('b0), + .SAXIGP0WDATA ('b0), + .SAXIGP0WID ('b0), + .SAXIGP0WLAST ('b0), + .SAXIGP0WSTRB ('b0), + .SAXIGP0WVALID ('b0), + .SAXIGP1ACLK ('b0), + .SAXIGP1ARADDR ('b0), + .SAXIGP1ARBURST ('b0), + .SAXIGP1ARCACHE ('b0), + .SAXIGP1ARID ('b0), + .SAXIGP1ARLEN ('b0), + .SAXIGP1ARLOCK ('b0), + .SAXIGP1ARPROT ('b0), + .SAXIGP1ARQOS ('b0), + .SAXIGP1ARSIZE ('b0), + .SAXIGP1ARVALID ('b0), + .SAXIGP1AWADDR ('b0), + .SAXIGP1AWBURST ('b0), + .SAXIGP1AWCACHE ('b0), + .SAXIGP1AWID ('b0), + .SAXIGP1AWLEN ('b0), + .SAXIGP1AWLOCK ('b0), + .SAXIGP1AWPROT ('b0), + .SAXIGP1AWQOS ('b0), + .SAXIGP1AWSIZE ('b0), + .SAXIGP1AWVALID ('b0), + .SAXIGP1BREADY ('b0), + .SAXIGP1RREADY ('b0), + .SAXIGP1WDATA ('b0), + .SAXIGP1WID ('b0), + .SAXIGP1WLAST ('b0), + .SAXIGP1WSTRB ('b0), + .SAXIGP1WVALID ('b0), + .SAXIHP0ACLK ('b0), + .SAXIHP0ARADDR ('b0), + .SAXIHP0ARBURST ('b0), + .SAXIHP0ARCACHE ('b0), + .SAXIHP0ARID ('b0), + .SAXIHP0ARLEN ('b0), + .SAXIHP0ARLOCK ('b0), + .SAXIHP0ARPROT ('b0), + .SAXIHP0ARQOS ('b0), + .SAXIHP0ARSIZE ('b0), + .SAXIHP0ARVALID ('b0), + .SAXIHP0AWADDR ('b0), + .SAXIHP0AWBURST ('b0), + .SAXIHP0AWCACHE ('b0), + .SAXIHP0AWID ('b0), + .SAXIHP0AWLEN ('b0), + .SAXIHP0AWLOCK ('b0), + .SAXIHP0AWPROT ('b0), + .SAXIHP0AWQOS ('b0), + .SAXIHP0AWSIZE ('b0), + .SAXIHP0AWVALID ('b0), + .SAXIHP0BREADY ('b0), + .SAXIHP0RDISSUECAP1EN ('b0), + .SAXIHP0RREADY ('b0), + .SAXIHP0WDATA ('b0), + .SAXIHP0WID ('b0), + .SAXIHP0WLAST ('b0), + .SAXIHP0WRISSUECAP1EN ('b0), + .SAXIHP0WSTRB ('b0), + .SAXIHP0WVALID ('b0), + .SAXIHP1ACLK ('b0), + .SAXIHP1ARADDR ('b0), + .SAXIHP1ARBURST ('b0), + .SAXIHP1ARCACHE ('b0), + .SAXIHP1ARID ('b0), + .SAXIHP1ARLEN ('b0), + .SAXIHP1ARLOCK ('b0), + .SAXIHP1ARPROT ('b0), + .SAXIHP1ARQOS ('b0), + .SAXIHP1ARSIZE ('b0), + .SAXIHP1ARVALID ('b0), + .SAXIHP1AWADDR ('b0), + .SAXIHP1AWBURST ('b0), + .SAXIHP1AWCACHE ('b0), + .SAXIHP1AWID ('b0), + .SAXIHP1AWLEN ('b0), + .SAXIHP1AWLOCK ('b0), + .SAXIHP1AWPROT ('b0), + .SAXIHP1AWQOS ('b0), + .SAXIHP1AWSIZE ('b0), + .SAXIHP1AWVALID ('b0), + .SAXIHP1BREADY ('b0), + .SAXIHP1RDISSUECAP1EN ('b0), + .SAXIHP1RREADY ('b0), + .SAXIHP1WDATA ('b0), + .SAXIHP1WID ('b0), + .SAXIHP1WLAST ('b0), + .SAXIHP1WRISSUECAP1EN ('b0), + .SAXIHP1WSTRB ('b0), + .SAXIHP1WVALID ('b0), + .SAXIHP2ACLK ('b0), + .SAXIHP2ARADDR ('b0), + .SAXIHP2ARBURST ('b0), + .SAXIHP2ARCACHE ('b0), + .SAXIHP2ARID ('b0), + .SAXIHP2ARLEN ('b0), + .SAXIHP2ARLOCK ('b0), + .SAXIHP2ARPROT ('b0), + .SAXIHP2ARQOS ('b0), + .SAXIHP2ARSIZE ('b0), + .SAXIHP2ARVALID ('b0), + .SAXIHP2AWADDR ('b0), + .SAXIHP2AWBURST ('b0), + .SAXIHP2AWCACHE ('b0), + .SAXIHP2AWID ('b0), + .SAXIHP2AWLEN ('b0), + .SAXIHP2AWLOCK ('b0), + .SAXIHP2AWPROT ('b0), + .SAXIHP2AWQOS ('b0), + .SAXIHP2AWSIZE ('b0), + .SAXIHP2AWVALID ('b0), + .SAXIHP2BREADY ('b0), + .SAXIHP2RDISSUECAP1EN ('b0), + .SAXIHP2RREADY ('b0), + .SAXIHP2WDATA ('b0), + .SAXIHP2WID ('b0), + .SAXIHP2WLAST ('b0), + .SAXIHP2WRISSUECAP1EN ('b0), + .SAXIHP2WSTRB ('b0), + .SAXIHP2WVALID ('b0), + .SAXIHP3ACLK ('b0), + .SAXIHP3ARADDR ('b0), + .SAXIHP3ARBURST ('b0), + .SAXIHP3ARCACHE ('b0), + .SAXIHP3ARID ('b0), + .SAXIHP3ARLEN ('b0), + .SAXIHP3ARLOCK ('b0), + .SAXIHP3ARPROT ('b0), + .SAXIHP3ARQOS ('b0), + .SAXIHP3ARSIZE ('b0), + .SAXIHP3ARVALID ('b0), + .SAXIHP3AWADDR ('b0), + .SAXIHP3AWBURST ('b0), + .SAXIHP3AWCACHE ('b0), + .SAXIHP3AWID ('b0), + .SAXIHP3AWLEN ('b0), + .SAXIHP3AWLOCK ('b0), + .SAXIHP3AWPROT ('b0), + .SAXIHP3AWQOS ('b0), + .SAXIHP3AWSIZE ('b0), + .SAXIHP3AWVALID ('b0), + .SAXIHP3BREADY ('b0), + .SAXIHP3RDISSUECAP1EN ('b0), + .SAXIHP3RREADY ('b0), + .SAXIHP3WDATA ('b0), + .SAXIHP3WID ('b0), + .SAXIHP3WLAST ('b0), + .SAXIHP3WRISSUECAP1EN ('b0), + .SAXIHP3WSTRB ('b0), + .SAXIHP3WVALID ('b0) +); From f6bdd9264088c1f6e5cd94ed5a852e0e3c9b2aac Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 16:11:38 -0800 Subject: [PATCH 087/174] Implement Arch::getPipName() and remove debug/verbose before routing --- xc7/arch.cc | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 06b138ac..fbfe5fdf 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -600,20 +600,26 @@ IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); -#if 1 - int x = chip_info->pip_data[pip.index].x; - int y = chip_info->pip_data[pip.index].y; + ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip.index].getSourceTilewire()); + ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip.index].getSinkTilewire()); + std::stringstream pip_name; + pip_name << ewi_src.mTileName << "." << ewi_src.mWireName << ".->." << ewi_dst.mWireName; + return id(pip_name.str()); - std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); - std::replace(src_name.begin(), src_name.end(), '/', '.'); - - std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); - std::replace(dst_name.begin(), dst_name.end(), '/', '.'); - - return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); -#else - return id(chip_info->pip_data[pip.index].name.get()); -#endif +//#if 1 +// int x = chip_info->pip_data[pip.index].x; +// int y = chip_info->pip_data[pip.index].y; +// +// std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); +// std::replace(src_name.begin(), src_name.end(), '/', '.'); +// +// std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); +// std::replace(dst_name.begin(), dst_name.end(), '/', '.'); +// +// return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); +//#else +// return id(chip_info->pip_data[pip.index].name.get()); +//#endif } // ----------------------------------------------------------------------- @@ -774,8 +780,6 @@ bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } bool Arch::route() { - getCtx()->debug = true; - getCtx()->verbose = true; return router1(getCtx(), Router1Cfg(getCtx())); } From 10d6db6d94873068809e26c9e3e724683f0339b1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 18:48:46 -0800 Subject: [PATCH 088/174] Do not add "$iob" suffix --- xc7/pack.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/pack.cc b/xc7/pack.cc index 7d7eb34d..d2130e72 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -421,7 +421,7 @@ static void pack_io(Context *ctx) } } else { // Create a IOBUF buffer - std::unique_ptr ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); + std::unique_ptr ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx)); nxio_to_sb(ctx, ci, ice_cell.get()); new_cells.push_back(std::move(ice_cell)); sb = new_cells.back().get(); From 533c73041863c580ee26b28bd1dc2f9eb98cdba4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 18:49:58 -0800 Subject: [PATCH 089/174] Update without $iob suffix --- xc7/blinky.pcf | 2 +- xc7/blinky_tb.v | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 1afc0f32..6c2e5149 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -4,5 +4,5 @@ COMP "led2" LOCATE = SITE "G14" LEVEL 1; COMP "led3" LOCATE = SITE "D18" LEVEL 1; COMP "clki" LOCATE = SITE "K17" LEVEL 1; NET "clki" PERIOD = 8 nS ; -PIN "clki_pin" = BEL "clki$iob.PAD" PINNAME PAD; +PIN "clki_pin" = BEL "clki.PAD" PINNAME PAD; PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/blinky_tb.v b/xc7/blinky_tb.v index 0378b679..069dbe9c 100644 --- a/xc7/blinky_tb.v +++ b/xc7/blinky_tb.v @@ -4,12 +4,12 @@ module blinky_tb; wire led0, led1, led2, led3; - chip uut ( - .\clki$iob.PAD.PAD (clk), - .\led0$iob.OUTBUF.OUT (led0), - .\led1$iob.OUTBUF.OUT (led1), - .\led2$iob.OUTBUF.OUT (led2), - .\led3$iob.OUTBUF.OUT (led3) + blinky uut ( + .\clki.PAD.PAD (clk), + .\led0.OUTBUF.OUT (led0), + .\led1.OUTBUF.OUT (led1), + .\led2.OUTBUF.OUT (led2), + .\led3.OUTBUF.OUT (led3) ); initial begin From a0c6c64be70eb5b874a9309d6da47bd275823947 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 18:50:43 -0800 Subject: [PATCH 090/174] blinky.v to not instantiate PS7, blink more slowly/predictably --- xc7/blinky.v | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/xc7/blinky.v b/xc7/blinky.v index cab84984..ad8f1de7 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -5,7 +5,7 @@ module blinky ( output led2, output led3 ); - `include "ps7.vh" + //`include "ps7.vh" BUFGCTRL clk_gb ( .I0(clki), @@ -19,7 +19,7 @@ module blinky ( ); localparam BITS = 4; - localparam LOG2DELAY = 21; + localparam LOG2DELAY = 23; reg [BITS+LOG2DELAY-1:0] counter = 0; reg [BITS-1:0] outcnt; @@ -29,5 +29,5 @@ module blinky ( outcnt <= counter >> LOG2DELAY; end - assign {led0, led1, led2, led3} = outcnt ^ (outcnt >> 1); + assign {led0, led1, led2, led3} = outcnt /*^ (outcnt >> 1)*/; endmodule From 99f5836b0ed2d988855930085fc78476f732362f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 10 Nov 2018 19:55:22 -0800 Subject: [PATCH 091/174] Add some cell delays --- xc7/arch.cc | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index fbfe5fdf..7600e3a1 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -963,8 +963,22 @@ std::vector Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { if (cell->type == id_SLICE_LUT6) { - if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) - return toPort == id_O || toPort == id_OQ; + if (fromPort.index >= id_I1.index && fromPort.index <= id_I6.index) { + if (toPort == id_O) { + delay.delay = 124; // Tilo + return true; + } + if (toPort == id_OQ) { + delay.delay = 95; // Tas + return true; + } + } + if (fromPort == id_CLK) { + if (toPort == id_OQ) { + delay.delay = 456; // Tcko + return false; // No path CLK->OQ, but this fn is used for getting clkToQ delay + } + } } else if (cell->type == id_BUFGCTRL) { return true; } From 83117bef66f5fbe27d98de8e30979e47d0a1ffbb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 11 Nov 2018 10:19:17 -0800 Subject: [PATCH 092/174] Add missing APIs needed for router_improve --- xc7/arch.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/xc7/arch.h b/xc7/arch.h index 9d8c4251..092cd5f6 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -677,6 +677,11 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } + WireId getConflictingWireWire(WireId wire) const + { + return wire; + } + NetInfo *getConflictingWireNet(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -773,6 +778,11 @@ struct Arch : BaseCtx return pip_to_net[pip.index]; } + WireId getConflictingPipWire(PipId pip) const + { + return WireId(); + } + NetInfo *getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); From dd85e11abb0f48a4e2cad17a061729e683ee613e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 11 Nov 2018 11:55:27 -0800 Subject: [PATCH 093/174] [timing] More verbosity for crit path report --- common/timing.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/common/timing.cc b/common/timing.cc index 81ce7b73..10981454 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -405,7 +405,26 @@ void timing_analysis(Context *ctx, bool print_histogram, bool print_path) log_info("%4.1f %4.1f Net %s budget %f ns (%d,%d) -> (%d,%d)\n", ctx->getDelayNS(net_delay), ctx->getDelayNS(total), net->name.c_str(ctx), ctx->getDelayNS(sink->budget), driver_loc.x, driver_loc.y, sink_loc.x, sink_loc.y); - log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx)); + log_info(" Sink %s.%s\n", sink_cell->name.c_str(ctx), sink->port.c_str(ctx)); + if (ctx->verbose) { + auto driver_wire = ctx->getNetinfoSourceWire(net); + auto sink_wire = ctx->getNetinfoSinkWire(net, *sink); + log_info(" prediction: %f ns estimate: %f ns\n", + ctx->getDelayNS(ctx->predictDelay(net, *sink)), ctx->getDelayNS(ctx->estimateDelay(driver_wire, sink_wire))); + auto cursor = sink_wire; + delay_t cursor_delay; + while (driver_wire != cursor) { + cursor_delay = ctx->getWireDelay(cursor).maxDelay(); + log_info(" %1.3f %30s\n", ctx->getDelayNS(cursor_delay), ctx->getWireName(cursor).c_str(ctx)); + auto it = net->wires.find(cursor); + assert(it != net->wires.end()); + auto pip = it->second.pip; + NPNR_ASSERT(pip != PipId()); + cursor = ctx->getPipSrcWire(pip); + } + cursor_delay = ctx->getWireDelay(cursor).maxDelay(); + log_info(" %1.3f %30s\n", ctx->getDelayNS(cursor_delay), ctx->getWireName(cursor).c_str(ctx)); + } last_port = sink->port; } log_break(); From 53f025c03f3e055d09ee643b531ff2cc243b0a08 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 11 Nov 2018 12:56:52 -0800 Subject: [PATCH 094/174] Improved delay estimator --- xc7/blinky.sh | 11 ++++++++--- xc7/delay.cc | 46 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index cccc6c24..b116b3ff 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -5,6 +5,11 @@ yosys blinky.ys xdl -xdl2ncd blinky.xdl bitgen -w blinky.ncd -g UnconstrainedPins:Allow trce blinky.ncd -v 10 -netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky -iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ -insert_glbl true -vvp -N ./blinky_tb + +#netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky -insert_glbl true +#iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ +#vvp -N ./blinky_tb + +#xdl -xdl2ncd blinky.xdl -nopips blinky_map.ncd +#par -w blinky_map.ncd blinky_par.ncd blinky.pcf +#bitgen -w blinky_par.ncd -g UnconstrainedPins:Allow diff --git a/xc7/delay.cc b/xc7/delay.cc index fe14a5ce..397bd483 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,8 +104,27 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - - return 100 * (abs(src_info.getCol() - dst_info.getCol()) + abs(src_info.getRow() - dst_info.getRow())); + auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); + auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); +#if 1 + auto div_LH = std::div(abs_delta_x, 12); + auto div_LV = std::div(abs_delta_y, 18); + auto div_LVB = std::div(div_LV.rem, 12); + auto div_H6 = std::div(div_LH.rem, 6); + auto div_V6 = std::div(div_LVB.rem, 6); + auto div_H4 = std::div(div_H6.rem, 4); + auto div_V4 = std::div(div_V6.rem, 4); + auto div_H2 = std::div(div_H4.rem, 2); + auto div_V2 = std::div(div_V4.rem, 2); + auto num_H1 = div_H2.rem; + auto num_V1 = div_V2.rem; + return div_LH.quot * 360/2 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot) * 210/2 + (div_V6.quot + div_V4.quot) * 210 + + div_H2.quot * 170/2 + div_V2.quot * 170 + + num_H1 * 150/2 + num_V1 * 150; +#else + return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); +#endif } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const @@ -113,8 +132,27 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const const auto &driver = net_info->driver; auto driver_loc = getBelLocation(driver.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel); - - return 100 * (abs(driver_loc.x - sink_loc.x) + abs(driver_loc.y - sink_loc.y)); + auto abs_delta_x = abs(driver_loc.x - sink_loc.x); + auto abs_delta_y = abs(driver_loc.y - sink_loc.y); +#if 1 + auto div_LH = std::div(abs_delta_x, 12); + auto div_LV = std::div(abs_delta_y, 18); + auto div_LVB = std::div(div_LV.rem, 12); + auto div_H6 = std::div(div_LH.rem, 6); + auto div_V6 = std::div(div_LVB.rem, 6); + auto div_H4 = std::div(div_H6.rem, 4); + auto div_V4 = std::div(div_V6.rem, 4); + auto div_H2 = std::div(div_H4.rem, 2); + auto div_V2 = std::div(div_V4.rem, 2); + auto num_H1 = div_H2.rem; + auto num_V1 = div_V2.rem; + return div_LH.quot * 360/2 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot) * 210/2 + (div_V6.quot + div_V4.quot) * 210 + + div_H2.quot * 170/2 + div_V2.quot * 170 + + num_H1 * 150/2 + num_V1 * 150; +#else + return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); +#endif } NEXTPNR_NAMESPACE_END From 75654a69f04bcc336a9d35e3a04ad8508a245551 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 11 Nov 2018 14:15:11 -0800 Subject: [PATCH 095/174] Fix LUT input delays, speedup construct_wire_to_delay? --- xc7/arch.cc | 89 +++++++++++++++++++++++++++++++---------------------- xc7/arch.h | 2 +- 2 files changed, 54 insertions(+), 37 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 7600e3a1..13fad6e0 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -41,7 +41,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string site_index_to_type(construct_site_index_to_type(ctx, sites)), bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), - num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(wire_to_tilewire, *ddb)), + num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(tiles, wire_to_tilewire, *ddb)), pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), num_pips(pip_to_arc.size()) { @@ -163,7 +163,7 @@ TorcInfo::construct_wire_to_tilewire(const Segments &segments, const Tiles &tile wire_to_tilewire.shrink_to_fit(); return wire_to_tilewire; } -std::vector TorcInfo::construct_wire_to_delay(const std::vector &wire_to_tilewire, const DDB &ddb) +std::vector TorcInfo::construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, const DDB &ddb) { std::vector wire_to_delay; wire_to_delay.reserve(wire_to_tilewire.size()); @@ -174,45 +174,62 @@ std::vector TorcInfo::construct_wire_to_delay(const std::vector> delay_lookup; boost::cmatch what; - ExtendedWireInfo ewi(ddb); for (const auto &tw : wire_to_tilewire) { - ewi.set(tw); - DelayInfo d; - if (boost::regex_match(ewi.mWireName, what, re_124)) { - switch (what.str(2)[0]) { - case '1': - d.delay = 150; - break; - case '2': - d.delay = 170; - break; - case '4': - d.delay = 210; - break; - case '6': - d.delay = 210; - break; - default: - throw; + const TileInfo& tileInfo = tiles.getTileInfo(tw.getTileIndex()); + auto tile_type_index = tileInfo.getTypeIndex(); + + auto it = delay_lookup.find(tile_type_index); + if (it == delay_lookup.end()) { + auto wireCount = tiles.getWireCount(tile_type_index); + std::vector tile_delays(wireCount); + for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { + const WireInfo& wireInfo = tiles.getWireInfo(tile_type_index, wireIndex); + auto wire_name = wireInfo.getName(); + if (boost::regex_match(wire_name, what, re_124)) { + switch (what.str(2)[0]) { + case '1': tile_delays[wireIndex] = 150; break; + case '2': tile_delays[wireIndex] = 170; break; + case '4': tile_delays[wireIndex] = 210; break; + case '6': tile_delays[wireIndex] = 210; break; + default: throw; + } + } else if (boost::regex_match(wire_name, what, re_L)) { + std::string l(what[2]); + if (l == "H") + tile_delays[wireIndex] = 360; + else if (l == "VB") + tile_delays[wireIndex] = 300; + else if (l == "V") + tile_delays[wireIndex] = 350; + else + throw; + } else if (boost::regex_match(wire_name, what, re_BYP)) { + tile_delays[wireIndex] = 190; + } else if (boost::regex_match(wire_name, what, re_BYP_B)) { + } else if (boost::regex_match(wire_name, what, re_FAN)) { + tile_delays[wireIndex] = 190; + } else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) { + switch (what.str(2)[0]) { + case '1': tile_delays[wireIndex] = 280; break; + case '2': tile_delays[wireIndex] = 280; break; + case '3': tile_delays[wireIndex] = 180; break; + case '4': tile_delays[wireIndex] = 180; break; + case '5': tile_delays[wireIndex] = 80; break; + case '6': tile_delays[wireIndex] = 40; break; + default: throw; + } + } } - } else if (boost::regex_match(ewi.mWireName, what, re_L)) { - std::string l(what[2]); - if (l == "H") - d.delay = 360; - else if (l == "VB") - d.delay = 300; - else if (l == "V") - d.delay = 350; - else - throw; - } else if (boost::regex_match(ewi.mWireName, what, re_BYP)) { - d.delay = 190; - } else if (boost::regex_match(ewi.mWireName, what, re_BYP_B)) { - } else if (boost::regex_match(ewi.mWireName, what, re_FAN)) { - d.delay = 190; + it = delay_lookup.emplace(tile_type_index, std::move(tile_delays)).first; } + assert(it != delay_lookup.end()); + DelayInfo d; + d.delay = it->second[tw.getWireIndex()]; wire_to_delay.emplace_back(std::move(d)); } diff --git a/xc7/arch.h b/xc7/arch.h index 092cd5f6..24501d61 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -331,7 +331,7 @@ struct TorcInfo construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map &segment_to_wire, std::unordered_map &trivial_to_wire); - static std::vector construct_wire_to_delay(const std::vector &wire_to_tilewire, + static std::vector construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, const DDB &ddb); static std::vector construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, std::vector> &wire_to_pips_uphill, From ec96897c1d5e01456087b7150911e93abd1b72c5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 11 Nov 2018 14:21:06 -0800 Subject: [PATCH 096/174] Ahead of LUT input swapping, assign LUT<6 from A6 downwards --- xc7/cells.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index e1588516..f8eb1373 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -259,17 +259,17 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; - replace_port(lut, ctx->id("I0"), lc, id_I1); + replace_port(lut, ctx->id("I0"), lc, id_I6); if (get_net_or_empty(lut, id_I1)) - replace_port(lut, id_I1, lc, id_I2); + replace_port(lut, id_I1, lc, id_I5); if (get_net_or_empty(lut, id_I2)) - replace_port(lut, id_I2, lc, id_I3); + replace_port(lut, id_I2, lc, id_I4); if (get_net_or_empty(lut, id_I3)) - replace_port(lut, id_I3, lc, id_I4); + replace_port(lut, id_I3, lc, id_I3); if (get_net_or_empty(lut, id_I4)) - replace_port(lut, id_I4, lc, id_I5); + replace_port(lut, id_I4, lc, id_I2); if (get_net_or_empty(lut, id_I5)) - replace_port(lut, id_I5, lc, id_I6); + replace_port(lut, id_I5, lc, id_I1); if (no_dff) { replace_port(lut, id_O, lc, id_O); lc->params[ctx->id("DFF_ENABLE")] = "0"; From 72a16004e14d75679582bf8860247e127c2a3f48 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 09:01:24 -0800 Subject: [PATCH 097/174] Divide columns by 2 to get better X estimate for tiles --- xc7/arch.cc | 2 +- xc7/delay.cc | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 13fad6e0..17785776 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -108,7 +108,7 @@ std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles for (SiteIndex i(0); i < site_index_to_type.size(); ++i) { const auto &site = sites.getSite(i); const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); - const auto x = tile_info.getCol(); + const auto x = (tile_info.getCol() + 1) / 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs const auto y = tile_info.getRow(); if (site_index_to_type[i] == id_SLICE_LUT6) { diff --git a/xc7/delay.cc b/xc7/delay.cc index 397bd483..fbb99962 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,7 +104,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); + auto abs_delta_x = (abs(tile_info.getCol() - dst_info.getCol()) + 1)/ 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); #if 1 auto div_LH = std::div(abs_delta_x, 12); @@ -118,10 +118,10 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const auto div_V2 = std::div(div_V4.rem, 2); auto num_H1 = div_H2.rem; auto num_V1 = div_V2.rem; - return div_LH.quot * 360/2 + div_LVB.quot * 300 + div_LV.quot * 350 - + (div_H6.quot + div_H4.quot) * 210/2 + (div_V6.quot + div_V4.quot) * 210 - + div_H2.quot * 170/2 + div_V2.quot * 170 - + num_H1 * 150/2 + num_V1 * 150; + return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + + (div_H2.quot + div_V2.quot) * 170 + + (num_H1 + num_V1) * 150; #else return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); #endif @@ -146,10 +146,10 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto div_V2 = std::div(div_V4.rem, 2); auto num_H1 = div_H2.rem; auto num_V1 = div_V2.rem; - return div_LH.quot * 360/2 + div_LVB.quot * 300 + div_LV.quot * 350 - + (div_H6.quot + div_H4.quot) * 210/2 + (div_V6.quot + div_V4.quot) * 210 - + div_H2.quot * 170/2 + div_V2.quot * 170 - + num_H1 * 150/2 + num_V1 * 150; + return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + + (div_H2.quot + div_V2.quot) * 170 + + (num_H1 + num_V1) * 150; #else return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); #endif From d5ca744ca0eda472661e08f8435f9453b19260fd Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 09:10:14 -0800 Subject: [PATCH 098/174] Fix typo --- xc7/delay.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index fbb99962..3bef3dfc 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,7 +104,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - auto abs_delta_x = (abs(tile_info.getCol() - dst_info.getCol()) + 1)/ 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs + auto abs_delta_x = (abs(src_info.getCol() - dst_info.getCol()) + 1)/ 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); #if 1 auto div_LH = std::div(abs_delta_x, 12); From fa3d366ddb52ee645dcf7cc38aac08f83663581f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 10:10:57 -0800 Subject: [PATCH 099/174] Add missing operator needed by router_improve --- xc7/archdefs.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/xc7/archdefs.h b/xc7/archdefs.h index 571d76d3..1c2a752d 100644 --- a/xc7/archdefs.h +++ b/xc7/archdefs.h @@ -70,6 +70,7 @@ struct BelId bool operator==(const BelId &other) const { return index == other.index; } bool operator!=(const BelId &other) const { return index != other.index; } + bool operator<(const BelId &other) const { return index < other.index; } }; struct WireId @@ -78,6 +79,7 @@ struct WireId bool operator==(const WireId &other) const { return index == other.index; } bool operator!=(const WireId &other) const { return index != other.index; } + bool operator<(const WireId &other) const { return index < other.index; } }; struct PipId @@ -86,6 +88,7 @@ struct PipId bool operator==(const PipId &other) const { return index == other.index; } bool operator!=(const PipId &other) const { return index != other.index; } + bool operator<(const PipId &other) const { return index < other.index; } }; struct GroupId From ca94aa19153d9354caf1bc2e4e07b11d158e709c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 10:11:27 -0800 Subject: [PATCH 100/174] Reduce blinky.sh freq to 150MHz --- xc7/blinky.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index b116b3ff..ff1a03b5 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex yosys blinky.ys -../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 250 +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 xdl -xdl2ncd blinky.xdl bitgen -w blinky.ncd -g UnconstrainedPins:Allow trce blinky.ncd -v 10 From bccf95296c94ffc0019611a1ec3fb4dc95433a47 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 11:07:08 -0800 Subject: [PATCH 101/174] Add picorv32.pcf --- xc7/picorv32.pcf | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 xc7/picorv32.pcf diff --git a/xc7/picorv32.pcf b/xc7/picorv32.pcf new file mode 100644 index 00000000..499b965d --- /dev/null +++ b/xc7/picorv32.pcf @@ -0,0 +1,3 @@ +NET "clk" PERIOD = 8 nS ; +PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; +PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; From 9a498c26d1a67727a4feb5dbd8b2e13a7030beb2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 13 Nov 2018 11:07:43 -0800 Subject: [PATCH 102/174] Update picorv32.sh --- xc7/picorv32.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xc7/picorv32.sh b/xc7/picorv32.sh index 0ccb217e..99860236 100755 --- a/xc7/picorv32.sh +++ b/xc7/picorv32.sh @@ -3,6 +3,7 @@ set -ex rm -f picorv32.v wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v yosys picorv32.ys -../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl -#../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32.json -#icetime -d hx8k -t picorv32.asc +../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl --pcf picorv32.pcf --freq 150 +xdl -xdl2ncd picorv32.xdl +#bitgen -w blinky.ncd -g UnconstrainedPins:Allow +trce picorv32.ncd -v 10 From 18cee5d279cb12827bb221b74af202d20dc369c2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Nov 2018 14:26:29 -0800 Subject: [PATCH 103/174] More changes for upstream --- xc7/arch.cc | 25 ++++++++++++++++++++++--- xc7/arch.h | 12 +++++++++++- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 17785776..4ef66aa7 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -993,7 +993,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort if (fromPort == id_CLK) { if (toPort == id_OQ) { delay.delay = 456; // Tcko - return false; // No path CLK->OQ, but this fn is used for getting clkToQ delay + return true; } } } else if (cell->type == id_BUFGCTRL) { @@ -1003,7 +1003,7 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort } // Get the port class, also setting clockPort to associated clock if applicable -TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockPort) const +TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const { if (cell->type == id_SLICE_LUT6) { if (port == id_CLK) @@ -1019,7 +1019,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id return TMG_COMB_OUTPUT; } if (cell->lcInfo.dffEnable) { - clockPort = id_CLK; + clockInfoCount = 1; if (port == id_OQ) return TMG_REGISTER_OUTPUT; return TMG_REGISTER_INPUT; @@ -1045,6 +1045,25 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, Id log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } +TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const +{ + TimingClockingInfo info; + if (cell->type == id_SLICE_LUT6) { + info.clock_port = id_CLK; + info.edge = cell->lcInfo.negClk ? FALLING_EDGE : RISING_EDGE; + if (port == id_OQ) { + bool has_clktoq = getCellDelay(cell, id_CLK, id_OQ, info.clockToQ); + NPNR_ASSERT(has_clktoq); + } else { + info.setup.delay = 124; // Tilo + info.hold.delay = 0; + } + } else { + NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo"); + } + return info; +} + bool Arch::isGlobalNet(const NetInfo *net) const { if (net == nullptr) diff --git a/xc7/arch.h b/xc7/arch.h index 24501d61..9dea8de8 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -898,6 +898,14 @@ struct Arch : BaseCtx delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } float getDelayNS(delay_t v) const { return v * 0.001; } + + DelayInfo getDelayFromNS(float ns) const + { + DelayInfo del; + del.delay = ns; + return del; + } + uint32_t getDelayChecksum(delay_t v) const { return v; } bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const; @@ -922,7 +930,9 @@ struct Arch : BaseCtx // if no path exists bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const; // Get the port class, also setting clockDomain if applicable - TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, IdString &clockDomain) const; + TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const; + // Get the TimingClockingInfo of a port + TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; From fa3e390e5fe07412a3cd29e740c5a90f323c75fb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Nov 2018 14:43:21 -0800 Subject: [PATCH 104/174] Add TODO --- xc7/arch.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xc7/arch.cc b/xc7/arch.cc index 4ef66aa7..c47f7cc2 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -296,6 +296,7 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector &wir if (tw.isUndefined()) continue; arcs.clear(); + // TODO // const_cast(ddb).expandSegmentSources(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true // /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); From ab9cb99f52f55d32273d0aeef20a7fb60ea644d5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Nov 2018 14:52:01 -0800 Subject: [PATCH 105/174] Arch::getPipDelay() returns delay of dst wire; Arch::getWireDelay() to return nothing --- xc7/arch.h | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/xc7/arch.h b/xc7/arch.h index 9dea8de8..9e687146 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -688,7 +688,7 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } - DelayInfo getWireDelay(WireId wire) const { return torc_info->wire_to_delay[wire.index]; } + DelayInfo getWireDelay(WireId wire) const { return {}; } BelPinRange getWireBelPins(WireId wire) const { @@ -839,13 +839,9 @@ struct Arch : BaseCtx DelayInfo getPipDelay(PipId pip) const { - DelayInfo delay; NPNR_ASSERT(pip != PipId()); - // if (fast_part) - // delay.delay = chip_info->pip_data[pip.index].fast_delay; - // else - // delay.delay = chip_info->pip_data[pip.index].slow_delay; - return delay; + auto wire = getPipDstWire(pip); + return torc_info->wire_to_delay[wire.index]; } PipRange getPipsDownhill(WireId wire) const From c3dc8696eb2f2310f6973f55e479742cda3e3730 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Nov 2018 15:00:09 -0800 Subject: [PATCH 106/174] Fix getDelayFromNS() --- xc7/arch.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.h b/xc7/arch.h index 9e687146..c64b9634 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -898,7 +898,7 @@ struct Arch : BaseCtx DelayInfo getDelayFromNS(float ns) const { DelayInfo del; - del.delay = ns; + del.delay = delay_t(ns * 1000); return del; } From fc015d28d3063a92af1397f8377ce93ac4a6ec1b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 20 Nov 2018 17:41:46 -0800 Subject: [PATCH 107/174] Fix pip indexing, do not allow fabric to connect to CLK (only global network can) --- xc7/arch.cc | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index c47f7cc2..6be6bbc9 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -264,14 +264,17 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector &wir !clb /* inUseRoutethrough */); auto index = pip_to_arc.size(); - pip_to_arc.insert(pip_to_arc.end(), arcs.begin(), arcs.end()); const boost::regex bufg_i("(CMT|CLK)_BUFG_BUFGCTRL\\d+_I0"); const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); + const boost::regex int_clk("CLK(_L)?[01]"); + const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); auto &pips = wire_to_pips_downhill[i]; pips.reserve(arcs.size()); const bool clk_tile = boost::starts_with(tileTypeName, "CMT") || boost::starts_with(tileTypeName, "CLK"); + const bool int_tile = boost::starts_with(tileTypeName, "INT"); + for (const auto &a : arcs) { // Disable BUFG I0 -> O routethrough if (clk_tile) { @@ -282,7 +285,17 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector &wir continue; } } + // Disable CLK inputs from being driven from the fabric (must be from global clock network) + else if (int_tile) { + ewi.set(a.getSinkTilewire()); + if (boost::regex_match(ewi.mWireName, int_clk)) { + ewi.set(a.getSourceTilewire()); + if (!boost::regex_match(ewi.mWireName, gclk)) + continue; + } + } pips.push_back(index); + pip_to_arc.emplace_back(a); arc_to_pip.emplace(a, index); ++index; } @@ -335,6 +348,12 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported XC7 chip type.\n"); } + /*if (getCtx()->verbose)*/ { + log_info("Number of bels: %d\n", torc_info->num_bels); + log_info("Number of wires: %d\n", torc_info->num_wires); + log_info("Number of pips: %d\n", torc_info->num_pips); + } + // package_info = nullptr; // for (int i = 0; i < chip_info->num_packages; i++) { // if (chip_info->packages_data[i].name.get() == args.package) { From ae9ccfa5adf42223ddf393fa323c30098716017a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 12:28:21 -0800 Subject: [PATCH 108/174] Refactor torc_info constructor --- xc7/arch.cc | 337 ++++++++++++++++++++-------------------------------- xc7/arch.h | 29 ++--- 2 files changed, 142 insertions(+), 224 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 6be6bbc9..04464501 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -35,110 +35,77 @@ NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), - segments(ddb->getSegments()), bel_to_site_index(construct_bel_to_site_index(ctx, sites)), - num_bels(bel_to_site_index.size()), - site_index_to_bel(construct_site_index_to_bel(ctx, sites, bel_to_site_index)), - site_index_to_type(construct_site_index_to_type(ctx, sites)), - bel_to_loc(construct_bel_to_loc(sites, tiles, num_bels, site_index_to_type)), - wire_to_tilewire(construct_wire_to_tilewire(segments, tiles, segment_to_wire, trivial_to_wire)), - num_wires(wire_to_tilewire.size()), wire_to_delay(construct_wire_to_delay(tiles, wire_to_tilewire, *ddb)), - pip_to_arc(construct_pip_to_arc(wire_to_tilewire, *ddb, wire_to_pips_uphill, wire_to_pips_downhill)), - num_pips(pip_to_arc.size()) + segments(ddb->getSegments()) { - pip_to_dst_wire.reserve(num_pips); - - for (const auto &arc : pip_to_arc) { - const auto &tw = arc.getSinkTilewire(); - pip_to_dst_wire.push_back(tilewire_to_wire(tw)); - } -} -std::vector TorcInfo::construct_bel_to_site_index(Arch *ctx, const Sites &sites) -{ - std::vector bel_to_site_index; - bel_to_site_index.reserve(sites.getSiteCount()); + bel_to_site_index.reserve(sites.getSiteCount()*4); + bel_to_loc.reserve(sites.getSiteCount()*4); + site_index_to_bel.resize(sites.getSiteCount()); + site_index_to_type.resize(sites.getSiteCount()); + BelId b; + b.index = 0; for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { - const auto &s = sites.getSite(i); - const auto &pd = s.getPrimitiveDefPtr(); + const auto &site = sites.getSite(i); + const auto &pd = site.getPrimitiveDefPtr(); const auto &type = pd->getName(); + const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); + const auto x = (tile_info.getCol() + 1) / 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs + const auto y = tile_info.getRow(); if (type == "SLICEL" || type == "SLICEM") { bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); - } else - bel_to_site_index.push_back(i); - } - return bel_to_site_index; -} -std::vector TorcInfo::construct_site_index_to_bel(Arch *ctx, const Sites &sites, const std::vector &bel_to_site_index) -{ - std::vector site_index_to_bel; - site_index_to_bel.resize(sites.getSiteCount()); - BelId b; - b.index = 0; - for (auto i : bel_to_site_index) { - site_index_to_bel[i] = b; - ++b.index; - } - return site_index_to_bel; -} -std::vector TorcInfo::construct_site_index_to_type(Arch *ctx, const Sites &sites) -{ - std::vector site_index_to_type; - site_index_to_type.resize(sites.getSiteCount()); - for (SiteIndex i(0); i < sites.getSiteCount(); ++i) { - const auto &s = sites.getSite(i); - const auto &pd = s.getPrimitiveDefPtr(); - const auto &type = pd->getName(); - if (type == "SLICEL" || type == "SLICEM") site_index_to_type[i] = id_SLICE_LUT6; - else if (type == "IOB33S" || type == "IOB33M") - site_index_to_type[i] = id_IOB33; - else - site_index_to_type[i] = ctx->id(type); - } - return site_index_to_type; -} -std::vector TorcInfo::construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, - const std::vector &site_index_to_type) -{ - std::vector bel_to_loc; - bel_to_loc.resize(num_bels); - int32_t bel_index = 0; - for (SiteIndex i(0); i < site_index_to_type.size(); ++i) { - const auto &site = sites.getSite(i); - const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); - const auto x = (tile_info.getCol() + 1) / 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs - const auto y = tile_info.getRow(); - - if (site_index_to_type[i] == id_SLICE_LUT6) { const auto site_name = site.getName(); const auto site_name_back = site_name.back(); if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || site_name_back == '8') { - bel_to_loc[bel_index++] = Loc(x, y, 0); - bel_to_loc[bel_index++] = Loc(x, y, 1); - bel_to_loc[bel_index++] = Loc(x, y, 2); - bel_to_loc[bel_index++] = Loc(x, y, 3); + bel_to_loc.emplace_back(x, y, 0); + bel_to_loc.emplace_back(x, y, 1); + bel_to_loc.emplace_back(x, y, 2); + bel_to_loc.emplace_back(x, y, 3); } else { - bel_to_loc[bel_index++] = Loc(x, y, 4); - bel_to_loc[bel_index++] = Loc(x, y, 5); - bel_to_loc[bel_index++] = Loc(x, y, 6); - bel_to_loc[bel_index++] = Loc(x, y, 7); + bel_to_loc.emplace_back(x, y, 4); + bel_to_loc.emplace_back(x, y, 5); + bel_to_loc.emplace_back(x, y, 6); + bel_to_loc.emplace_back(x, y, 7); } - } else - bel_to_loc[bel_index++] = Loc(x, y, 0); + site_index_to_bel[i] = b; + b.index += 4; + } else if (type == "IOB33S" || type == "IOB33M") { + bel_to_site_index.push_back(i); + site_index_to_type[i] = id_IOB33; + bel_to_loc.emplace_back(x, y, 0); + site_index_to_bel[i] = b; + ++b.index; + } else { + bel_to_site_index.push_back(i); + site_index_to_type[i] = ctx->id(type); + bel_to_loc.emplace_back(x, y, 0); + site_index_to_bel[i] = b; + ++b.index; + } } - return bel_to_loc; -} -std::vector -TorcInfo::construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, - std::unordered_map &segment_to_wire, - std::unordered_map &trivial_to_wire) -{ - std::vector wire_to_tilewire; + num_bels = bel_to_site_index.size(); + bel_to_site_index.shrink_to_fit(); + bel_to_loc.shrink_to_fit(); + const boost::regex re_124("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); + const boost::regex re_L("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); + const boost::regex re_BYP("BYP(_ALT)?\\d"); + const boost::regex re_BYP_B("BYP_[BL]\\d"); + const boost::regex re_BOUNCE_NS("(BYP|FAN)_BOUNCE_[NS]3_\\d"); + const boost::regex re_FAN("FAN(_ALT)?\\d"); + const boost::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); + const boost::regex bufg_i("(CMT|CLK)_BUFG_BUFGCTRL\\d+_I0"); + const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); + const boost::regex int_clk("CLK(_L)?[01]"); + const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); + std::unordered_map> delay_lookup; Tilewire currentTilewire; + boost::cmatch what; + WireId w; + w.index = 0; for (TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { // iterate over every wire in the tile const auto &tileInfo = tiles.getTileInfo(tileIndex); @@ -157,120 +124,85 @@ TorcInfo::construct_wire_to_tilewire(const Segments &segments, const Tiles &tile trivial_to_wire.emplace(currentTilewire, wire_to_tilewire.size()); wire_to_tilewire.push_back(currentTilewire); - } - } - wire_to_tilewire.shrink_to_fit(); - return wire_to_tilewire; -} -std::vector TorcInfo::construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, const DDB &ddb) -{ - std::vector wire_to_delay; - wire_to_delay.reserve(wire_to_tilewire.size()); - - const boost::regex re_124 = boost::regex("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); - const boost::regex re_L = boost::regex("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); - const boost::regex re_BYP = boost::regex("BYP(_ALT)?\\d"); - const boost::regex re_BYP_B = boost::regex("BYP_[BL]\\d"); - const boost::regex re_BOUNCE_NS = boost::regex("(BYP|FAN)_BOUNCE_[NS]3_\\d"); - const boost::regex re_FAN = boost::regex("FAN(_ALT)?\\d"); - const boost::regex re_CLB_I1_6 = boost::regex("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); - - std::unordered_map> delay_lookup; - - boost::cmatch what; - for (const auto &tw : wire_to_tilewire) { - const TileInfo& tileInfo = tiles.getTileInfo(tw.getTileIndex()); - auto tile_type_index = tileInfo.getTypeIndex(); - - auto it = delay_lookup.find(tile_type_index); - if (it == delay_lookup.end()) { - auto wireCount = tiles.getWireCount(tile_type_index); - std::vector tile_delays(wireCount); - for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { - const WireInfo& wireInfo = tiles.getWireInfo(tile_type_index, wireIndex); - auto wire_name = wireInfo.getName(); - if (boost::regex_match(wire_name, what, re_124)) { - switch (what.str(2)[0]) { - case '1': tile_delays[wireIndex] = 150; break; - case '2': tile_delays[wireIndex] = 170; break; - case '4': tile_delays[wireIndex] = 210; break; - case '6': tile_delays[wireIndex] = 210; break; - default: throw; - } - } else if (boost::regex_match(wire_name, what, re_L)) { - std::string l(what[2]); - if (l == "H") - tile_delays[wireIndex] = 360; - else if (l == "VB") - tile_delays[wireIndex] = 300; - else if (l == "V") - tile_delays[wireIndex] = 350; - else - throw; - } else if (boost::regex_match(wire_name, what, re_BYP)) { - tile_delays[wireIndex] = 190; - } else if (boost::regex_match(wire_name, what, re_BYP_B)) { - } else if (boost::regex_match(wire_name, what, re_FAN)) { - tile_delays[wireIndex] = 190; - } else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) { - switch (what.str(2)[0]) { - case '1': tile_delays[wireIndex] = 280; break; - case '2': tile_delays[wireIndex] = 280; break; - case '3': tile_delays[wireIndex] = 180; break; - case '4': tile_delays[wireIndex] = 180; break; - case '5': tile_delays[wireIndex] = 80; break; - case '6': tile_delays[wireIndex] = 40; break; + auto it = delay_lookup.find(tileTypeIndex); + if (it == delay_lookup.end()) { + auto wireCount = tiles.getWireCount(tileTypeIndex); + std::vector tile_delays(wireCount); + for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { + const WireInfo& wireInfo = tiles.getWireInfo(tileTypeIndex, wireIndex); + auto wire_name = wireInfo.getName(); + if (boost::regex_match(wire_name, what, re_124)) { + switch (what.str(2)[0]) { + case '1': tile_delays[wireIndex] = 150; break; + case '2': tile_delays[wireIndex] = 170; break; + case '4': tile_delays[wireIndex] = 210; break; + case '6': tile_delays[wireIndex] = 210; break; default: throw; + } + } else if (boost::regex_match(wire_name, what, re_L)) { + std::string l(what[2]); + if (l == "H") + tile_delays[wireIndex] = 360; + else if (l == "VB") + tile_delays[wireIndex] = 300; + else if (l == "V") + tile_delays[wireIndex] = 350; + else + throw; + } else if (boost::regex_match(wire_name, what, re_BYP)) { + tile_delays[wireIndex] = 190; + } else if (boost::regex_match(wire_name, what, re_BYP_B)) { + } else if (boost::regex_match(wire_name, what, re_FAN)) { + tile_delays[wireIndex] = 190; + } else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) { + switch (what.str(2)[0]) { + case '1': tile_delays[wireIndex] = 280; break; + case '2': tile_delays[wireIndex] = 280; break; + case '3': tile_delays[wireIndex] = 180; break; + case '4': tile_delays[wireIndex] = 180; break; + case '5': tile_delays[wireIndex] = 80; break; + case '6': tile_delays[wireIndex] = 40; break; + default: throw; + } } } + it = delay_lookup.emplace(tileTypeIndex, std::move(tile_delays)).first; } - it = delay_lookup.emplace(tile_type_index, std::move(tile_delays)).first; + assert(it != delay_lookup.end()); + + DelayInfo d; + d.delay = it->second[currentTilewire.getWireIndex()]; + wire_to_delay.emplace_back(std::move(d)); } - assert(it != delay_lookup.end()); - DelayInfo d; - d.delay = it->second[tw.getWireIndex()]; - wire_to_delay.emplace_back(std::move(d)); } + wire_to_tilewire.shrink_to_fit(); + wire_to_delay.shrink_to_fit(); + num_wires = wire_to_tilewire.size(); - return wire_to_delay; -} -std::vector TorcInfo::construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, - std::vector> &wire_to_pips_uphill, - std::vector> &wire_to_pips_downhill) -{ - const auto &tiles = ddb.getTiles(); - - std::vector pip_to_arc; - wire_to_pips_downhill.resize(wire_to_tilewire.size()); - - std::unordered_map arc_to_pip; - + wire_to_pips_downhill.resize(num_wires); + //std::unordered_map arc_to_pip; ArcVector arcs; - ExtendedWireInfo ewi(ddb); - for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { - const auto &tw = wire_to_tilewire[i]; - if (tw.isUndefined()) + ExtendedWireInfo ewi(*ddb); + PipId p; + p.index = 0; + for (w.index = 0; w.index < num_wires; ++w.index) { + const auto ¤tTilewire = wire_to_tilewire[w.index]; + if (currentTilewire.isUndefined()) continue; arcs.clear(); - const auto &tileInfo = tiles.getTileInfo(tw.getTileIndex()); + const auto &tileInfo = tiles.getTileInfo(currentTilewire.getTileIndex()); const auto tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); const bool clb = boost::starts_with( tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) - const_cast(ddb).expandSegmentSinks(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, - true /*inUseRegular */, true /* inUseIrregular */, - !clb /* inUseRoutethrough */); + arcs.clear(); + const_cast(*ddb).expandSegmentSinks(currentTilewire, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, + true /*inUseRegular */, true /* inUseIrregular */, + !clb /* inUseRoutethrough */); - auto index = pip_to_arc.size(); - - const boost::regex bufg_i("(CMT|CLK)_BUFG_BUFGCTRL\\d+_I0"); - const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); - const boost::regex int_clk("CLK(_L)?[01]"); - const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); - - auto &pips = wire_to_pips_downhill[i]; + auto &pips = wire_to_pips_downhill[w.index]; pips.reserve(arcs.size()); const bool clk_tile = boost::starts_with(tileTypeName, "CMT") || boost::starts_with(tileTypeName, "CLK"); const bool int_tile = boost::starts_with(tileTypeName, "INT"); @@ -294,38 +226,23 @@ std::vector TorcInfo::construct_pip_to_arc(const std::vector &wir continue; } } - pips.push_back(index); + pips.push_back(p.index); pip_to_arc.emplace_back(a); - arc_to_pip.emplace(a, index); - ++index; + //arc_to_pip.emplace(a, p.index); + const auto &tw = a.getSinkTilewire(); + pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); + ++p.index; } + pips.shrink_to_fit(); } - pip_to_arc.shrink_to_fit(); - - wire_to_pips_uphill.resize(wire_to_tilewire.size()); - for (auto i = 0u; i < wire_to_tilewire.size(); ++i) { - const auto &tw = wire_to_tilewire[i]; - if (tw.isUndefined()) - continue; - arcs.clear(); - // TODO - // const_cast(ddb).expandSegmentSources(tw, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, true - // /*inUseRegular */, true /* inUseIrregular */, false /* inUseRoutethrough */); - - auto &pips = wire_to_pips_uphill[i]; - pips.reserve(arcs.size()); - for (const auto &a : arcs) - pips.push_back(arc_to_pip.at(a)); + num_pips = pip_to_arc.size(); + + pip_to_dst_wire.reserve(num_pips); + for (const auto &arc : pip_to_arc) { + const auto &tw = arc.getSinkTilewire(); + pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); } - - return pip_to_arc; -} - -std::vector construct_pip_to_dst_wire(const std::vector &pip_to_arc) -{ - std::vector pip_to_wire; - return pip_to_wire; } // ----------------------------------------------------------------------- diff --git a/xc7/arch.h b/xc7/arch.h index c64b9634..1847607b 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -305,23 +305,24 @@ struct TorcInfo return trivial_to_wire.at(tw); } - const std::vector bel_to_site_index; - const int num_bels; - const std::vector site_index_to_bel; - const std::vector site_index_to_type; - const std::vector bel_to_loc; + std::vector bel_to_site_index; + int num_bels; + std::vector site_index_to_bel; + std::vector site_index_to_type; + std::vector bel_to_loc; std::unordered_map segment_to_wire; std::unordered_map trivial_to_wire; - const std::vector wire_to_tilewire; - const int num_wires; - const std::vector wire_to_delay; + std::vector wire_to_tilewire; + int num_wires; + std::vector wire_to_delay; std::vector> wire_to_pips_uphill; std::vector> wire_to_pips_downhill; - const std::vector pip_to_arc; - const int num_pips; + std::vector pip_to_arc; + int num_pips; std::vector pip_to_dst_wire; private: + void _construct(); static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); static std::vector construct_site_index_to_bel(Arch *ctx, const Sites &sites, const std::vector &bel_to_site_index); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); @@ -858,10 +859,10 @@ struct Arch : BaseCtx PipRange getPipsUphill(WireId wire) const { PipRange range; - NPNR_ASSERT(wire != WireId()); - const auto &pips = torc_info->wire_to_pips_uphill[wire.index]; - range.b.cursor = pips.data(); - range.e.cursor = range.b.cursor + pips.size(); + //NPNR_ASSERT(wire != WireId()); + //const auto &pips = torc_info->wire_to_pips_uphill[wire.index]; + //range.b.cursor = pips.data(); + //range.e.cursor = range.b.cursor + pips.size(); return range; } From a0b6d3b19b7f2751d3b52afbc3b4df3dd0344d36 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 12:28:48 -0800 Subject: [PATCH 109/174] clangformat --- xc7/arch.cc | 113 +++++++++++++++++++++++++++++---------------------- xc7/arch.h | 25 +++++------- xc7/delay.cc | 17 ++++---- xc7/xdl.cc | 2 +- 4 files changed, 83 insertions(+), 74 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 04464501..b0be78eb 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -37,8 +37,8 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()) { - bel_to_site_index.reserve(sites.getSiteCount()*4); - bel_to_loc.reserve(sites.getSiteCount()*4); + bel_to_site_index.reserve(sites.getSiteCount() * 4); + bel_to_loc.reserve(sites.getSiteCount() * 4); site_index_to_bel.resize(sites.getSiteCount()); site_index_to_type.resize(sites.getSiteCount()); BelId b; @@ -48,7 +48,8 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string const auto &pd = site.getPrimitiveDefPtr(); const auto &type = pd->getName(); const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); - const auto x = (tile_info.getCol() + 1) / 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs + const auto x = (tile_info.getCol() + 1) / + 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs const auto y = tile_info.getRow(); if (type == "SLICEL" || type == "SLICEM") { bel_to_site_index.push_back(i); @@ -101,7 +102,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); const boost::regex int_clk("CLK(_L)?[01]"); const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); - std::unordered_map> delay_lookup; + std::unordered_map> delay_lookup; Tilewire currentTilewire; boost::cmatch what; WireId w; @@ -130,15 +131,24 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string auto wireCount = tiles.getWireCount(tileTypeIndex); std::vector tile_delays(wireCount); for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { - const WireInfo& wireInfo = tiles.getWireInfo(tileTypeIndex, wireIndex); + const WireInfo &wireInfo = tiles.getWireInfo(tileTypeIndex, wireIndex); auto wire_name = wireInfo.getName(); if (boost::regex_match(wire_name, what, re_124)) { switch (what.str(2)[0]) { - case '1': tile_delays[wireIndex] = 150; break; - case '2': tile_delays[wireIndex] = 170; break; - case '4': tile_delays[wireIndex] = 210; break; - case '6': tile_delays[wireIndex] = 210; break; - default: throw; + case '1': + tile_delays[wireIndex] = 150; + break; + case '2': + tile_delays[wireIndex] = 170; + break; + case '4': + tile_delays[wireIndex] = 210; + break; + case '6': + tile_delays[wireIndex] = 210; + break; + default: + throw; } } else if (boost::regex_match(wire_name, what, re_L)) { std::string l(what[2]); @@ -157,13 +167,26 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string tile_delays[wireIndex] = 190; } else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) { switch (what.str(2)[0]) { - case '1': tile_delays[wireIndex] = 280; break; - case '2': tile_delays[wireIndex] = 280; break; - case '3': tile_delays[wireIndex] = 180; break; - case '4': tile_delays[wireIndex] = 180; break; - case '5': tile_delays[wireIndex] = 80; break; - case '6': tile_delays[wireIndex] = 40; break; - default: throw; + case '1': + tile_delays[wireIndex] = 280; + break; + case '2': + tile_delays[wireIndex] = 280; + break; + case '3': + tile_delays[wireIndex] = 180; + break; + case '4': + tile_delays[wireIndex] = 180; + break; + case '5': + tile_delays[wireIndex] = 80; + break; + case '6': + tile_delays[wireIndex] = 40; + break; + default: + throw; } } } @@ -181,7 +204,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string num_wires = wire_to_tilewire.size(); wire_to_pips_downhill.resize(num_wires); - //std::unordered_map arc_to_pip; + // std::unordered_map arc_to_pip; ArcVector arcs; ExtendedWireInfo ewi(*ddb); PipId p; @@ -198,9 +221,9 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) arcs.clear(); - const_cast(*ddb).expandSegmentSinks(currentTilewire, arcs, DDB::eExpandDirectionNone, false /* inUseTied */, - true /*inUseRegular */, true /* inUseIrregular */, - !clb /* inUseRoutethrough */); + const_cast(*ddb).expandSegmentSinks(currentTilewire, arcs, DDB::eExpandDirectionNone, + false /* inUseTied */, true /*inUseRegular */, + true /* inUseIrregular */, !clb /* inUseRoutethrough */); auto &pips = wire_to_pips_downhill[w.index]; pips.reserve(arcs.size()); @@ -228,7 +251,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string } pips.push_back(p.index); pip_to_arc.emplace_back(a); - //arc_to_pip.emplace(a, p.index); + // arc_to_pip.emplace(a, p.index); const auto &tw = a.getSinkTilewire(); pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); ++p.index; @@ -237,7 +260,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string } pip_to_arc.shrink_to_fit(); num_pips = pip_to_arc.size(); - + pip_to_dst_wire.reserve(num_pips); for (const auto &arc : pip_to_arc) { const auto &tw = arc.getSinkTilewire(); @@ -411,8 +434,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const throw; } } - } - else if (bel_type == id_PS7) { + } else if (bel_type == id_PS7) { // e.g. Convert DDRARB[0] -> DDRARB0 boost::erase_all(pin_name, "["); boost::erase_all(pin_name, "]"); @@ -560,28 +582,25 @@ IdString Arch::getPipName(PipId pip) const pip_name << ewi_src.mTileName << "." << ewi_src.mWireName << ".->." << ewi_dst.mWireName; return id(pip_name.str()); -//#if 1 -// int x = chip_info->pip_data[pip.index].x; -// int y = chip_info->pip_data[pip.index].y; -// -// std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); -// std::replace(src_name.begin(), src_name.end(), '/', '.'); -// -// std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); -// std::replace(dst_name.begin(), dst_name.end(), '/', '.'); -// -// return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); -//#else -// return id(chip_info->pip_data[pip.index].name.get()); -//#endif + //#if 1 + // int x = chip_info->pip_data[pip.index].x; + // int y = chip_info->pip_data[pip.index].y; + // + // std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + // std::replace(src_name.begin(), src_name.end(), '/', '.'); + // + // std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + // std::replace(dst_name.begin(), dst_name.end(), '/', '.'); + // + // return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); + //#else + // return id(chip_info->pip_data[pip.index].name.get()); + //#endif } // ----------------------------------------------------------------------- -BelId Arch::getPackagePinBel(const std::string &pin) const -{ - return getBelByName(id(pin)); -} +BelId Arch::getPackagePinBel(const std::string &pin) const { return getBelByName(id(pin)); } std::string Arch::getBelPackagePin(BelId bel) const { @@ -732,10 +751,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } -bool Arch::route() -{ - return router1(getCtx(), Router1Cfg(getCtx())); -} +bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } // ----------------------------------------------------------------------- @@ -974,8 +990,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in if (port == id_O) return TMG_COMB_OUTPUT; return TMG_COMB_INPUT; - } - else if (cell->type == id_PS7) { + } else if (cell->type == id_PS7) { // TODO return TMG_IGNORE; } diff --git a/xc7/arch.h b/xc7/arch.h index 1847607b..d14ab9df 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -324,7 +324,8 @@ struct TorcInfo private: void _construct(); static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); - static std::vector construct_site_index_to_bel(Arch *ctx, const Sites &sites, const std::vector &bel_to_site_index); + static std::vector construct_site_index_to_bel(Arch *ctx, const Sites &sites, + const std::vector &bel_to_site_index); static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, const std::vector &site_index_to_type); @@ -332,8 +333,8 @@ struct TorcInfo construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, std::unordered_map &segment_to_wire, std::unordered_map &trivial_to_wire); - static std::vector construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, - const DDB &ddb); + static std::vector + construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, const DDB &ddb); static std::vector construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, std::vector> &wire_to_pips_uphill, std::vector> &wire_to_pips_downhill); @@ -678,10 +679,7 @@ struct Arch : BaseCtx return wire_to_net[wire.index]; } - WireId getConflictingWireWire(WireId wire) const - { - return wire; - } + WireId getConflictingWireWire(WireId wire) const { return wire; } NetInfo *getConflictingWireNet(WireId wire) const { @@ -779,10 +777,7 @@ struct Arch : BaseCtx return pip_to_net[pip.index]; } - WireId getConflictingPipWire(PipId pip) const - { - return WireId(); - } + WireId getConflictingPipWire(PipId pip) const { return WireId(); } NetInfo *getConflictingPipNet(PipId pip) const { @@ -859,10 +854,10 @@ struct Arch : BaseCtx PipRange getPipsUphill(WireId wire) const { PipRange range; - //NPNR_ASSERT(wire != WireId()); - //const auto &pips = torc_info->wire_to_pips_uphill[wire.index]; - //range.b.cursor = pips.data(); - //range.e.cursor = range.b.cursor + pips.size(); + // NPNR_ASSERT(wire != WireId()); + // const auto &pips = torc_info->wire_to_pips_uphill[wire.index]; + // range.b.cursor = pips.data(); + // range.e.cursor = range.b.cursor + pips.size(); return range; } diff --git a/xc7/delay.cc b/xc7/delay.cc index 3bef3dfc..0df02f7e 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,7 +104,8 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - auto abs_delta_x = (abs(src_info.getCol() - dst_info.getCol()) + 1)/ 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs + auto abs_delta_x = (abs(src_info.getCol() - dst_info.getCol()) + 1) / + 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); #if 1 auto div_LH = std::div(abs_delta_x, 12); @@ -118,10 +119,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const auto div_V2 = std::div(div_V4.rem, 2); auto num_H1 = div_H2.rem; auto num_V1 = div_V2.rem; - return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 - + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 - + (div_H2.quot + div_V2.quot) * 170 - + (num_H1 + num_V1) * 150; + return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + + (num_H1 + num_V1) * 150; #else return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); #endif @@ -146,10 +146,9 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto div_V2 = std::div(div_V4.rem, 2); auto num_H1 = div_H2.rem; auto num_V1 = div_V2.rem; - return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 - + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 - + (div_H2.quot + div_V2.quot) * 170 - + (num_H1 + num_V1) * 150; + return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + + (num_H1 + num_V1) * 150; #else return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); #endif diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 97a18538..32546490 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -136,7 +136,7 @@ void write_xdl(const Context *ctx, std::ostream &out) NPNR_ASSERT(init.size() == (1u << lut_inputs.size())); unsigned n = 0; for (unsigned i = 0; i < init.size(); ++i) { - if (init[init.size()-1-i] == '0') + if (init[init.size() - 1 - i] == '0') continue; if (n++ > 0) value += "+"; From 662733c171738d051da78ed74c72d3f117d89b08 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 14:12:25 -0800 Subject: [PATCH 110/174] Remove methods --- xc7/arch.cc | 13 ++++++++----- xc7/arch.h | 18 ------------------ 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index b0be78eb..ae138513 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -37,6 +37,8 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), segments(ddb->getSegments()) { + static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); + boost::cmatch what; bel_to_site_index.reserve(sites.getSiteCount() * 4); bel_to_loc.reserve(sites.getSiteCount() * 4); site_index_to_bel.resize(sites.getSiteCount()); @@ -47,10 +49,12 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string const auto &site = sites.getSite(i); const auto &pd = site.getPrimitiveDefPtr(); const auto &type = pd->getName(); - const auto &tile_info = tiles.getTileInfo(site.getTileIndex()); - const auto x = (tile_info.getCol() + 1) / - 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs - const auto y = tile_info.getRow(); + const auto &tileInfo = tiles.getTileInfo(site.getTileIndex()); + if (!boost::regex_match(tileInfo.getName(), what, re_loc)) + throw; + const auto x = boost::lexical_cast(what.str(1)); + const auto y = boost::lexical_cast(what.str(2)); + if (type == "SLICEL" || type == "SLICEM") { bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); @@ -104,7 +108,6 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); std::unordered_map> delay_lookup; Tilewire currentTilewire; - boost::cmatch what; WireId w; w.index = 0; for (TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { diff --git a/xc7/arch.h b/xc7/arch.h index d14ab9df..410bf8b1 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -320,24 +320,6 @@ struct TorcInfo std::vector pip_to_arc; int num_pips; std::vector pip_to_dst_wire; - - private: - void _construct(); - static std::vector construct_bel_to_site_index(Arch *ctx, const Sites &sites); - static std::vector construct_site_index_to_bel(Arch *ctx, const Sites &sites, - const std::vector &bel_to_site_index); - static std::vector construct_site_index_to_type(Arch *ctx, const Sites &sites); - static std::vector construct_bel_to_loc(const Sites &sites, const Tiles &tiles, const int num_bels, - const std::vector &site_index_to_type); - static std::vector - construct_wire_to_tilewire(const Segments &segments, const Tiles &tiles, - std::unordered_map &segment_to_wire, - std::unordered_map &trivial_to_wire); - static std::vector - construct_wire_to_delay(const Tiles &tiles, const std::vector &wire_to_tilewire, const DDB &ddb); - static std::vector construct_pip_to_arc(const std::vector &wire_to_tilewire, const DDB &ddb, - std::vector> &wire_to_pips_uphill, - std::vector> &wire_to_pips_downhill); }; extern std::unique_ptr torc_info; From 440802bf9d9eb8f811e1ee5df8e44c7e4dc1a239 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 17:55:31 -0800 Subject: [PATCH 111/174] Add support for serialization of torc_info --- xc7/arch.cc | 171 +++++++++++++++++++++++++++++++++++++++++++---- xc7/arch.h | 58 ++++++++++------ xc7/family.cmake | 2 + 3 files changed, 199 insertions(+), 32 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ae138513..f9d56185 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -28,14 +28,30 @@ #include "router1.h" #include "util.h" +#include +#include +#include +#include +#include +struct nextpnr_binary_iarchive : public boost::archive::binary_iarchive { + nextpnr_binary_iarchive(std::ifstream &ifs, NEXTPNR_NAMESPACE::BaseCtx* ctx, const std::string& inDeviceName, const std::string& inPackageName) : boost::archive::binary_iarchive(ifs), ctx(ctx), inDeviceName(inDeviceName), inPackageName(inPackageName) {} + NEXTPNR_NAMESPACE::BaseCtx *ctx; + std::string inDeviceName, inPackageName; +}; +struct nextpnr_binary_oarchive : public boost::archive::binary_oarchive { + nextpnr_binary_oarchive(std::ofstream &ofs, NEXTPNR_NAMESPACE::BaseCtx* ctx) : boost::archive::binary_oarchive(ofs), ctx(ctx) {} + NEXTPNR_NAMESPACE::BaseCtx *ctx; +}; + #include "torc/common/DirectoryTree.hpp" +//#define TORC_INFO_DB "torc_info.ar" + NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; -TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName) - : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), - segments(ddb->getSegments()) +TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::string &inPackageName) + : TorcInfo(inDeviceName, inPackageName) { static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); boost::cmatch what; @@ -123,9 +139,9 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string if (!currentSegment.isTrivial()) { if (currentSegment.getAnchorTileIndex() != tileIndex) continue; - segment_to_wire.emplace(currentSegment, wire_to_tilewire.size()); + segment_to_wire.emplace(currentSegment, w); } else - trivial_to_wire.emplace(currentTilewire, wire_to_tilewire.size()); + trivial_to_wire.emplace(currentTilewire, w); wire_to_tilewire.push_back(currentTilewire); @@ -200,6 +216,8 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string DelayInfo d; d.delay = it->second[currentTilewire.getWireIndex()]; wire_to_delay.emplace_back(std::move(d)); + + ++w.index; } } wire_to_tilewire.shrink_to_fit(); @@ -252,7 +270,7 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string continue; } } - pips.push_back(p.index); + pips.emplace_back(p); pip_to_arc.emplace_back(a); // arc_to_pip.emplace(a, p.index); const auto &tw = a.getSinkTilewire(); @@ -270,6 +288,11 @@ TorcInfo::TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); } } +TorcInfo::TorcInfo(const std::string& inDeviceName, const std::string &inPackageName) + : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), + segments(ddb->getSegments()) +{ +} // ----------------------------------------------------------------------- @@ -286,11 +309,31 @@ Arch::Arch(ArchArgs args) : args(args) { torc::common::DirectoryTree directoryTree("/opt/torc/src/torc"); if (args.type == ArchArgs::Z020) { - torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", args.package)); +#ifdef TORC_INFO_DB + std::ifstream ifs(TORC_INFO_DB, std::ios::binary); + if (ifs) { + nextpnr_binary_iarchive ia(ifs, this, "xc7z020", args.package); + ia >> torc_info; + std::cout << ifs.tellg() << std::endl; + } else +#endif + { + torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", args.package)); +#ifdef TORC_INFO_DB + std::ofstream ofs(TORC_INFO_DB, std::ios::binary); + if (ofs) { + nextpnr_binary_oarchive oa(ofs, this); + oa << torc_info; + ofs.flush(); + std::cout << ofs.tellp() << std::endl; + } + } +#endif } else { log_error("Unsupported XC7 chip type.\n"); } + /*if (getCtx()->verbose)*/ { log_info("Number of bels: %d\n", torc_info->num_bels); log_info("Number of wires: %d\n", torc_info->num_wires); @@ -409,8 +452,6 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const WireId Arch::getBelPinWire(BelId bel, IdString pin) const { - WireId ret; - auto pin_name = pin.str(this); auto bel_type = getBelType(bel); if (bel_type == id_SLICE_LUT6) { @@ -451,7 +492,7 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const log_error("no wire found for site '%s' pin '%s' \n", torc_info->bel_to_name(bel.index).c_str(), pin_name.c_str()); - ret.index = torc_info->tilewire_to_wire(tw); + return torc_info->tilewire_to_wire(tw); // NPNR_ASSERT(bel != BelId()); // @@ -479,8 +520,8 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const // b = i + 1; // } // } - - return ret; + // + //return ret; } std::vector Arch::getBelPins(BelId bel) const @@ -1075,3 +1116,109 @@ void Arch::assignCellInfo(CellInfo *cell) } NEXTPNR_NAMESPACE_END + +// outside of any namespace +BOOST_SERIALIZATION_SPLIT_FREE(Segments::SegmentReference) +BOOST_SERIALIZATION_SPLIT_FREE(CompactSegmentIndex) +BOOST_SERIALIZATION_SPLIT_FREE(TileIndex) +BOOST_SERIALIZATION_SPLIT_FREE(Arc) +BOOST_SERIALIZATION_SPLIT_FREE(Tilewire) +BOOST_SERIALIZATION_SPLIT_FREE(WireIndex) +BOOST_SERIALIZATION_SPLIT_FREE(SiteIndex) +BOOST_SERIALIZATION_SPLIT_FREE(NEXTPNR_NAMESPACE::IdString) + +namespace boost { namespace serialization { + +template +inline void load_construct_data( + Archive & ar, NEXTPNR_NAMESPACE::TorcInfo * t, const unsigned int file_version +){ + const auto& inDeviceName = static_cast(ar).inDeviceName; + const auto& inPackageName = static_cast(ar).inPackageName; + ::new(t)NEXTPNR_NAMESPACE::TorcInfo(inDeviceName, inPackageName); +} + +template +void save(Archive& ar, const Segments::SegmentReference& o, unsigned int) { + ar & o.getCompactSegmentIndex(); + ar & o.getAnchorTileIndex(); +} +template +void load(Archive& ar, Segments::SegmentReference& o, unsigned int) { + CompactSegmentIndex i; + TileIndex j; + ar & i; + ar & j; + o = Segments::SegmentReference(i, j); +} +#define SERIALIZE_POD(__T__) \ +template \ +void save(Archive& ar, const __T__& o, unsigned int) { \ + ar & static_cast<__T__::pod>(o); \ +} \ +template \ +void load(Archive& ar, __T__& o, unsigned int) { \ + __T__::pod i; \ + ar & i; \ + o = __T__(i); \ +} +SERIALIZE_POD(CompactSegmentIndex) +SERIALIZE_POD(TileIndex) +SERIALIZE_POD(WireIndex) +SERIALIZE_POD(SiteIndex) +template +void save(Archive& ar, const Arc& o, unsigned int) { + ar & o.getSourceTilewire(); + ar & o.getSinkTilewire(); +} +template +void load(Archive& ar, Arc& o, unsigned int) { + Tilewire s, t; + ar & s; + ar & t; + o = Arc(s, t); +} +template +void save(Archive& ar, const Tilewire& o, unsigned int) { + ar & o.getTileIndex(); + ar & o.getWireIndex(); +} +template +void load(Archive& ar, Tilewire& o, unsigned int) { + TileIndex i; + WireIndex j; + ar & i; + ar & j; + o.setTileIndex(TileIndex(i)); + o.setWireIndex(WireIndex(j)); +} +template +void serialize(Archive& ar, NEXTPNR_NAMESPACE::Loc& o, unsigned int) { + ar & o.x; + ar & o.y; + ar & o.z; +} +template +void serialize(Archive& ar, NEXTPNR_NAMESPACE::DelayInfo& o, unsigned int) { + ar & o.delay; +} +template +void save(Archive& ar, const NEXTPNR_NAMESPACE::IdString& o, unsigned int) { + const std::string i = o.str(static_cast(ar).ctx); + ar & i; +} +template +void load(Archive& ar, NEXTPNR_NAMESPACE::IdString& o, unsigned int) { + std::string i; + ar & i; + o = static_cast(ar).ctx->id(i); +} +#define SERIALIZE_INDEX(__T__) \ +template \ +void serialize(Archive& ar, __T__& o, unsigned int) { \ + ar & o.index; \ +} +SERIALIZE_INDEX(NEXTPNR_NAMESPACE::BelId) +SERIALIZE_INDEX(NEXTPNR_NAMESPACE::WireId) +SERIALIZE_INDEX(NEXTPNR_NAMESPACE::PipId) +}} // namespace boost::serialization diff --git a/xc7/arch.h b/xc7/arch.h index 410bf8b1..648ace00 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -21,6 +21,8 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include + #include "torc/Architecture.hpp" #include "torc/Common.hpp" using namespace torc::architecture; @@ -268,10 +270,10 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD { RelPtr cell_timing; }); -struct Arch; struct TorcInfo { - TorcInfo(Arch *ctx, const std::string &inDeviceName, const std::string &inPackageName); + TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::string &inPackageName); + TorcInfo() = delete; std::unique_ptr ddb; const Sites &sites; const Tiles &tiles; @@ -297,7 +299,7 @@ struct TorcInfo ss << "(" << tw.getWireIndex() << "@" << tw.getTileIndex() << ")"; return ss.str(); } - int32_t tilewire_to_wire(const Tilewire &tw) const + WireId tilewire_to_wire(const Tilewire &tw) const { const auto &segment = segments.getTilewireSegment(tw); if (!segment.isTrivial()) @@ -310,16 +312,40 @@ struct TorcInfo std::vector site_index_to_bel; std::vector site_index_to_type; std::vector bel_to_loc; - std::unordered_map segment_to_wire; - std::unordered_map trivial_to_wire; + std::unordered_map segment_to_wire; + std::unordered_map trivial_to_wire; std::vector wire_to_tilewire; int num_wires; std::vector wire_to_delay; - std::vector> wire_to_pips_uphill; - std::vector> wire_to_pips_downhill; + //std::vector> wire_to_pips_uphill; + std::vector> wire_to_pips_downhill; std::vector pip_to_arc; int num_pips; - std::vector pip_to_dst_wire; + std::vector pip_to_dst_wire; + + TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); +private: + friend class boost::serialization::access; + //TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); + //template friend inline void load_construct_data(Archive &ar, T *t, const unsigned int file_version); + template + void serialize(Archive & ar, const unsigned int /*version*/) + { + ar & bel_to_site_index; + ar & num_bels; + ar & site_index_to_bel; + ar & site_index_to_type; + ar & bel_to_loc; + ar & segment_to_wire; + ar & trivial_to_wire; + ar & wire_to_tilewire; + ar & num_wires; + ar & wire_to_delay; + ar & wire_to_pips_downhill; + ar & pip_to_arc; + ar & num_pips; + ar & pip_to_dst_wire; + } }; extern std::unique_ptr torc_info; @@ -438,16 +464,14 @@ struct AllPipRange struct PipIterator { - const int *cursor = nullptr; + const PipId *cursor = nullptr; void operator++() { cursor++; } bool operator!=(const PipIterator &other) const { return cursor != other.cursor; } PipId operator*() const { - PipId ret; - ret.index = *cursor; - return ret; + return *cursor; } }; @@ -797,22 +821,17 @@ struct Arch : BaseCtx WireId getPipSrcWire(PipId pip) const { - WireId wire; NPNR_ASSERT(pip != PipId()); const auto &arc = torc_info->pip_to_arc[pip.index]; const auto &tw = arc.getSourceTilewire(); - wire.index = torc_info->tilewire_to_wire(tw); - - return wire; + return torc_info->tilewire_to_wire(tw); } WireId getPipDstWire(PipId pip) const { - WireId wire; NPNR_ASSERT(pip != PipId()); - wire.index = torc_info->pip_to_dst_wire[pip.index]; - return wire; + return torc_info->pip_to_dst_wire[pip.index]; } DelayInfo getPipDelay(PipId pip) const @@ -829,7 +848,6 @@ struct Arch : BaseCtx const auto &pips = torc_info->wire_to_pips_downhill[wire.index]; range.b.cursor = pips.data(); range.e.cursor = range.b.cursor + pips.size(); - return range; } diff --git a/xc7/family.cmake b/xc7/family.cmake index 4c835e38..c8e1c57f 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,6 +1,8 @@ include_directories(/opt/torc/src) #include_directories(torc/externals/zlib) +find_package(Boost REQUIRED COMPONENTS serialization ${boost_libs}) + target_link_libraries( nextpnr-${family} PRIVATE /opt/torc/src/torc/architecture/Arc.o From 212b03999bd68cc3e764f0a0fe9d7c52983bcd7b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 18:08:03 -0800 Subject: [PATCH 112/174] Gzip the torc_info data --- xc7/arch.cc | 19 ++++++++++++------- xc7/family.cmake | 2 +- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index f9d56185..d95453e3 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -33,13 +33,15 @@ #include #include #include +#include +#include struct nextpnr_binary_iarchive : public boost::archive::binary_iarchive { - nextpnr_binary_iarchive(std::ifstream &ifs, NEXTPNR_NAMESPACE::BaseCtx* ctx, const std::string& inDeviceName, const std::string& inPackageName) : boost::archive::binary_iarchive(ifs), ctx(ctx), inDeviceName(inDeviceName), inPackageName(inPackageName) {} + nextpnr_binary_iarchive(boost::iostreams::filtering_istreambuf &ifs, NEXTPNR_NAMESPACE::BaseCtx* ctx, const std::string& inDeviceName, const std::string& inPackageName) : boost::archive::binary_iarchive(ifs), ctx(ctx), inDeviceName(inDeviceName), inPackageName(inPackageName) {} NEXTPNR_NAMESPACE::BaseCtx *ctx; std::string inDeviceName, inPackageName; }; struct nextpnr_binary_oarchive : public boost::archive::binary_oarchive { - nextpnr_binary_oarchive(std::ofstream &ofs, NEXTPNR_NAMESPACE::BaseCtx* ctx) : boost::archive::binary_oarchive(ofs), ctx(ctx) {} + nextpnr_binary_oarchive(boost::iostreams::filtering_ostreambuf &ofs, NEXTPNR_NAMESPACE::BaseCtx* ctx) : boost::archive::binary_oarchive(ofs), ctx(ctx) {} NEXTPNR_NAMESPACE::BaseCtx *ctx; }; @@ -312,9 +314,11 @@ Arch::Arch(ArchArgs args) : args(args) #ifdef TORC_INFO_DB std::ifstream ifs(TORC_INFO_DB, std::ios::binary); if (ifs) { - nextpnr_binary_iarchive ia(ifs, this, "xc7z020", args.package); + boost::iostreams::filtering_istreambuf fifs; + fifs.push(boost::iostreams::zlib_decompressor()); + fifs.push(ifs); + nextpnr_binary_iarchive ia(fifs, this, "xc7z020", args.package); ia >> torc_info; - std::cout << ifs.tellg() << std::endl; } else #endif { @@ -322,10 +326,11 @@ Arch::Arch(ArchArgs args) : args(args) #ifdef TORC_INFO_DB std::ofstream ofs(TORC_INFO_DB, std::ios::binary); if (ofs) { - nextpnr_binary_oarchive oa(ofs, this); + boost::iostreams::filtering_ostreambuf fofs; + fofs.push(boost::iostreams::zlib_compressor()); + fofs.push(ofs); + nextpnr_binary_oarchive oa(fofs, this); oa << torc_info; - ofs.flush(); - std::cout << ofs.tellp() << std::endl; } } #endif diff --git a/xc7/family.cmake b/xc7/family.cmake index c8e1c57f..4a350690 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,7 +1,7 @@ include_directories(/opt/torc/src) #include_directories(torc/externals/zlib) -find_package(Boost REQUIRED COMPONENTS serialization ${boost_libs}) +find_package(Boost REQUIRED COMPONENTS serialization iostreams ${boost_libs}) target_link_libraries( nextpnr-${family} From 13e7798b347f4550faba670f2134a705605a8e57 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 27 Nov 2018 18:11:19 -0800 Subject: [PATCH 113/174] Fix #endif placement --- xc7/arch.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index d95453e3..d64f5aca 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -332,8 +332,8 @@ Arch::Arch(ArchArgs args) : args(args) nextpnr_binary_oarchive oa(fofs, this); oa << torc_info; } - } #endif + } } else { log_error("Unsupported XC7 chip type.\n"); } From f2fecc3c69a4b98b5ee39e4e855e6402c7dd34ab Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 28 Nov 2018 17:04:10 +0100 Subject: [PATCH 114/174] make gui run --- common/log.h | 10 +++ gui/application.cc | 6 +- gui/xc7/family.cmake | 1 + gui/xc7/mainwindow.cc | 51 +++++++++++++ gui/xc7/mainwindow.h | 45 ++++++++++++ gui/xc7/nextpnr.qrc | 2 + xc7/arch.cc | 163 +++++++---------------------------------- xc7/arch.h | 4 + xc7/arch_pybindings.cc | 12 +-- xc7/arch_pybindings.h | 7 ++ 10 files changed, 150 insertions(+), 151 deletions(-) create mode 100644 gui/xc7/family.cmake create mode 100644 gui/xc7/mainwindow.cc create mode 100644 gui/xc7/mainwindow.h create mode 100644 gui/xc7/nextpnr.qrc diff --git a/common/log.h b/common/log.h index 77adbb2f..52158f18 100644 --- a/common/log.h +++ b/common/log.h @@ -84,4 +84,14 @@ static inline void log_assert_worker(bool cond, const char *expr, const char *fi NEXTPNR_NAMESPACE_END +namespace std { +template <> struct hash +{ + std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX LogLevel &loglevel) const noexcept + { + return std::hash()((int)loglevel); + } +}; +} // namespace std + #endif diff --git a/gui/application.cc b/gui/application.cc index aece5d2a..ccbf5645 100644 --- a/gui/application.cc +++ b/gui/application.cc @@ -50,9 +50,9 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) bool Application::notify(QObject *receiver, QEvent *event) { bool retVal = true; - try { + //try { retVal = QApplication::notify(receiver, event); - } catch (assertion_failure ex) { + /*} catch (assertion_failure ex) { QString msg; QTextStream out(&msg); out << ex.filename.c_str() << " at " << ex.line << "\n"; @@ -60,7 +60,7 @@ bool Application::notify(QObject *receiver, QEvent *event) QMessageBox::critical(0, "Error", msg); } catch (...) { QMessageBox::critical(0, "Error", "Fatal error !!!"); - } + }*/ return retVal; } diff --git a/gui/xc7/family.cmake b/gui/xc7/family.cmake new file mode 100644 index 00000000..3b010c7b --- /dev/null +++ b/gui/xc7/family.cmake @@ -0,0 +1 @@ +include_directories(/opt/torc/src) \ No newline at end of file diff --git a/gui/xc7/mainwindow.cc b/gui/xc7/mainwindow.cc new file mode 100644 index 00000000..3ee64727 --- /dev/null +++ b/gui/xc7/mainwindow.cc @@ -0,0 +1,51 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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 "mainwindow.h" + +static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } + +NEXTPNR_NAMESPACE_BEGIN + +MainWindow::MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent) + : BaseMainWindow(std::move(context), args, parent) +{ + initMainResource(); + + std::string title = "nextpnr-xc7 - [EMPTY]"; + setWindowTitle(title.c_str()); + + connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext); + + createMenu(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::newContext(Context *ctx) +{ + std::string title = "nextpnr-xc7 - " + ctx->getChipName(); + setWindowTitle(title.c_str()); +} + +void MainWindow::createMenu() {} + +void MainWindow::new_proj() {} + +NEXTPNR_NAMESPACE_END diff --git a/gui/xc7/mainwindow.h b/gui/xc7/mainwindow.h new file mode 100644 index 00000000..bb6a4cf1 --- /dev/null +++ b/gui/xc7/mainwindow.h @@ -0,0 +1,45 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Miodrag Milanovic + * + * 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 MAINWINDOW_H +#define MAINWINDOW_H + +#include "../basewindow.h" + +NEXTPNR_NAMESPACE_BEGIN + +class MainWindow : public BaseMainWindow +{ + Q_OBJECT + + public: + explicit MainWindow(std::unique_ptr context, ArchArgs args, QWidget *parent = 0); + virtual ~MainWindow(); + + public: + void createMenu(); + + protected Q_SLOTS: + void new_proj() override; + void newContext(Context *ctx); +}; + +NEXTPNR_NAMESPACE_END + +#endif // MAINWINDOW_H diff --git a/gui/xc7/nextpnr.qrc b/gui/xc7/nextpnr.qrc new file mode 100644 index 00000000..03585ec0 --- /dev/null +++ b/gui/xc7/nextpnr.qrc @@ -0,0 +1,2 @@ + + diff --git a/xc7/arch.cc b/xc7/arch.cc index d95453e3..13c1537a 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -455,6 +455,12 @@ PortType Arch::getBelPinType(BelId bel, IdString pin) const return PORT_INOUT; } +std::vector> Arch::getBelAttrs(BelId bel) const +{ + std::vector> ret; + return ret; +} + WireId Arch::getBelPinWire(BelId bel, IdString pin) const { auto pin_name = pin.str(this); @@ -533,14 +539,14 @@ std::vector Arch::getBelPins(BelId bel) const { std::vector ret; - NPNR_ASSERT(bel != BelId()); +/* NPNR_ASSERT(bel != BelId()); int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) ret.push_back(IdString(bel_wires[i].port)); - +*/ return ret; } @@ -600,13 +606,20 @@ IdString Arch::getWireType(WireId wire) const return IdString(); } +// ----------------------------------------------------------------------- +std::vector> Arch::getWireAttrs(WireId wire) const +{ + std::vector> ret; + return ret; +} + // ----------------------------------------------------------------------- PipId Arch::getPipByName(IdString name) const { PipId ret; - if (pip_by_name.empty()) { +/* if (pip_by_name.empty()) { for (int i = 0; i < chip_info->num_pips; i++) { PipId pip; pip.index = i; @@ -617,7 +630,7 @@ PipId Arch::getPipByName(IdString name) const auto it = pip_by_name.find(name); if (it != pip_by_name.end()) ret.index = it->second; - +*/ return ret; } @@ -647,6 +660,13 @@ IdString Arch::getPipName(PipId pip) const //#endif } +std::vector> Arch::getPipAttrs(PipId pip) const +{ + std::vector> ret; + + return ret; +} + // ----------------------------------------------------------------------- BelId Arch::getPackagePinBel(const std::string &pin) const { return getBelByName(id(pin)); } @@ -719,7 +739,7 @@ IdString Arch::getGroupName(GroupId group) const std::vector Arch::getGroups() const { std::vector ret; - +/* for (int y = 0; y < chip_info->height; y++) { for (int x = 0; x < chip_info->width; x++) { TileType type = chip_info->tile_grid[y * chip_info->width + x]; @@ -764,7 +784,7 @@ std::vector Arch::getGroups() const ret.push_back(group); } } - } + }*/ return ret; } @@ -843,137 +863,6 @@ DecalXY Arch::getGroupDecal(GroupId group) const std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; - - if (decal.type == DecalId::TYPE_GROUP) { - int type = (decal.index >> 16) & 255; - int x = (decal.index >> 8) & 255; - int y = decal.index & 255; - - if (type == GroupId::TYPE_FRAME) { - GraphicElement el; - el.type = GraphicElement::TYPE_LINE; - el.style = GraphicElement::STYLE_FRAME; - - el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.01, el.y2 = y + 0.01; - ret.push_back(el); - el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.01, el.y2 = y + 0.02; - ret.push_back(el); - - el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.01, el.y2 = y + 0.01; - ret.push_back(el); - el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.01, el.y2 = y + 0.02; - ret.push_back(el); - - el.x1 = x + 0.99, el.x2 = x + 0.98, el.y1 = y + 0.99, el.y2 = y + 0.99; - ret.push_back(el); - el.x1 = x + 0.99, el.x2 = x + 0.99, el.y1 = y + 0.99, el.y2 = y + 0.98; - ret.push_back(el); - - el.x1 = x + 0.01, el.x2 = x + 0.02, el.y1 = y + 0.99, el.y2 = y + 0.99; - ret.push_back(el); - el.x1 = x + 0.01, el.x2 = x + 0.01, el.y1 = y + 0.99, el.y2 = y + 0.98; - ret.push_back(el); - } - - if (type == GroupId::TYPE_MAIN_SW) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = GraphicElement::STYLE_FRAME; - - el.x1 = x + main_swbox_x1; - el.x2 = x + main_swbox_x2; - el.y1 = y + main_swbox_y1; - el.y2 = y + main_swbox_y2; - ret.push_back(el); - } - - if (type == GroupId::TYPE_LOCAL_SW) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = GraphicElement::STYLE_FRAME; - - el.x1 = x + local_swbox_x1; - el.x2 = x + local_swbox_x2; - el.y1 = y + local_swbox_y1; - el.y2 = y + local_swbox_y2; - ret.push_back(el); - } - - if (GroupId::TYPE_LC0_SW <= type && type <= GroupId::TYPE_LC7_SW) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = GraphicElement::STYLE_FRAME; - - el.x1 = x + lut_swbox_x1; - el.x2 = x + lut_swbox_x2; - el.y1 = y + logic_cell_y1 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW); - el.y2 = y + logic_cell_y2 + logic_cell_pitch * (type - GroupId::TYPE_LC0_SW); - ret.push_back(el); - } - } - - if (decal.type == DecalId::TYPE_WIRE) { - int n = chip_info->wire_data[decal.index].num_segments; - const WireSegmentPOD *p = chip_info->wire_data[decal.index].segments.get(); - - GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; - - for (int i = 0; i < n; i++) - gfxTileWire(ret, p[i].x, p[i].y, GfxTileWireId(p[i].index), style); - } - - if (decal.type == DecalId::TYPE_PIP) { - const PipInfoPOD &p = chip_info->pip_data[decal.index]; - GraphicElement::style_t style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_HIDDEN; - gfxTilePip(ret, p.x, p.y, GfxTileWireId(p.src_seg), GfxTileWireId(p.dst_seg), style); - } - - if (decal.type == DecalId::TYPE_BEL) { - BelId bel; - bel.index = SiteIndex(decal.index); - - auto bel_type = getBelType(bel); - - if (bel_type == id_ICESTORM_LC) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; - el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; - el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + - (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + - (chip_info->bel_data[bel.index].z) * logic_cell_pitch; - ret.push_back(el); - } - - if (bel_type == id_SB_IO) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; - el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; - el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + - (4 * chip_info->bel_data[bel.index].z) * logic_cell_pitch; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + - (4 * chip_info->bel_data[bel.index].z + 3) * logic_cell_pitch; - ret.push_back(el); - } - - if (bel_type == id_ICESTORM_RAM) { - for (int i = 0; i < 2; i++) { - GraphicElement el; - el.type = GraphicElement::TYPE_BOX; - el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; - el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; - el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; - el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1 + i; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + i + 7 * logic_cell_pitch; - ret.push_back(el); - } - } - } - return ret; } diff --git a/xc7/arch.h b/xc7/arch.h index 648ace00..b106d9ab 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -625,6 +625,8 @@ struct Arch : BaseCtx return torc_info->site_index_to_type[site_index]; } + std::vector> getBelAttrs(BelId bel) const; + WireId getBelPinWire(BelId bel, IdString pin) const; PortType getBelPinType(BelId bel, IdString pin) const; std::vector getBelPins(BelId bel) const; @@ -640,6 +642,7 @@ struct Arch : BaseCtx } IdString getWireType(WireId wire) const; + std::vector> getWireAttrs(WireId wire) const; uint32_t getWireChecksum(WireId wire) const { return wire.index; } @@ -816,6 +819,7 @@ struct Arch : BaseCtx IdString getPipName(PipId pip) const; IdString getPipType(PipId pip) const { return IdString(); } + std::vector> getPipAttrs(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } diff --git a/xc7/arch_pybindings.cc b/xc7/arch_pybindings.cc index f1639ba6..04d9d5d9 100644 --- a/xc7/arch_pybindings.cc +++ b/xc7/arch_pybindings.cc @@ -31,21 +31,11 @@ void arch_wrap_python() using namespace PythonConversion; class_("ArchArgs").def_readwrite("type", &ArchArgs::type); - enum_().type)>("iCE40Type") - .value("NONE", ArchArgs::NONE) - .value("LP384", ArchArgs::LP384) - .value("LP1K", ArchArgs::LP1K) - .value("LP8K", ArchArgs::LP8K) - .value("HX1K", ArchArgs::HX1K) - .value("HX8K", ArchArgs::HX8K) - .value("UP5K", ArchArgs::UP5K) - .export_values(); - class_("BelId").def_readwrite("index", &BelId::index); class_("WireId").def_readwrite("index", &WireId::index); - class_("PipId").def_readwrite("index", &PipId::index); + class_("PipId").def_readwrite("index", &PipId::index); class_("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); diff --git a/xc7/arch_pybindings.h b/xc7/arch_pybindings.h index 070c2396..c2c67aa2 100644 --- a/xc7/arch_pybindings.h +++ b/xc7/arch_pybindings.h @@ -48,6 +48,13 @@ template <> struct string_converter std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; +template <> struct string_converter +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + + std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } +}; + template <> struct string_converter { PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } From bfa2157ae62a21599cf659fbc93176ecbc09e74b Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 28 Nov 2018 17:59:58 +0100 Subject: [PATCH 115/174] compile fix for gui and proper size --- CMakeLists.txt | 8 +++++++- xc7/arch.cc | 8 ++++++-- xc7/arch.h | 8 ++++++-- xc7/family.cmake | 2 +- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f4b3c61a..0d6cd312 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,9 +120,10 @@ if (BUILD_PYTHON) # Original source: https://github.com/BVLC/caffe/blob/master/cmake/Dependencies.cmake#L148 set(version ${PYTHONLIBS_VERSION_STRING}) - STRING(REGEX REPLACE "[^0-9]" "" boost_py_version ${version}) + STRING(REGEX REPLACE "[^0-9]" "" boost_py_version ${version}) find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs}) set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) + set(boost_python_lib "python-py${boost_py_version}") while (NOT "${version}" STREQUAL "" AND NOT Boost_PYTHON_FOUND) STRING(REGEX REPLACE "([0-9.]+).[0-9]+" "\\1" version ${version}) @@ -130,6 +131,7 @@ if (BUILD_PYTHON) STRING(REGEX REPLACE "[^0-9]" "" boost_py_version ${version}) find_package(Boost QUIET COMPONENTS "python-py${boost_py_version}" ${boost_libs}) set(Boost_PYTHON_FOUND ${Boost_PYTHON-PY${boost_py_version}_FOUND}) + set(boost_python_lib "python-py${boost_py_version}") STRING(REGEX MATCHALL "([0-9.]+).[0-9]+" has_more_version ${version}) if ("${has_more_version}" STREQUAL "") @@ -139,6 +141,7 @@ if (BUILD_PYTHON) if (NOT Boost_PYTHON_FOUND) find_package(Boost QUIET COMPONENTS python3 ${boost_libs}) + set(boost_python_lib python3) if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) set(Boost_PYTHON_FOUND TRUE) endif () @@ -146,6 +149,7 @@ if (BUILD_PYTHON) if (NOT Boost_PYTHON_FOUND) find_package(Boost QUIET COMPONENTS python36 ${boost_libs}) + set(boost_python_lib python36) if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) set(Boost_PYTHON_FOUND TRUE) endif () @@ -153,6 +157,7 @@ if (BUILD_PYTHON) if (NOT Boost_PYTHON_FOUND) find_package(Boost QUIET COMPONENTS python37 ${boost_libs}) + set(boost_python_lib python37) if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) set(Boost_PYTHON_FOUND TRUE) endif () @@ -161,6 +166,7 @@ if (BUILD_PYTHON) if (NOT Boost_PYTHON_FOUND) STRING(REGEX REPLACE "([0-9]+\\.[0-9]+).*" "\\1" gentoo_version ${PYTHONLIBS_VERSION_STRING}) find_package(Boost QUIET COMPONENTS python-${gentoo_version} ${boost_libs}) + set(boost_python_lib python-${gentoo_version}) if ("${Boost_LIBRARIES}" MATCHES ".*(python|PYTHON).*" ) set(Boost_PYTHON_FOUND TRUE) endif () diff --git a/xc7/arch.cc b/xc7/arch.cc index 13c1537a..85933ff0 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -289,6 +289,9 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const auto &tw = arc.getSinkTilewire(); pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); } + + height = (int)tiles.getRowCount(); + width = (int)tiles.getColCount(); } TorcInfo::TorcInfo(const std::string& inDeviceName, const std::string &inPackageName) : ddb(new DDB(inDeviceName, inPackageName)), sites(ddb->getSites()), tiles(ddb->getTiles()), @@ -332,13 +335,14 @@ Arch::Arch(ArchArgs args) : args(args) nextpnr_binary_oarchive oa(fofs, this); oa << torc_info; } - } #endif + } } else { log_error("Unsupported XC7 chip type.\n"); } - + width = torc_info->width; + height = torc_info->height; /*if (getCtx()->verbose)*/ { log_info("Number of bels: %d\n", torc_info->num_bels); log_info("Number of wires: %d\n", torc_info->num_wires); diff --git a/xc7/arch.h b/xc7/arch.h index b106d9ab..fe89208b 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -322,6 +322,8 @@ struct TorcInfo std::vector pip_to_arc; int num_pips; std::vector pip_to_dst_wire; + int width; + int height; TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); private: @@ -497,6 +499,8 @@ struct Arch : BaseCtx bool fast_part; const ChipInfoPOD *chip_info; const PackageInfoPOD *package_info; + int width; + int height; mutable std::unordered_map wire_by_name; mutable std::unordered_map pip_by_name; @@ -519,8 +523,8 @@ struct Arch : BaseCtx // ------------------------------------------------- - int getGridDimX() const { return 34; } - int getGridDimY() const { return 34; } + int getGridDimX() const { return width; } + int getGridDimY() const { return height; } int getTileBelDimZ(int, int) const { return 8; } int getTilePipDimZ(int, int) const { return 1; } diff --git a/xc7/family.cmake b/xc7/family.cmake index 4a350690..c3eab64a 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,7 +1,7 @@ include_directories(/opt/torc/src) #include_directories(torc/externals/zlib) -find_package(Boost REQUIRED COMPONENTS serialization iostreams ${boost_libs}) +find_package(Boost REQUIRED COMPONENTS serialization iostreams ${boost_libs} ${boost_python_lib}) target_link_libraries( nextpnr-${family} From 105c14884885c4324c8a20da2550aaba2d3c5dfc Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 28 Nov 2018 19:49:28 +0100 Subject: [PATCH 116/174] Made Pip and Wires trees work --- gui/designwidget.cc | 9 ++++++++- xc7/arch.cc | 28 +++++++++++++++++++--------- xc7/arch.h | 13 ++++++++++++- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 235dd2cb..958d8840 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -317,6 +317,12 @@ void DesignWidget::newContext(Context *ctx) for (const auto &wire : ctx->getWires()) { wireMap[std::pair(wire.location.x, wire.location.y)].push_back(wire); } +#endif +#ifdef ARCH_XC7 + for (const auto &wire : ctx->getWires()) { + const auto loc = torc_info->wire_to_loc(wire.index); + wireMap[std::pair(loc.x, loc.y)].push_back(wire); + } #endif auto wireGetter = [](Context *ctx, WireId id) { return ctx->getWireName(id); }; getTreeByElementType(ElementType::WIRE) @@ -706,8 +712,9 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx)); addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip)); addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET); + WireId conflict = ctx->getConflictingPipWire(pip); addProperty(topItem, QVariant::String, "Conflicting Wire", - ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE); + (conflict!=WireId() ? ctx->getWireName(conflict).c_str(ctx) : ""), ElementType::WIRE); addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)), ElementType::NET); addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx), diff --git a/xc7/arch.cc b/xc7/arch.cc index 85933ff0..3a269422 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -388,9 +388,19 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- +static bool endsWith(const std::string& str, const std::string& suffix) +{ + return str.size() >= suffix.size() && 0 == str.compare(str.size()-suffix.size(), suffix.size(), suffix); +} + BelId Arch::getBelByName(IdString name) const { - auto it = torc_info->sites.findSiteIndex(name.str(this)); + std::string n = name.str(this); + if (endsWith(n,"_A") || endsWith(n,"_B") || endsWith(n,"_C") || endsWith(n,"_D")) + { + n = n.substr(0,n.size()-2); + } + auto it = torc_info->sites.findSiteIndex(n); if (it != SiteIndex(-1)) return torc_info->site_index_to_bel.at(it); return BelId(); @@ -561,13 +571,13 @@ WireId Arch::getWireByName(IdString name) const WireId ret; if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + for (int i = 0; i < torc_info->num_wires; i++) + wire_by_name[id(torc_info->wire_to_name(i))] = i; } - // auto it = wire_by_name.find(name); - // if (it != wire_by_name.end()) - // ret.index = it->second; + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; return ret; } @@ -623,8 +633,8 @@ PipId Arch::getPipByName(IdString name) const { PipId ret; -/* if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { + if (pip_by_name.empty()) { + for (int i = 0; i < torc_info->num_pips; i++) { PipId pip; pip.index = i; pip_by_name[getPipName(pip)] = i; @@ -634,7 +644,7 @@ PipId Arch::getPipByName(IdString name) const auto it = pip_by_name.find(name); if (it != pip_by_name.end()) ret.index = it->second; -*/ + return ret; } diff --git a/xc7/arch.h b/xc7/arch.h index fe89208b..238ff18b 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -299,6 +299,17 @@ struct TorcInfo ss << "(" << tw.getWireIndex() << "@" << tw.getTileIndex() << ")"; return ss.str(); } + + Loc wire_to_loc(int32_t index) const + { + const auto &tw = wire_to_tilewire[index]; + ExtendedWireInfo ewi(*ddb, tw); + Loc l; + l.x = (int)ewi.mTileCol; + l.y = (int)ewi.mTileRow; + return l; + } + WireId tilewire_to_wire(const Tilewire &tw) const { const auto &segment = segments.getTilewireSegment(tw); @@ -708,7 +719,7 @@ struct Arch : BaseCtx // NPNR_ASSERT(wire != WireId()); // range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); // range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; - throw; + //throw; return range; } From 4161856d496c6d53a7b396086e06d6a5c027a098 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 28 Nov 2018 22:34:22 -0800 Subject: [PATCH 117/174] Add support for MMCME2_ADV --- xc7/arch.cc | 7 ++++--- xc7/constids.inc | 1 + xc7/xdl.cc | 39 +++++++++++++++++++++++++++++++++------ 3 files changed, 38 insertions(+), 9 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index d64f5aca..adf38207 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -483,10 +483,9 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const throw; } } - } else if (bel_type == id_PS7) { + } else if (bel_type == id_PS7 || bel_type == id_MMCME2_ADV) { // e.g. Convert DDRARB[0] -> DDRARB0 - boost::erase_all(pin_name, "["); - boost::erase_all(pin_name, "]"); + pin_name.erase(std::remove_if(pin_name.begin(), pin_name.end(), boost::is_any_of("[]")), pin_name.end()); } auto site_index = torc_info->bel_to_site_index[bel.index]; @@ -1042,6 +1041,8 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in } else if (cell->type == id_PS7) { // TODO return TMG_IGNORE; + } else if (cell->type == id_MMCME2_ADV) { + return TMG_IGNORE; } log_error("no timing info for port '%s' of cell type '%s'\n", port.c_str(this), cell->type.c_str(this)); } diff --git a/xc7/constids.inc b/xc7/constids.inc index bf0e7114..0bc012b3 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -459,3 +459,4 @@ X(BUFGCTRL) X(SLICE_LUT6) X(IOB33) X(PS7) +X(MMCME2_ADV) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 32546490..e6878ba1 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -68,7 +68,7 @@ void write_xdl(const Context *ctx, std::ostream &out) const char *type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7) + else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) type = cell.second->type.c_str(ctx); else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -198,14 +198,35 @@ void write_xdl(const Context *ctx, std::ostream &out) } else if (cell.second->type == id_BUFGCTRL) { auto it = cell.second->params.find(ctx->id("PRESELECT_I0")); instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "FALSE"); - instPtr->setConfig("CE0INV", "", "CE0"); instPtr->setConfig("S0INV", "", "S0"); - instPtr->setConfig("IGNORE0INV", "", "IGNORE0"); - instPtr->setConfig("CE1INV", "", "CE1"); - instPtr->setConfig("S1INV", "", "S1"); - instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); + //instPtr->setConfig("IGNORE0INV", "", "IGNORE0"); + //instPtr->setConfig("CE1INV", "", "CE1"); + //instPtr->setConfig("S1INV", "", "S1"); + //instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); } else if (cell.second->type == id_PS7) { + } else if (cell.second->type == id_MMCME2_ADV) { + for (const auto& i : cell.second->params) { + instPtr->setConfig(i.first.str(ctx), "", i.second); + } + if (!cell.second->params.count(ctx->id("CLKIN2_PERIOD"))) + instPtr->setConfig("CLKIN2_PERIOD", "", "0"); + for (const auto& i : { "CLKOUT1_DIVIDE", "CLKOUT2_DIVIDE", "CLKOUT3_DIVIDE", "CLKOUT4_DIVIDE", "CLKOUT5_DIVIDE", "CLKOUT6_DIVIDE" }) { + if (!cell.second->params.count(ctx->id(i))) + instPtr->setConfig(i, "", "1"); + } + for (const auto& i : { "CLKOUT1_PHASE", "CLKOUT2_PHASE", "CLKOUT3_PHASE", "CLKOUT4_PHASE", "CLKOUT5_PHASE", "CLKOUT6_PHASE" }) { + if (!cell.second->params.count(ctx->id(i))) + instPtr->setConfig(i, "", "0.0"); + } + for (const auto& i : { "CLKOUT1_DUTY_CYCLE", "CLKOUT2_DUTY_CYCLE", "CLKOUT3_DUTY_CYCLE", "CLKOUT4_DUTY_CYCLE", "CLKOUT5_DUTY_CYCLE", "CLKOUT6_DUTY_CYCLE" }) { + if (!cell.second->params.count(ctx->id(i))) + instPtr->setConfig(i, "", "0.5"); + } + if (!cell.second->params.count(ctx->id("REF_JITTER2"))) + instPtr->setConfig("REF_JITTER2", "", "0.01"); + if (!cell.second->params.count(ctx->id("SS_MOD_PERIOD"))) + instPtr->setConfig("SS_MOD_PERIOD", "", "10000"); } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } @@ -224,6 +245,8 @@ void write_xdl(const Context *ctx, std::ostream &out) const auto lut = bel_to_lut(driver.cell->bel); pin_name[0] = lut[0]; } + // e.g. Convert DDRARB[0] -> DDRARB0 + pin_name.erase(std::remove_if(pin_name.begin(), pin_name.end(), boost::is_any_of("[]")), pin_name.end()); auto pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); netPtr->addSource(pinPtr); @@ -237,6 +260,10 @@ void write_xdl(const Context *ctx, std::ostream &out) const auto lut = bel_to_lut(user.cell->bel); pin_name[0] = lut[0]; } + else { + // e.g. Convert DDRARB[0] -> DDRARB0 + pin_name.erase(std::remove_if(pin_name.begin(), pin_name.end(), boost::is_any_of("[]")), pin_name.end()); + } pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); netPtr->addSink(pinPtr); } From b7a06a02c45b87dcecda08a8e641c54949eb47fc Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 29 Nov 2018 20:54:46 +0100 Subject: [PATCH 118/174] Display slices --- xc7/arch.cc | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 3a269422..0741114d 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -79,7 +79,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_site_index.push_back(i); bel_to_site_index.push_back(i); site_index_to_type[i] = id_SLICE_LUT6; - const auto site_name = site.getName(); + const auto site_name = site.getName(); const auto site_name_back = site_name.back(); if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || site_name_back == '8') { @@ -396,13 +396,18 @@ static bool endsWith(const std::string& str, const std::string& suffix) BelId Arch::getBelByName(IdString name) const { std::string n = name.str(this); + int ndx = 0; if (endsWith(n,"_A") || endsWith(n,"_B") || endsWith(n,"_C") || endsWith(n,"_D")) { + ndx = (int)(n.back() - 'A'); n = n.substr(0,n.size()-2); } auto it = torc_info->sites.findSiteIndex(n); - if (it != SiteIndex(-1)) - return torc_info->site_index_to_bel.at(it); + if (it != SiteIndex(-1)) { + BelId id = torc_info->site_index_to_bel.at(it); + id.index += ndx; + return id; + } return BelId(); } @@ -877,6 +882,31 @@ DecalXY Arch::getGroupDecal(GroupId group) const std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; + + if (decal.type == DecalId::TYPE_BEL) { + BelId bel; + bel.index = decal.index; + auto bel_type = getBelType(bel); + int x = torc_info->bel_to_loc[bel.index].x; + int y = torc_info->bel_to_loc[bel.index].y; + int z = torc_info->bel_to_loc[bel.index].z; + if (bel_type == id_SLICE_LUT6) { + GraphicElement el; + /*if (z>3) { + z = z - 4; + x -= logic_cell_x2- logic_cell_x1; + }*/ + el.type = GraphicElement::TYPE_BOX; + el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE; + el.x1 = x + logic_cell_x1; + el.x2 = x + logic_cell_x2; + el.y1 = y + logic_cell_y1 + (z)*logic_cell_pitch; + el.y2 = y + logic_cell_y2 + (z)*logic_cell_pitch; + ret.push_back(el); + } + + } + return ret; } From 1f387d44fb0b3e803e8b4e36ac99cff382b9318a Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 29 Nov 2018 21:12:56 +0100 Subject: [PATCH 119/174] Use site x location to determine if it is one block or other --- xc7/arch.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 0741114d..4e02227f 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -80,9 +80,11 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_site_index.push_back(i); site_index_to_type[i] = id_SLICE_LUT6; const auto site_name = site.getName(); + if (!boost::regex_match(site_name.c_str(), what, re_loc)) + throw; + const auto sx = boost::lexical_cast(what.str(1)); const auto site_name_back = site_name.back(); - if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || - site_name_back == '8') { + if ((sx & 1) == 0) { bel_to_loc.emplace_back(x, y, 0); bel_to_loc.emplace_back(x, y, 1); bel_to_loc.emplace_back(x, y, 2); From 9f03d9eed3caf7e9e66025c273db3dfee36f904c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 12:25:39 -0800 Subject: [PATCH 120/174] Add PLL to bring 125MHz clock to 60MHz for picorv32 --- xc7/125MHz_to_60MHz.v | 177 ++++++++++++++++++++++++++++++++++++++++++ xc7/picorv32.pcf | 6 +- xc7/picorv32.ys | 1 + xc7/picorv32_top.v | 8 +- 4 files changed, 182 insertions(+), 10 deletions(-) create mode 100755 xc7/125MHz_to_60MHz.v diff --git a/xc7/125MHz_to_60MHz.v b/xc7/125MHz_to_60MHz.v new file mode 100755 index 00000000..72e474d8 --- /dev/null +++ b/xc7/125MHz_to_60MHz.v @@ -0,0 +1,177 @@ +// file: clk_wiz_v3_6.v +// +// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved. +// +// This file contains confidential and proprietary information +// of Xilinx, Inc. and is protected under U.S. and +// international copyright and other intellectual property +// laws. +// +// DISCLAIMER +// This disclaimer is not a license and does not grant any +// rights to the materials distributed herewith. Except as +// otherwise provided in a valid license issued to you by +// Xilinx, and to the maximum extent permitted by applicable +// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND +// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES +// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING +// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- +// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and +// (2) Xilinx shall not be liable (whether in contract or tort, +// including negligence, or under any other theory of +// liability) for any loss or damage of any kind or nature +// related to, arising under or in connection with these +// materials, including for any direct, or any indirect, +// special, incidental, or consequential loss or damage +// (including loss of data, profits, goodwill, or any type of +// loss or damage suffered as a result of any action brought +// by a third party) even if such damage or loss was +// reasonably foreseeable or Xilinx had been advised of the +// possibility of the same. +// +// CRITICAL APPLICATIONS +// Xilinx products are not designed or intended to be fail- +// safe, or for use in any application requiring fail-safe +// performance, such as life-support or safety devices or +// systems, Class III medical devices, nuclear facilities, +// applications related to the deployment of airbags, or any +// other applications that could lead to death, personal +// injury, or severe property or environmental damage +// (individually and collectively, "Critical +// Applications"). Customer assumes the sole risk and +// liability of any use of Xilinx products in Critical +// Applications, subject only to applicable laws and +// regulations governing limitations on product liability. +// +// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS +// PART OF THIS FILE AT ALL TIMES. +// +//---------------------------------------------------------------------------- +// User entered comments +//---------------------------------------------------------------------------- +// None +// +//---------------------------------------------------------------------------- +// "Output Output Phase Duty Pk-to-Pk Phase" +// "Clock Freq (MHz) (degrees) Cycle (%) Jitter (ps) Error (ps)" +//---------------------------------------------------------------------------- +// CLK_OUT1____60.000______0.000______50.0______231.736____234.038 +// +//---------------------------------------------------------------------------- +// "Input Clock Freq (MHz) Input Jitter (UI)" +//---------------------------------------------------------------------------- +// __primary_________125.000____________0.010 + +`timescale 1ps/1ps + +(* CORE_GENERATION_INFO = "clk_wiz_v3_6,clk_wiz_v3_6,{component_name=clk_wiz_v3_6,use_phase_alignment=false,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=MMCM_ADV,num_out_clk=1,clkin1_period=8.000,clkin2_period=10.000,use_power_down=false,use_reset=false,use_locked=false,use_inclk_stopped=false,use_status=false,use_freeze=false,use_clk_valid=false,feedback_type=SINGLE,clock_mgr_type=MANUAL,manual_override=false}" *) +module clk_wiz_v3_6 + (// Clock in ports + input CLK_IN1, + // Clock out ports + output CLK_OUT1 + ); + + // Input buffering + //------------------------------------ + assign clkin1 = CLK_IN1; + + + // Clocking primitive + //------------------------------------ + // Instantiation of the MMCM primitive + // * Unused inputs are tied off + // * Unused outputs are labeled unused + wire [15:0] do_unused; + wire drdy_unused; + wire psdone_unused; + wire locked_unused; + wire clkfbout; + wire clkfboutb_unused; + wire clkout0b_unused; + wire clkout1_unused; + wire clkout1b_unused; + wire clkout2_unused; + wire clkout2b_unused; + wire clkout3_unused; + wire clkout3b_unused; + wire clkout4_unused; + wire clkout5_unused; + wire clkout6_unused; + wire clkfbstopped_unused; + wire clkinstopped_unused; + + MMCME2_ADV + #(.BANDWIDTH ("OPTIMIZED"), + .CLKOUT4_CASCADE ("FALSE"), + .COMPENSATION ("ZHOLD"), + .STARTUP_WAIT ("FALSE"), + .DIVCLK_DIVIDE (5), + .CLKFBOUT_MULT_F (40.500), + .CLKFBOUT_PHASE (0.000), + .CLKFBOUT_USE_FINE_PS ("FALSE"), + .CLKOUT0_DIVIDE_F (16.875), + .CLKOUT0_PHASE (0.000), + .CLKOUT0_DUTY_CYCLE (0.500), + .CLKOUT0_USE_FINE_PS ("FALSE"), + .CLKIN1_PERIOD (8.000), + .REF_JITTER1 (0.010)) + mmcm_adv_inst + // Output clocks + (.CLKFBOUT (clkfbout), + .CLKFBOUTB (clkfboutb_unused), + .CLKOUT0 (clkout0), + .CLKOUT0B (clkout0b_unused), + .CLKOUT1 (clkout1_unused), + .CLKOUT1B (clkout1b_unused), + .CLKOUT2 (clkout2_unused), + .CLKOUT2B (clkout2b_unused), + .CLKOUT3 (clkout3_unused), + .CLKOUT3B (clkout3b_unused), + .CLKOUT4 (clkout4_unused), + .CLKOUT5 (clkout5_unused), + .CLKOUT6 (clkout6_unused), + // Input clock control + .CLKFBIN (clkfbout), + .CLKIN1 (clkin1), + .CLKIN2 (1'b0), + // Tied to always select the primary input clock + .CLKINSEL (1'b1), + // Ports for dynamic reconfiguration + .DADDR (7'h0), + .DCLK (1'b0), + .DEN (1'b0), + .DI (16'h0), + .DO (do_unused), + .DRDY (drdy_unused), + .DWE (1'b0), + // Ports for dynamic phase shift + .PSCLK (1'b0), + .PSEN (1'b0), + .PSINCDEC (1'b0), + .PSDONE (psdone_unused), + // Other control and status signals + .LOCKED (locked_unused), + .CLKINSTOPPED (clkinstopped_unused), + .CLKFBSTOPPED (clkfbstopped_unused), + .PWRDWN (1'b0), + .RST (1'b0)); + + // Output buffering + //----------------------------------- + + //BUFG clkout1_buf + // (.O (CLK_OUT1), + // .I (clkout0)); + + // BUFG not currently supported + BUFGCTRL clkout1_buf ( + .I0(clkout0), + .CE0(1'b1), + .S0(1'b1), + .O(CLK_OUT1) + ); + + + +endmodule diff --git a/xc7/picorv32.pcf b/xc7/picorv32.pcf index 499b965d..0f023697 100644 --- a/xc7/picorv32.pcf +++ b/xc7/picorv32.pcf @@ -1,3 +1,3 @@ -NET "clk" PERIOD = 8 nS ; -PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; -PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; +NET "pll.clkin1" PERIOD = 8 nS ; +#PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; +#PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/picorv32.ys b/xc7/picorv32.ys index 61916173..e6eec6cd 100644 --- a/xc7/picorv32.ys +++ b/xc7/picorv32.ys @@ -1,5 +1,6 @@ read_verilog picorv32.v read_verilog picorv32_top.v +read_verilog 125MHz_to_60MHz.v #synth_xilinx -top picorv32 diff --git a/xc7/picorv32_top.v b/xc7/picorv32_top.v index 7e2bf488..34149622 100644 --- a/xc7/picorv32_top.v +++ b/xc7/picorv32_top.v @@ -12,13 +12,7 @@ module top ( input [31:0] mem_rdata ); - wire gclk; - BUFGCTRL clk_gb ( - .I0(clk), - .CE0(1'b1), - .S0(1'b1), - .O(gclk) - ); + clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); picorv32 #( .ENABLE_COUNTERS(0), From 535fc953d44ad67692f7ac5bf3600d36d6bf57dc Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 29 Nov 2018 21:12:56 +0100 Subject: [PATCH 121/174] Use site x location to determine if it is one block or other --- xc7/arch.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index adf38207..46a2bdd9 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -80,9 +80,10 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_site_index.push_back(i); site_index_to_type[i] = id_SLICE_LUT6; const auto site_name = site.getName(); - const auto site_name_back = site_name.back(); - if (site_name_back == '0' || site_name_back == '2' || site_name_back == '4' || site_name_back == '6' || - site_name_back == '8') { + if (!boost::regex_match(site_name.c_str(), what, re_loc)) + throw; + const auto sx = boost::lexical_cast(what.str(1)); + if ((sx & 1) == 0) { bel_to_loc.emplace_back(x, y, 0); bel_to_loc.emplace_back(x, y, 1); bel_to_loc.emplace_back(x, y, 2); From d8b6b231de03428cd52062b993f0f0a1c7f1ec3a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 15:38:28 -0800 Subject: [PATCH 122/174] Move required attributes to pack --- xc7/pack.cc | 28 +++++++++++++++++++++++++++- xc7/xdl.cc | 34 +++------------------------------- 2 files changed, 30 insertions(+), 32 deletions(-) diff --git a/xc7/pack.cc b/xc7/pack.cc index d2130e72..63e68b48 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -631,7 +631,33 @@ static void pack_special(Context *ctx) for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; - if (is_sb_lfosc(ctx, ci)) { + if (ci->type == id_BUFGCTRL) { + ci->params.emplace(ctx->id("PRESELECT_I0"), "FALSE"); + ci->params.emplace(ctx->id("CE0INV"), "CE0"); + ci->params.emplace(ctx->id("S0INV"), "S0"); + ci->params.emplace(ctx->id("IGNORE0INV"), "IGNORE0"); + ci->params.emplace(ctx->id("CE1INV"), "CE1"); + ci->params.emplace(ctx->id("S1INV"), "S1"); + ci->params.emplace(ctx->id("IGNORE1INV"), "IGNORE1"); + } else if (ci->type == id_MMCME2_ADV) { + ci->params.emplace(ctx->id("CLKINSELINV"), "CLKINSEL"); + ci->params.emplace(ctx->id("PSENINV"), "PSEN"); + ci->params.emplace(ctx->id("PSINCDECINV"), "PSINCDEC"); + ci->params.emplace(ctx->id("PWRDWNINV"), "PWRDWN"); + ci->params.emplace(ctx->id("RSTINV"), "RST"); + ci->params.emplace(ctx->id("CLKIN2_PERIOD"), "0"); + for (const auto& i : { "CLKOUT1_DIVIDE", "CLKOUT2_DIVIDE", "CLKOUT3_DIVIDE", "CLKOUT4_DIVIDE", "CLKOUT5_DIVIDE", "CLKOUT6_DIVIDE" }) { + ci->params.emplace(ctx->id(i), "1"); + } + for (const auto& i : { "CLKOUT1_PHASE", "CLKOUT2_PHASE", "CLKOUT3_PHASE", "CLKOUT4_PHASE", "CLKOUT5_PHASE", "CLKOUT6_PHASE" }) { + ci->params.emplace(ctx->id(i), "0.0"); + } + for (const auto& i : { "CLKOUT1_DUTY_CYCLE", "CLKOUT2_DUTY_CYCLE", "CLKOUT3_DUTY_CYCLE", "CLKOUT4_DUTY_CYCLE", "CLKOUT5_DUTY_CYCLE", "CLKOUT6_DUTY_CYCLE" }) { + ci->params.emplace(ctx->id(i), "0.5"); + } + ci->params.emplace(ctx->id("REF_JITTER2"), "0.5"); + ci->params.emplace(ctx->id("SS_MOD_PERIOD"), "10000"); + } else if (is_sb_lfosc(ctx, ci)) { std::unique_ptr packed = create_xc7_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); packed_cells.insert(ci->name); diff --git a/xc7/xdl.cc b/xc7/xdl.cc index e6878ba1..1860942f 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -195,38 +195,10 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } - } else if (cell.second->type == id_BUFGCTRL) { - auto it = cell.second->params.find(ctx->id("PRESELECT_I0")); - instPtr->setConfig("PRESELECT_I0", "", it != cell.second->params.end() ? it->second : "FALSE"); - instPtr->setConfig("CE0INV", "", "CE0"); - instPtr->setConfig("S0INV", "", "S0"); - //instPtr->setConfig("IGNORE0INV", "", "IGNORE0"); - //instPtr->setConfig("CE1INV", "", "CE1"); - //instPtr->setConfig("S1INV", "", "S1"); - //instPtr->setConfig("IGNORE1INV", "", "IGNORE1"); - } else if (cell.second->type == id_PS7) { - } else if (cell.second->type == id_MMCME2_ADV) { - for (const auto& i : cell.second->params) { + } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_MMCME2_ADV) { + for (const auto& i : cell.second->params) instPtr->setConfig(i.first.str(ctx), "", i.second); - } - if (!cell.second->params.count(ctx->id("CLKIN2_PERIOD"))) - instPtr->setConfig("CLKIN2_PERIOD", "", "0"); - for (const auto& i : { "CLKOUT1_DIVIDE", "CLKOUT2_DIVIDE", "CLKOUT3_DIVIDE", "CLKOUT4_DIVIDE", "CLKOUT5_DIVIDE", "CLKOUT6_DIVIDE" }) { - if (!cell.second->params.count(ctx->id(i))) - instPtr->setConfig(i, "", "1"); - } - for (const auto& i : { "CLKOUT1_PHASE", "CLKOUT2_PHASE", "CLKOUT3_PHASE", "CLKOUT4_PHASE", "CLKOUT5_PHASE", "CLKOUT6_PHASE" }) { - if (!cell.second->params.count(ctx->id(i))) - instPtr->setConfig(i, "", "0.0"); - } - for (const auto& i : { "CLKOUT1_DUTY_CYCLE", "CLKOUT2_DUTY_CYCLE", "CLKOUT3_DUTY_CYCLE", "CLKOUT4_DUTY_CYCLE", "CLKOUT5_DUTY_CYCLE", "CLKOUT6_DUTY_CYCLE" }) { - if (!cell.second->params.count(ctx->id(i))) - instPtr->setConfig(i, "", "0.5"); - } - if (!cell.second->params.count(ctx->id("REF_JITTER2"))) - instPtr->setConfig("REF_JITTER2", "", "0.01"); - if (!cell.second->params.count(ctx->id("SS_MOD_PERIOD"))) - instPtr->setConfig("SS_MOD_PERIOD", "", "10000"); + } else if (cell.second->type == id_PS7) { } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From d7dd945f552af791575e6a706d37be15a2215f68 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 16:32:08 -0800 Subject: [PATCH 123/174] Overwrite COMPENSATION attribute on MMCME2_ADV to "INTERNAL" --- xc7/pack.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/xc7/pack.cc b/xc7/pack.cc index 63e68b48..ab76f4cb 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -646,6 +646,7 @@ static void pack_special(Context *ctx) ci->params.emplace(ctx->id("PWRDWNINV"), "PWRDWN"); ci->params.emplace(ctx->id("RSTINV"), "RST"); ci->params.emplace(ctx->id("CLKIN2_PERIOD"), "0"); + ci->params[ctx->id("COMPENSATION")] = "INTERNAL"; for (const auto& i : { "CLKOUT1_DIVIDE", "CLKOUT2_DIVIDE", "CLKOUT3_DIVIDE", "CLKOUT4_DIVIDE", "CLKOUT5_DIVIDE", "CLKOUT6_DIVIDE" }) { ci->params.emplace(ctx->id(i), "1"); } From c5165f78303866b599062cb0d244655234c34fea Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 16:32:33 -0800 Subject: [PATCH 124/174] Duplicate arcs.clear() --- xc7/arch.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 4481da7e..59510591 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -237,7 +237,6 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const auto ¤tTilewire = wire_to_tilewire[w.index]; if (currentTilewire.isUndefined()) continue; - arcs.clear(); const auto &tileInfo = tiles.getTileInfo(currentTilewire.getTileIndex()); const auto tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); From 0327fa554a6a80ba7308fe5664ec88c7f2d2b202 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 16:54:33 -0800 Subject: [PATCH 125/174] Revert "Ahead of LUT input swapping, assign LUT<6 from A6 downwards" This reverts commit ec96897c1d5e01456087b7150911e93abd1b72c5. --- xc7/cells.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index f8eb1373..e1588516 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -259,17 +259,17 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; - replace_port(lut, ctx->id("I0"), lc, id_I6); + replace_port(lut, ctx->id("I0"), lc, id_I1); if (get_net_or_empty(lut, id_I1)) - replace_port(lut, id_I1, lc, id_I5); + replace_port(lut, id_I1, lc, id_I2); if (get_net_or_empty(lut, id_I2)) - replace_port(lut, id_I2, lc, id_I4); + replace_port(lut, id_I2, lc, id_I3); if (get_net_or_empty(lut, id_I3)) - replace_port(lut, id_I3, lc, id_I3); + replace_port(lut, id_I3, lc, id_I4); if (get_net_or_empty(lut, id_I4)) - replace_port(lut, id_I4, lc, id_I2); + replace_port(lut, id_I4, lc, id_I5); if (get_net_or_empty(lut, id_I5)) - replace_port(lut, id_I5, lc, id_I1); + replace_port(lut, id_I5, lc, id_I6); if (no_dff) { replace_port(lut, id_O, lc, id_O); lc->params[ctx->id("DFF_ENABLE")] = "0"; From 2fdf937259ae03d968bdad75f7c00c3858f581b3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 17:08:05 -0800 Subject: [PATCH 126/174] Assignment LUT inputs from fastest down --- xc7/cells.cc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index e1588516..5d9df55a 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -259,17 +259,18 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri void lut_to_lc(const Context *ctx, CellInfo *lut, CellInfo *lc, bool no_dff) { lc->params[ctx->id("INIT")] = lut->params[ctx->id("INIT")]; - replace_port(lut, ctx->id("I0"), lc, id_I1); - if (get_net_or_empty(lut, id_I1)) - replace_port(lut, id_I1, lc, id_I2); - if (get_net_or_empty(lut, id_I2)) - replace_port(lut, id_I2, lc, id_I3); - if (get_net_or_empty(lut, id_I3)) - replace_port(lut, id_I3, lc, id_I4); - if (get_net_or_empty(lut, id_I4)) - replace_port(lut, id_I4, lc, id_I5); + int i = 6; if (get_net_or_empty(lut, id_I5)) - replace_port(lut, id_I5, lc, id_I6); + replace_port(lut, id_I5, lc, ctx->id("I" + std::to_string(i--))); + if (get_net_or_empty(lut, id_I4)) + replace_port(lut, id_I4, lc, ctx->id("I" + std::to_string(i--))); + if (get_net_or_empty(lut, id_I3)) + replace_port(lut, id_I3, lc, ctx->id("I" + std::to_string(i--))); + if (get_net_or_empty(lut, id_I2)) + replace_port(lut, id_I2, lc, ctx->id("I" + std::to_string(i--))); + if (get_net_or_empty(lut, id_I1)) + replace_port(lut, id_I1, lc, ctx->id("I" + std::to_string(i--))); + replace_port(lut, ctx->id("I0"), lc, ctx->id("I" + std::to_string(i--))); if (no_dff) { replace_port(lut, id_O, lc, id_O); lc->params[ctx->id("DFF_ENABLE")] = "0"; From f4e7f4e690a4101026c19d5672af085a522fd8b8 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 17:20:35 -0800 Subject: [PATCH 127/174] Use wholesale attrs from ISE for MMCME2_ADV --- xc7/pack.cc | 219 +++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 208 insertions(+), 11 deletions(-) diff --git a/xc7/pack.cc b/xc7/pack.cc index ab76f4cb..5137757f 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -640,24 +640,221 @@ static void pack_special(Context *ctx) ci->params.emplace(ctx->id("S1INV"), "S1"); ci->params.emplace(ctx->id("IGNORE1INV"), "IGNORE1"); } else if (ci->type == id_MMCME2_ADV) { + ci->params.emplace(ctx->id("BANDWIDTH"), "OPTIMIZED"); + ci->params.emplace(ctx->id("CLKBURST_ENABLE"), "FALSE"); + ci->params.emplace(ctx->id("CLKBURST_REPEAT"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBIN_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBIN_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKFBOUT_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBOUT_EN"), "TRUE"); + ci->params.emplace(ctx->id("CLKFBOUT_FRAC_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBOUT_FRAC_WF_FALL"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBOUT_FRAC_WF_RISE"), "FALSE"); + ci->params.emplace(ctx->id("CLKFBOUT_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKFBOUT_USE_FINE_PS"), "FALSE"); ci->params.emplace(ctx->id("CLKINSELINV"), "CLKINSEL"); + ci->params.emplace(ctx->id("CLKOUT0_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT0_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT0_FRAC_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT0_FRAC_WF_FALL"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT0_FRAC_WF_RISE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT0_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT0_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT1_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT1_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT1_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT1_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT2_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT2_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT2_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT2_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT3_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT3_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT3_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT3_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT4_CASCADE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT4_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT4_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT4_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT4_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT5_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT5_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT5_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT5_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT6_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT6_EN"), "FALSE"); + ci->params.emplace(ctx->id("CLKOUT6_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("CLKOUT6_USE_FINE_PS"), "FALSE"); + ci->params.emplace(ctx->id("COMPENSATION"), "INTERNAL"); + ci->params.emplace(ctx->id("DIRECT_PATH_CNTRL"), "FALSE"); + ci->params.emplace(ctx->id("DIVCLK_EDGE"), "FALSE"); + ci->params.emplace(ctx->id("DIVCLK_NOCOUNT"), "TRUE"); + ci->params.emplace(ctx->id("EN_VCO_DIV1"), "FALSE"); + ci->params.emplace(ctx->id("EN_VCO_DIV6"), "FALSE"); + ci->params.emplace(ctx->id("GTS_WAIT"), "FALSE"); + ci->params.emplace(ctx->id("HVLF_CNT_TEST_EN"), "FALSE"); + ci->params.emplace(ctx->id("INTERP_TEST"), "FALSE"); + ci->params.emplace(ctx->id("IN_DLY_EN"), "TRUE"); + ci->params.emplace(ctx->id("LF_LOW_SEL"), "FALSE"); + ci->params.emplace(ctx->id("MMCM_EN"), "TRUE"); + ci->params.emplace(ctx->id("PERF0_USE_CLK"), "FALSE"); + ci->params.emplace(ctx->id("PERF1_USE_CLK"), "FALSE"); + ci->params.emplace(ctx->id("PERF2_USE_CLK"), "FALSE"); + ci->params.emplace(ctx->id("PERF3_USE_CLK"), "FALSE"); ci->params.emplace(ctx->id("PSENINV"), "PSEN"); ci->params.emplace(ctx->id("PSINCDECINV"), "PSINCDEC"); ci->params.emplace(ctx->id("PWRDWNINV"), "PWRDWN"); ci->params.emplace(ctx->id("RSTINV"), "RST"); + ci->params.emplace(ctx->id("SEL_HV_NMOS"), "FALSE"); + ci->params.emplace(ctx->id("SEL_LV_NMOS"), "FALSE"); + ci->params.emplace(ctx->id("SEL_SLIPD"), "FALSE"); + ci->params.emplace(ctx->id("SS_EN"), "FALSE"); + ci->params.emplace(ctx->id("SS_MODE"), "CENTER_HIGH"); + ci->params.emplace(ctx->id("STARTUP_WAIT"), "FALSE"); + ci->params.emplace(ctx->id("SUP_SEL_AREG"), "FALSE"); + ci->params.emplace(ctx->id("SUP_SEL_DREG"), "FALSE"); + ci->params.emplace(ctx->id("TMUX_MUX_SEL"), "00"); + ci->params.emplace(ctx->id("VLF_HIGH_DIS_B"), "TRUE"); + ci->params.emplace(ctx->id("VLF_HIGH_PWDN_B"), "TRUE"); + //ci->params.emplace(ctx->id("MMCME2_ADV:mmcm_adv_inst:"); + ci->params.emplace(ctx->id("ANALOG_MISC"), "0000"); + ci->params.emplace(ctx->id("AVDD_COMP_SET"), "011"); + ci->params.emplace(ctx->id("AVDD_VBG_PD"), "110"); + ci->params.emplace(ctx->id("AVDD_VBG_SEL"), "1001"); + ci->params.emplace(ctx->id("CLKBURST_CNT"), "1"); + ci->params.emplace(ctx->id("CLKFBIN_HT"), "1"); + ci->params.emplace(ctx->id("CLKFBIN_LT"), "1"); + ci->params.emplace(ctx->id("CLKFBIN_MULT"), "1"); + ci->params.emplace(ctx->id("CLKFBOUT_DT"), "0"); + ci->params.emplace(ctx->id("CLKFBOUT_FRAC"), "0"); + ci->params.emplace(ctx->id("CLKFBOUT_HT"), "1"); + ci->params.emplace(ctx->id("CLKFBOUT_LT"), "1"); + ci->params.emplace(ctx->id("CLKFBOUT_MULT_F"), "40.5"); + ci->params.emplace(ctx->id("CLKFBOUT_MX"), "00"); + ci->params.emplace(ctx->id("CLKFBOUT_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKFBOUT_PM_FALL"), "000"); + ci->params.emplace(ctx->id("CLKFBOUT_PM_RISE"), "000"); + ci->params.emplace(ctx->id("CLKFB_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("CLKIN1_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("CLKIN1_PERIOD"), "8"); + ci->params.emplace(ctx->id("CLKIN2_MUX_SEL"), "000"); ci->params.emplace(ctx->id("CLKIN2_PERIOD"), "0"); - ci->params[ctx->id("COMPENSATION")] = "INTERNAL"; - for (const auto& i : { "CLKOUT1_DIVIDE", "CLKOUT2_DIVIDE", "CLKOUT3_DIVIDE", "CLKOUT4_DIVIDE", "CLKOUT5_DIVIDE", "CLKOUT6_DIVIDE" }) { - ci->params.emplace(ctx->id(i), "1"); - } - for (const auto& i : { "CLKOUT1_PHASE", "CLKOUT2_PHASE", "CLKOUT3_PHASE", "CLKOUT4_PHASE", "CLKOUT5_PHASE", "CLKOUT6_PHASE" }) { - ci->params.emplace(ctx->id(i), "0.0"); - } - for (const auto& i : { "CLKOUT1_DUTY_CYCLE", "CLKOUT2_DUTY_CYCLE", "CLKOUT3_DUTY_CYCLE", "CLKOUT4_DUTY_CYCLE", "CLKOUT5_DUTY_CYCLE", "CLKOUT6_DUTY_CYCLE" }) { - ci->params.emplace(ctx->id(i), "0.5"); - } - ci->params.emplace(ctx->id("REF_JITTER2"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT0_DIVIDE_F"), "16.875"); + ci->params.emplace(ctx->id("CLKOUT0_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT0_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT0_FRAC"), "0"); + ci->params.emplace(ctx->id("CLKOUT0_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT0_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT0_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT0_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT0_PM_FALL"), "000"); + ci->params.emplace(ctx->id("CLKOUT0_PM_RISE"), "000"); + ci->params.emplace(ctx->id("CLKOUT1_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT1_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT1_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT1_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT1_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT1_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT1_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT1_PM"), "000"); + ci->params.emplace(ctx->id("CLKOUT2_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT2_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT2_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT2_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT2_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT2_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT2_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT2_PM"), "000"); + ci->params.emplace(ctx->id("CLKOUT3_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT3_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT3_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT3_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT3_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT3_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT3_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT3_PM"), "000"); + ci->params.emplace(ctx->id("CLKOUT4_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT4_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT4_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT4_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT4_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT4_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT4_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT4_PM"), "000"); + ci->params.emplace(ctx->id("CLKOUT5_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT5_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT5_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT5_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT5_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT5_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT5_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT5_PM"), "000"); + ci->params.emplace(ctx->id("CLKOUT6_DIVIDE"), "1"); + ci->params.emplace(ctx->id("CLKOUT6_DT"), "0"); + ci->params.emplace(ctx->id("CLKOUT6_DUTY_CYCLE"), "0.5"); + ci->params.emplace(ctx->id("CLKOUT6_HT"), "1"); + ci->params.emplace(ctx->id("CLKOUT6_LT"), "1"); + ci->params.emplace(ctx->id("CLKOUT6_MX"), "00"); + ci->params.emplace(ctx->id("CLKOUT6_PHASE"), "0.0"); + ci->params.emplace(ctx->id("CLKOUT6_PM"), "000"); + ci->params.emplace(ctx->id("CONTROL_0"), "1111001101111100"); + ci->params.emplace(ctx->id("CONTROL_1"), "0111110101001101"); + ci->params.emplace(ctx->id("CONTROL_2"), "0101000001000010"); + ci->params.emplace(ctx->id("CONTROL_3"), "1110101111001000"); + ci->params.emplace(ctx->id("CONTROL_4"), "1101010011011111"); + ci->params.emplace(ctx->id("CONTROL_5"), "1010110111111011"); + ci->params.emplace(ctx->id("CONTROL_6"), "1011001011000011"); + ci->params.emplace(ctx->id("CONTROL_7"), "0100110000101110"); + ci->params.emplace(ctx->id("CP"), "0000"); + ci->params.emplace(ctx->id("CP_BIAS_TRIP_SET"), "0"); + ci->params.emplace(ctx->id("CP_RES"), "01"); + ci->params.emplace(ctx->id("DIVCLK_DIVIDE"), "5"); + ci->params.emplace(ctx->id("DIVCLK_HT"), "1"); + ci->params.emplace(ctx->id("DIVCLK_LT"), "1"); + ci->params.emplace(ctx->id("DVDD_COMP_SET"), "011"); + ci->params.emplace(ctx->id("DVDD_VBG_PD"), "110"); + ci->params.emplace(ctx->id("DVDD_VBG_SEL"), "1001"); + ci->params.emplace(ctx->id("EN_CURR_SINK"), "11"); + ci->params.emplace(ctx->id("FINE_PS_FRAC"), "0"); + ci->params.emplace(ctx->id("FREQ_BB_USE_CLK0"), "0"); + ci->params.emplace(ctx->id("FREQ_BB_USE_CLK1"), "0"); + ci->params.emplace(ctx->id("FREQ_BB_USE_CLK2"), "0"); + ci->params.emplace(ctx->id("FREQ_BB_USE_CLK3"), "0"); + ci->params.emplace(ctx->id("FREQ_COMP"), "01"); + ci->params.emplace(ctx->id("HROW_DLY_SET"), "0"); + ci->params.emplace(ctx->id("HVLF_CNT_TEST"), "0"); + ci->params.emplace(ctx->id("INTERP_EN"), "00010000"); + ci->params.emplace(ctx->id("IN_DLY_MX_CVDD"), "011000"); + ci->params.emplace(ctx->id("IN_DLY_MX_DVDD"), "000001"); + ci->params.emplace(ctx->id("IN_DLY_SET"), "38"); + ci->params.emplace(ctx->id("LFHF"), "11"); + ci->params.emplace(ctx->id("LF_NEN"), "10"); + ci->params.emplace(ctx->id("LF_PEN"), "00"); + ci->params.emplace(ctx->id("LOCK_CNT"), "128"); + ci->params.emplace(ctx->id("LOCK_FB_DLY"), "3"); + ci->params.emplace(ctx->id("LOCK_REF_DLY"), "3"); + ci->params.emplace(ctx->id("LOCK_SAT_HIGH"), "160"); + ci->params.emplace(ctx->id("MAN_LF"), "000"); + ci->params.emplace(ctx->id("MVDD_SEL"), "11"); + ci->params.emplace(ctx->id("PERF0_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("PERF1_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("PERF2_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("PERF3_MUX_SEL"), "000"); + ci->params.emplace(ctx->id("PFD"), "0100001"); + ci->params.emplace(ctx->id("REF_JITTER1"), "0.01"); + ci->params.emplace(ctx->id("REF_JITTER2"), "0.01"); + ci->params.emplace(ctx->id("RES"), "0000"); + ci->params.emplace(ctx->id("SKEW_FLOP_INV"), "0000"); + ci->params.emplace(ctx->id("SPARE_ANALOG"), "00000"); + ci->params.emplace(ctx->id("SPARE_DIGITAL"), "00000"); ci->params.emplace(ctx->id("SS_MOD_PERIOD"), "10000"); + ci->params.emplace(ctx->id("SS_STEPS"), "011"); + ci->params.emplace(ctx->id("SS_STEPS_INIT"), "010"); + ci->params.emplace(ctx->id("SYNTH_CLK_DIV"), "11"); + ci->params.emplace(ctx->id("UNLOCK_CNT"), "64"); + ci->params.emplace(ctx->id("VREF_START"), "01"); + + ci->params[ctx->id("COMPENSATION")] = "INTERNAL"; } else if (is_sb_lfosc(ctx, ci)) { std::unique_ptr packed = create_xc7_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); From cac7ce27476d819d307943c57cbd7542d9fbd6f9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 29 Nov 2018 17:20:51 -0800 Subject: [PATCH 128/174] Cleanup --- xc7/xdl.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 1860942f..ea834593 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -195,10 +195,9 @@ void write_xdl(const Context *ctx, std::ostream &out) instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } - } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_MMCME2_ADV) { + } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) { for (const auto& i : cell.second->params) instPtr->setConfig(i.first.str(ctx), "", i.second); - } else if (cell.second->type == id_PS7) { } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From fdca3d6d779b9e7f93076d5d2ae0556d4bcce283 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Nov 2018 15:23:09 -0800 Subject: [PATCH 129/174] firmware.hex with delay loop --- xc7/firmware.hex | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 xc7/firmware.hex diff --git a/xc7/firmware.hex b/xc7/firmware.hex new file mode 100644 index 00000000..ef9aa3c5 --- /dev/null +++ b/xc7/firmware.hex @@ -0,0 +1,8 @@ +@00000000 +13 04 20 00 B7 04 00 02 93 09 00 10 13 04 14 00 +63 44 34 01 13 04 20 00 13 09 20 00 63 5E 89 00 +13 05 04 00 93 05 09 00 EF 00 C0 01 63 0A 05 00 +13 09 19 00 6F F0 9F FE 23 A0 84 00 EF 00 80 01 +6F F0 DF FC 93 02 10 00 33 05 B5 40 E3 5E 55 FE +67 80 00 00 B7 82 05 00 93 82 02 E4 93 82 F2 FF +E3 9E 02 FE 67 80 00 00 From 4574a57efc532621bf96b10583347bae0423dec6 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Nov 2018 15:24:32 -0800 Subject: [PATCH 130/174] Add attosoc --- xc7/attosoc.pcf | 9 ++++ xc7/attosoc.v | 127 ++++++++++++++++++++++++++++++++++++++++++++++ xc7/attosoc.ys | 56 ++++++++++++++++++++ xc7/attosoc_top.v | 15 ++++++ 4 files changed, 207 insertions(+) create mode 100644 xc7/attosoc.pcf create mode 100644 xc7/attosoc.v create mode 100644 xc7/attosoc.ys create mode 100644 xc7/attosoc_top.v diff --git a/xc7/attosoc.pcf b/xc7/attosoc.pcf new file mode 100644 index 00000000..3ef75a17 --- /dev/null +++ b/xc7/attosoc.pcf @@ -0,0 +1,9 @@ +COMP "led[0]" LOCATE = SITE "M14" LEVEL 1; +COMP "led[1]" LOCATE = SITE "M15" LEVEL 1; +COMP "led[2]" LOCATE = SITE "G14" LEVEL 1; +COMP "led[3]" LOCATE = SITE "D18" LEVEL 1; +COMP "clk" LOCATE = SITE "K17" LEVEL 1; +COMP "pll.mmcm_adv_inst" LOCATE = SITE "MMCME2_ADV_X1Y2" LEVEL 1; +NET "pll.clkin1" PERIOD = 8 nS ; +#PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; +#PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/attosoc.v b/xc7/attosoc.v new file mode 100644 index 00000000..4921e298 --- /dev/null +++ b/xc7/attosoc.v @@ -0,0 +1,127 @@ +/* + * ECP5 PicoRV32 demo + * + * Copyright (C) 2017 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. + * + */ + +`ifdef PICORV32_V +`error "attosoc.v must be read before picorv32.v!" +`endif + +`define PICORV32_REGS picosoc_regs + +module attosoc ( + input clk, + output reg [7:0] led +); + + reg [5:0] reset_cnt = 0; + wire resetn = &reset_cnt; + + always @(posedge clk) begin + reset_cnt <= reset_cnt + !resetn; + end + + parameter integer MEM_WORDS = 256; + parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory + parameter [31:0] PROGADDR_RESET = 32'h 0000_0000; // ROM at 0x0 + parameter integer ROM_BYTES = 256; + + reg [7:0] rom [0:ROM_BYTES-1]; + wire [31:0] rom_rdata = {rom[mem_addr+3], rom[mem_addr+2], rom[mem_addr+1], rom[mem_addr+0]}; + initial $readmemh("firmware.hex", rom); + + wire mem_valid; + wire mem_instr; + wire mem_ready; + wire [31:0] mem_addr; + wire [31:0] mem_wdata; + wire [3:0] mem_wstrb; + wire [31:0] mem_rdata; + + wire rom_ready = mem_valid && mem_addr[31:24] == 8'h00; + + wire iomem_valid; + wire iomem_ready; + wire [31:0] iomem_addr; + wire [31:0] iomem_wdata; + wire [3:0] iomem_wstrb; + wire [31:0] iomem_rdata; + + assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01); + assign iomem_ready = 1'b1; + assign iomem_wstrb = mem_wstrb; + assign iomem_addr = mem_addr; + assign iomem_wdata = mem_wdata; + + wire [31:0] spimemio_cfgreg_do; + + + always @(posedge clk) + if (iomem_valid && iomem_wstrb[0]) + led <= iomem_wdata[7:0]; + + assign mem_ready = (iomem_valid && iomem_ready) || rom_ready; + + assign mem_rdata = rom_rdata; + + picorv32 #( + .STACKADDR(STACKADDR), + .PROGADDR_RESET(PROGADDR_RESET), + .PROGADDR_IRQ(32'h 0000_0000), + .BARREL_SHIFTER(0), + .COMPRESSED_ISA(0), + .ENABLE_MUL(0), + .ENABLE_DIV(0), + .ENABLE_IRQ(0), + .ENABLE_IRQ_QREGS(0) + ) cpu ( + .clk (clk ), + .resetn (resetn ), + .mem_valid (mem_valid ), + .mem_instr (mem_instr ), + .mem_ready (mem_ready ), + .mem_addr (mem_addr ), + .mem_wdata (mem_wdata ), + .mem_wstrb (mem_wstrb ), + .mem_rdata (mem_rdata ) + ); + + + +endmodule + +// Implementation note: +// Replace the following two modules with wrappers for your SRAM cells. + +module picosoc_regs ( + input clk, wen, + input [5:0] waddr, + input [5:0] raddr1, + input [5:0] raddr2, + input [31:0] wdata, + output [31:0] rdata1, + output [31:0] rdata2 +); + reg [31:0] regs [0:31]; + + always @(posedge clk) + if (wen) regs[waddr[4:0]] <= wdata; + + assign rdata1 = regs[raddr1[4:0]]; + assign rdata2 = regs[raddr2[4:0]]; +endmodule diff --git a/xc7/attosoc.ys b/xc7/attosoc.ys new file mode 100644 index 00000000..105728c9 --- /dev/null +++ b/xc7/attosoc.ys @@ -0,0 +1,56 @@ +read_verilog attosoc_top.v +read_verilog attosoc.v +read_verilog picorv32.v +read_verilog 125MHz_to_60MHz.v + +#synth_xilinx -top picorv32 + +#begin: + read_verilog -lib +/xilinx/cells_sim.v + read_verilog -lib +/xilinx/cells_xtra.v +# read_verilog -lib +/xilinx/brams_bb.v +# read_verilog -lib +/xilinx/drams_bb.v + hierarchy -check -top top + +#flatten: (only if -flatten) + proc + flatten + +#coarse: + synth -run coarse + +#bram: +# memory_bram -rules +/xilinx/brams.txt +# techmap -map +/xilinx/brams_map.v +# +#dram: +# memory_bram -rules +/xilinx/drams.txt +# techmap -map +/xilinx/drams_map.v + +fine: + opt -fast -full + memory_map + dffsr2dff +# dff2dffe + opt -full + techmap -map +/techmap.v #-map +/xilinx/arith_map.v + opt -fast + +map_luts: + abc -luts 2:2,3,6:5 #,10,20 [-dff] + clean + +map_cells: + techmap -map +/xilinx/cells_map.v + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT + clean + +check: + hierarchy -check + stat + check -noinit + +#edif: (only if -edif) +# write_edif + +write_json attosoc.json diff --git a/xc7/attosoc_top.v b/xc7/attosoc_top.v new file mode 100644 index 00000000..5611f1d2 --- /dev/null +++ b/xc7/attosoc_top.v @@ -0,0 +1,15 @@ +module top ( + input clk, + output [3:0] led +); + + (* keep *) + wire led_unused; + + wire gclk; + //clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); + assign gclk = clk; + attosoc soc(.clk(gclk), .led({led_unused, led})); + +endmodule + From 5ddfc32c750d21d70526fa32cc1d56233baa254d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 30 Nov 2018 17:06:55 -0800 Subject: [PATCH 131/174] Add attosoc.sh and attosoc_tb.vhd --- xc7/attosoc.sh | 12 ++++++++++++ xc7/attosoc_tb.vhd | 25 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100755 xc7/attosoc.sh create mode 100644 xc7/attosoc_tb.vhd diff --git a/xc7/attosoc.sh b/xc7/attosoc.sh new file mode 100755 index 00000000..f6a125da --- /dev/null +++ b/xc7/attosoc.sh @@ -0,0 +1,12 @@ +#!/bin/bash +#set -ex +#rm -f picorv32.v +#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +yosys attosoc.ys +../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 150 +xdl -xdl2ncd attosoc.xdl +bitgen -w attosoc.ncd -g UnconstrainedPins:Allow +trce attosoc.ncd -v 10 + +netgen -sim -ofmt vhdl attosoc.ncd attosoc_pnr.vhd +ghdl -c -fexplicit --no-vital-checks --ieee=synopsys -Pxilinx-ise attosoc_tb.vhd attosoc_pnr.vhd -r testbench diff --git a/xc7/attosoc_tb.vhd b/xc7/attosoc_tb.vhd new file mode 100644 index 00000000..6ad8ed27 --- /dev/null +++ b/xc7/attosoc_tb.vhd @@ -0,0 +1,25 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +entity testbench is +end entity; +architecture rtl of testbench is + signal clk : STD_LOGIC; + signal led : STD_LOGIC_VECTOR(3 downto 0); +begin + process begin + clk <= '0'; + wait for 4 ns; + clk <= '1'; + wait for 4 ns; + end process; + + uut: entity work.name port map(clk_PAD_PAD => clk, led_0_OUTBUF_OUT => led(0), led_1_OUTBUF_OUT => led(1), led_2_OUTBUF_OUT => led(2), led_3_OUTBUF_OUT => led(3)); + +process +begin +report std_logic'image(led(3)) & std_logic'image(led(2)) & std_logic'image(led(1)) & std_logic'image(led(0)); +wait on led; +end process; + +end rtl; From 5aff7bbbc4033dca12066c99f770829e58e28f19 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Dec 2018 15:32:29 -0800 Subject: [PATCH 132/174] Fix INIT of pass-thru LUT to be "2" not "1" --- xc7/cells.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index 5d9df55a..297c45f1 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -319,7 +319,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l NPNR_ASSERT(citer == config.end()); if (pass_thru_lut) { - lc->params[ctx->id("INIT")] = "1"; + lc->params[ctx->id("INIT")] = "2"; replace_port(dff, ctx->id("D"), lc, id_I1); } From 8f0e8888156f055c8713c19fddc15107356344e1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Dec 2018 15:40:20 -0800 Subject: [PATCH 133/174] nextpnr now writes to log, netgen to overwrite --- xc7/attosoc.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/attosoc.sh b/xc7/attosoc.sh index f6a125da..e7f1c95a 100755 --- a/xc7/attosoc.sh +++ b/xc7/attosoc.sh @@ -3,10 +3,10 @@ #rm -f picorv32.v #wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v yosys attosoc.ys -../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 150 +../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 150 |& tee attosoc.log xdl -xdl2ncd attosoc.xdl bitgen -w attosoc.ncd -g UnconstrainedPins:Allow trce attosoc.ncd -v 10 -netgen -sim -ofmt vhdl attosoc.ncd attosoc_pnr.vhd +netgen -sim -ofmt vhdl attosoc.ncd -w attosoc_pnr.vhd ghdl -c -fexplicit --no-vital-checks --ieee=synopsys -Pxilinx-ise attosoc_tb.vhd attosoc_pnr.vhd -r testbench From b1b81839677aa2ee2b7b0b3cff60f20dda95476e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Dec 2018 15:41:03 -0800 Subject: [PATCH 134/174] Re-enable PLL in attosoc.v --- xc7/attosoc_top.v | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xc7/attosoc_top.v b/xc7/attosoc_top.v index 5611f1d2..b794abda 100644 --- a/xc7/attosoc_top.v +++ b/xc7/attosoc_top.v @@ -7,8 +7,8 @@ module top ( wire led_unused; wire gclk; - //clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); - assign gclk = clk; + clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); + //assign gclk = clk; attosoc soc(.clk(gclk), .led({led_unused, led})); endmodule From 20f0353f767bb1432e2bacaaa28375d24e0439e0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sun, 2 Dec 2018 15:41:30 -0800 Subject: [PATCH 135/174] Add report to attosoc_tb.vhd --- xc7/attosoc_tb.vhd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/attosoc_tb.vhd b/xc7/attosoc_tb.vhd index 6ad8ed27..fe697c3f 100644 --- a/xc7/attosoc_tb.vhd +++ b/xc7/attosoc_tb.vhd @@ -18,7 +18,7 @@ begin process begin -report std_logic'image(led(3)) & std_logic'image(led(2)) & std_logic'image(led(1)) & std_logic'image(led(0)); +report "led = " & std_logic'image(led(3)) & std_logic'image(led(2)) & std_logic'image(led(1)) & std_logic'image(led(0)); wait on led; end process; From 5f75a8447f77254a20dc2e022efc9d39265917aa Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 20:07:51 +0000 Subject: [PATCH 136/174] Merge in vx980t support --- common/place_common.cc | 2 ++ xc7/arch.cc | 10 +++++++++- xc7/arch.h | 3 ++- xc7/cells.cc | 14 +++++++++----- xc7/constids.inc | 1 + xc7/main.cc | 11 +++++++++-- xc7/xdl.cc | 15 +++++++++++++-- 7 files changed, 45 insertions(+), 11 deletions(-) diff --git a/common/place_common.cc b/common/place_common.cc index b3eb4267..2a18a1a2 100644 --- a/common/place_common.cc +++ b/common/place_common.cc @@ -37,6 +37,8 @@ wirelen_t get_net_metric(const Context *ctx, const NetInfo *net, MetricType type if (driver_gb) return 0; int clock_count; + if (ctx->getPortTimingClass(driver_cell, net->driver.port, clock_count) == TMG_IGNORE) + return 0; bool timing_driven = ctx->timing_driven && type == MetricType::COST && ctx->getPortTimingClass(driver_cell, net->driver.port, clock_count) != TMG_IGNORE; delay_t negative_slack = 0; diff --git a/xc7/arch.cc b/xc7/arch.cc index 59510591..f33c72ee 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -102,6 +102,12 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_loc.emplace_back(x, y, 0); site_index_to_bel[i] = b; ++b.index; + } else if (type == "IOB18S" || type == "IOB18M") { + bel_to_site_index.push_back(i); + site_index_to_type[i] = id_IOB18; + bel_to_loc.emplace_back(x, y, 0); + site_index_to_bel[i] = b; + ++b.index; } else { bel_to_site_index.push_back(i); site_index_to_type[i] = ctx->id(type); @@ -337,6 +343,8 @@ Arch::Arch(ArchArgs args) : args(args) } #endif } + } else if (args.type == ArchArgs::VX980) { + torc_info = std::unique_ptr(new TorcInfo(this, "xc7vx980t", args.package)); } else { log_error("Unsupported XC7 chip type.\n"); } @@ -922,7 +930,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in } // TODO // if (port == id_OMUX) - } else if (cell->type == id_IOB33) { + } else if (cell->type == id_IOB33 || cell->type == id_IOB18) { if (port == id_I) return TMG_STARTPOINT; else if (port == id_O) diff --git a/xc7/arch.h b/xc7/arch.h index fe89208b..1d4af94f 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -489,7 +489,8 @@ struct ArchArgs enum ArchArgsTypes { NONE, - Z020 + Z020, + VX980 } type = NONE; std::string package; }; diff --git a/xc7/cells.cc b/xc7/cells.cc index 297c45f1..817fbab6 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -70,11 +70,15 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { - new_cell->type = id_IOB33; - new_cell->params[ctx->id("PIN_TYPE")] = "0"; - new_cell->params[ctx->id("PULLUP")] = "0"; - new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; - new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; + if (ctx->args.type == ArchArgs::Z020) { + new_cell->type = id_IOB33; + } else { + new_cell->type = id_IOB18; + } + //new_cell->params[ctx->id("PIN_TYPE")] = "0"; + //new_cell->params[ctx->id("PULLUP")] = "0"; + //new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; + //new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; // add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); // diff --git a/xc7/constids.inc b/xc7/constids.inc index 0bc012b3..d9fee532 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -458,5 +458,6 @@ X(FDPE) X(BUFGCTRL) X(SLICE_LUT6) X(IOB33) +X(IOB18) X(PS7) X(MMCME2_ADV) diff --git a/xc7/main.cc b/xc7/main.cc index 65fabff4..cac9a397 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -51,8 +51,9 @@ Xc7CommandHandler::Xc7CommandHandler(int argc, char **argv) : CommandHandler(arg po::options_description Xc7CommandHandler::getArchOptions() { po::options_description specific("Architecture specific options"); - specific.add_options()("xc7z020", "set device type to xc7z020"); - // specific.add_options()("package", po::value(), "set device package"); + specific.add_options()("z020", "set device type to xc7z020"); + specific.add_options()("vx980", "set device type to xc7v980"); + specific.add_options()("package", po::value(), "set device package"); specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); @@ -97,6 +98,12 @@ std::unique_ptr Xc7CommandHandler::createContext() chipArgs.package = "clg400"; } + if (vm.count("vx980")) { + chipArgs.type = ArchArgs::VX980; + chipArgs.package = "ffg1926"; + } + + if (chipArgs.type == ArchArgs::NONE) { chipArgs.type = ArchArgs::Z020; chipArgs.package = "clg400"; diff --git a/xc7/xdl.cc b/xc7/xdl.cc index ea834593..63d67749 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -68,7 +68,7 @@ void write_xdl(const Context *ctx, std::ostream &out) const char *type; if (cell.second->type == id_SLICE_LUT6) type = "SLICEL"; - else if (cell.second->type == id_IOB33 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) + else if (cell.second->type == id_IOB33 || cell.second->type == id_IOB18 || cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) type = cell.second->type.c_str(ctx); else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); @@ -111,7 +111,7 @@ void write_xdl(const Context *ctx, std::ostream &out) // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t if (lut_inputs.size() < 6) { auto init_as_uint = boost::lexical_cast(init); - NPNR_ASSERT(init_as_uint < (1ull << (1u << lut_inputs.size()))); + NPNR_ASSERT(init_as_uint <= (1ull << (1u << lut_inputs.size()))); if (lut_inputs.empty()) value += init; else { @@ -198,6 +198,17 @@ void write_xdl(const Context *ctx, std::ostream &out) } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) { for (const auto& i : cell.second->params) instPtr->setConfig(i.first.str(ctx), "", i.second); + } else if (cell.second->type == id_IOB18) { + if (get_net_or_empty(cell.second.get(), id_I)) { + instPtr->setConfig("IUSED", "", "0"); + instPtr->setConfig("IBUF_LOW_PWR", "", "TRUE"); + instPtr->setConfig("ISTANDARD", "", "LVCMOS18"); + } else { + instPtr->setConfig("OUSED", "", "0"); + instPtr->setConfig("OSTANDARD", "", "LVCMOS18"); + instPtr->setConfig("DRIVE", "", "12"); + instPtr->setConfig("SLEW", "", "SLOW"); + } } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From 557011cfe671ba37ccbde3bccb5e6fe8d53096e2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 14:51:24 -0800 Subject: [PATCH 137/174] Have a go at generating FASM from Torc XDL --- xc7/main.cc | 6 +++ xc7/xdl.cc | 142 +++++++++++++++++++++++++++++++++++++++++----------- xc7/xdl.h | 1 + 3 files changed, 120 insertions(+), 29 deletions(-) diff --git a/xc7/main.cc b/xc7/main.cc index cac9a397..1ff585b3 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -56,6 +56,7 @@ po::options_description Xc7CommandHandler::getArchOptions() specific.add_options()("package", po::value(), "set device package"); specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); + specific.add_options()("fasm", po::value(), "FASM file to write"); // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); return specific; } @@ -83,6 +84,11 @@ void Xc7CommandHandler::customBitstream(Context *ctx) std::ofstream f(filename); write_xdl(ctx, f); } + if (vm.count("fasm")) { + std::string filename = vm["fasm"].as(); + std::ofstream f(filename); + write_fasm(ctx, f); + } } void Xc7CommandHandler::setupArchContext(Context *ctx) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 63d67749..81b11c00 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -25,6 +25,7 @@ #include "log.h" #include "nextpnr.h" #include "util.h" +#include #include "torc/Physical.hpp" using namespace torc::architecture::xilinx; @@ -32,9 +33,8 @@ using namespace torc::physical; NEXTPNR_NAMESPACE_BEGIN -void write_xdl(const Context *ctx, std::ostream &out) +DesignSharedPtr create_torc_design(const Context *ctx) { - XdlExporter exporter(out); auto designPtr = Factory::newDesignPtr("name", torc_info->ddb->getDeviceName(), ctx->args.package, "-1", ""); std::unordered_map site_to_instance; @@ -232,40 +232,124 @@ void write_xdl(const Context *ctx, std::ostream &out) auto pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); netPtr->addSource(pinPtr); - for (const auto &user : net.second->users) { - site_index = torc_info->bel_to_site_index[user.cell->bel.index]; - instPtr = site_to_instance.at(site_index); + if (!net.second->users.empty()) { + for (const auto &user : net.second->users) { + site_index = torc_info->bel_to_site_index[user.cell->bel.index]; + instPtr = site_to_instance.at(site_index); - pin_name = user.port.str(ctx); - // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT - if (user.cell->type == id_SLICE_LUT6 && (pin_name[0] == 'I' || pin_name[0] == 'O')) { - const auto lut = bel_to_lut(user.cell->bel); - pin_name[0] = lut[0]; + pin_name = user.port.str(ctx); + // For all LUT based inputs and outputs (I1-I6,O,OQ,OMUX) then change the I/O into the LUT + if (user.cell->type == id_SLICE_LUT6 && (pin_name[0] == 'I' || pin_name[0] == 'O')) { + const auto lut = bel_to_lut(user.cell->bel); + pin_name[0] = lut[0]; + } + else { + // e.g. Convert DDRARB[0] -> DDRARB0 + pin_name.erase(std::remove_if(pin_name.begin(), pin_name.end(), boost::is_any_of("[]")), pin_name.end()); + } + pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); + netPtr->addSink(pinPtr); } - else { - // e.g. Convert DDRARB[0] -> DDRARB0 - pin_name.erase(std::remove_if(pin_name.begin(), pin_name.end(), boost::is_any_of("[]")), pin_name.end()); + + auto b = designPtr->addNet(netPtr); + assert(b); + + for (const auto &i : net.second->wires) { + const auto &pip_map = i.second; + if (pip_map.pip == PipId()) + continue; + ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSourceTilewire()); + ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSinkTilewire()); + auto p = Factory::newPip(ewi_src.mTileName, ewi_src.mWireName, ewi_dst.mWireName, + ePipUnidirectionalBuffered); + netPtr->addPip(p); } - pinPtr = Factory::newInstancePinPtr(instPtr, pin_name); - netPtr->addSink(pinPtr); - } - - auto b = designPtr->addNet(netPtr); - assert(b); - - for (const auto &i : net.second->wires) { - const auto &pip_map = i.second; - if (pip_map.pip == PipId()) - continue; - ExtendedWireInfo ewi_src(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSourceTilewire()); - ExtendedWireInfo ewi_dst(*torc_info->ddb, torc_info->pip_to_arc[pip_map.pip.index].getSinkTilewire()); - auto p = Factory::newPip(ewi_src.mTileName, ewi_src.mWireName, ewi_dst.mWireName, - ePipUnidirectionalBuffered); - netPtr->addPip(p); } } + return designPtr; +} + +void write_xdl(const Context *ctx, std::ostream &out) +{ + XdlExporter exporter(out); + auto designPtr = create_torc_design(ctx); exporter(designPtr); } +void write_fasm(const Context *ctx, std::ostream &out) +{ + auto designPtr = create_torc_design(ctx); + + static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); + boost::smatch what; + + // export the instances + Circuit::InstanceSharedPtrConstIterator pi = designPtr->instancesBegin(); + Circuit::InstanceSharedPtrConstIterator ei = designPtr->instancesEnd(); + for (; pi < ei; ++pi) { + std::stringstream ss; + ss << (*pi)->getTile() << '.'; + const auto& type = (*pi)->getType(); + if (type == "SLICEL") { + const auto& site_name = (*pi)->getSite(); + if (!boost::regex_match(site_name, what, re_loc)) + throw; + + const auto x = boost::lexical_cast(what.str(1)); + ss << type << "_X" << static_cast(x & 1) << '.'; + + out << "# " << (*pi)->getName() << std::endl; + + auto pc = (*pi)->configBegin(); + auto ec = (*pi)->configEnd(); + for (; pc != ec; ++pc) + if (pc->first == "A6LUT" || pc->first == "B6LUT" || pc->first == "C6LUT" || pc->first == "D6LUT") { + auto name = pc->second.getName(); + boost::replace_all(name, "\\:", ":"); + auto it = ctx->cells.find(ctx->id(name)); + if (it == ctx->cells.end()) it = ctx->cells.find(ctx->id(name + "_LC")); + assert(it != ctx->cells.end()); + auto cell = it->second.get(); + const auto &init = cell->params[ctx->id("INIT")]; + if (cell->lcInfo.inputCount <= 5) { + auto num_bits = (1 << cell->lcInfo.inputCount); + auto init_as_uint = boost::lexical_cast(init); + out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT"; + out << "[" << num_bits-1 << ":0]" << "="; + out << num_bits << "'b"; + for (auto i = 0; i < num_bits; ++i) + out << ((init_as_uint >> i) & 1 ? '1' : '0'); + out << std::endl; + } + else { + out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[31:0]="; + out << "32'b" << boost::adaptors::reverse(init.substr(0,32)) << std::endl; + out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[63:32]="; + out << "32'b" << boost::adaptors::reverse(init.substr(32,32)) << std::endl; + } + } + else + out << ss.str() << pc->first << '.' << pc->second.getValue() << std::endl; + + out << std::endl; + } + } + + // export the nets + Circuit::NetSharedPtrConstIterator pn = designPtr->netsBegin(); + Circuit::NetSharedPtrConstIterator en = designPtr->netsEnd(); + for (; pn < en; ++pn) { + + out << "# " << (*pn)->getName() << std::endl; + + auto pp = (*pn)->pipsBegin(); + auto ep = (*pn)->pipsEnd(); + for (; pp != ep; ++pp) + out << pp->getTileName() << "." << pp->getSourceWireName() << "." << pp->getSinkWireName() << std::endl; + + out << std::endl; + } +} + NEXTPNR_NAMESPACE_END diff --git a/xc7/xdl.h b/xc7/xdl.h index 19bc5478..19ee10cc 100644 --- a/xc7/xdl.h +++ b/xc7/xdl.h @@ -27,6 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN void write_xdl(const Context *ctx, std::ostream &out); +void write_fasm(const Context *ctx, std::ostream &out); NEXTPNR_NAMESPACE_END From c708a4e0d39248e4b319d4b68ce42bd386450652 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 16:11:15 -0800 Subject: [PATCH 138/174] Fix leftover divide by 2 in Arch::estimateDelay() --- xc7/delay.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index 0df02f7e..6606fc37 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,8 +104,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - auto abs_delta_x = (abs(src_info.getCol() - dst_info.getCol()) + 1) / - 2; // Divide by 2 because XDL coordinate space counts the INT tiles between CLBs + auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); #if 1 auto div_LH = std::div(abs_delta_x, 12); From 66f22150b1a7ca9724baaea191a434fbea5e59df Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 16:49:35 -0800 Subject: [PATCH 139/174] Improve estimateDelay for global clocks --- xc7/arch.cc | 6 +++++- xc7/arch.h | 2 ++ xc7/delay.cc | 45 ++++++++++++++++++++++++++++----------------- 3 files changed, 35 insertions(+), 18 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index f33c72ee..94afaf1b 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -232,6 +232,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str wire_to_tilewire.shrink_to_fit(); wire_to_delay.shrink_to_fit(); num_wires = wire_to_tilewire.size(); + wire_is_clk.resize(num_wires); wire_to_pips_downhill.resize(num_wires); // std::unordered_map arc_to_pip; @@ -256,9 +257,12 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str auto &pips = wire_to_pips_downhill[w.index]; pips.reserve(arcs.size()); - const bool clk_tile = boost::starts_with(tileTypeName, "CMT") || boost::starts_with(tileTypeName, "CLK"); + const bool clk_tile = boost::starts_with(tileTypeName, "CLK"); const bool int_tile = boost::starts_with(tileTypeName, "INT"); + if (clk_tile) + wire_is_clk[w.index] = clk_tile; + for (const auto &a : arcs) { // Disable BUFG I0 -> O routethrough if (clk_tile) { diff --git a/xc7/arch.h b/xc7/arch.h index 1d4af94f..01a9475b 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -324,6 +324,7 @@ struct TorcInfo std::vector pip_to_dst_wire; int width; int height; + std::vector wire_is_clk; TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); private: @@ -347,6 +348,7 @@ private: ar & pip_to_arc; ar & num_pips; ar & pip_to_dst_wire; + ar & wire_is_clk; } }; extern std::unique_ptr torc_info; diff --git a/xc7/delay.cc b/xc7/delay.cc index 6606fc37..a2ffc870 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -104,26 +104,37 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); - auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); + + if (!torc_info->wire_is_clk[src.index]) { + auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); + auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); #if 1 - auto div_LH = std::div(abs_delta_x, 12); - auto div_LV = std::div(abs_delta_y, 18); - auto div_LVB = std::div(div_LV.rem, 12); - auto div_H6 = std::div(div_LH.rem, 6); - auto div_V6 = std::div(div_LVB.rem, 6); - auto div_H4 = std::div(div_H6.rem, 4); - auto div_V4 = std::div(div_V6.rem, 4); - auto div_H2 = std::div(div_H4.rem, 2); - auto div_V2 = std::div(div_V4.rem, 2); - auto num_H1 = div_H2.rem; - auto num_V1 = div_V2.rem; - return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + - (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + - (num_H1 + num_V1) * 150; + auto div_LH = std::div(abs_delta_x, 12); + auto div_LV = std::div(abs_delta_y, 18); + auto div_LVB = std::div(div_LV.rem, 12); + auto div_H6 = std::div(div_LH.rem, 6); + auto div_V6 = std::div(div_LVB.rem, 6); + auto div_H4 = std::div(div_H6.rem, 4); + auto div_V4 = std::div(div_V6.rem, 4); + auto div_H2 = std::div(div_H4.rem, 2); + auto div_V2 = std::div(div_V4.rem, 2); + auto num_H1 = div_H2.rem; + auto num_V1 = div_V2.rem; + return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + + (num_H1 + num_V1) * 150; #else - return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); + return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); #endif + } + else { + auto src_y = src_info.getRow(); + auto dst_y = dst_info.getRow(); + src_y -= src_y % 50; + dst_y -= dst_y % 50; + auto abs_delta_y = abs(src_y - dst_y); + return abs_delta_y * 64; // arbitrary factor + } } delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const From 904860b2b42a3c4f6068fb8a898cd1075afae8f7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 16:53:48 -0800 Subject: [PATCH 140/174] Add comment --- xc7/arch.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xc7/arch.cc b/xc7/arch.cc index 94afaf1b..71852a9a 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -99,12 +99,14 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str } else if (type == "IOB33S" || type == "IOB33M") { bel_to_site_index.push_back(i); site_index_to_type[i] = id_IOB33; + // TODO: Fix z when two IOBs on same tile bel_to_loc.emplace_back(x, y, 0); site_index_to_bel[i] = b; ++b.index; } else if (type == "IOB18S" || type == "IOB18M") { bel_to_site_index.push_back(i); site_index_to_type[i] = id_IOB18; + // TODO: Fix z when two IOBs on same tile bel_to_loc.emplace_back(x, y, 0); site_index_to_bel[i] = b; ++b.index; From 8c448884666ea089a7f3ec2c4a304511afc638e0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 17:40:15 -0800 Subject: [PATCH 141/174] Fix delay prediction --- xc7/arch.cc | 28 ++++++++++++++++++---------- xc7/arch.h | 6 ++++-- xc7/delay.cc | 22 +++++++--------------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 71852a9a..96c574d6 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -57,6 +57,16 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str { static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); boost::cmatch what; + tile_to_xy.resize(tiles.getTileCount()); + for (TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { + const auto &tileInfo = tiles.getTileInfo(tileIndex); + if (!boost::regex_match(tileInfo.getName(), what, re_loc)) + throw; + const auto x = boost::lexical_cast(what.str(1)); + const auto y = boost::lexical_cast(what.str(2)); + tile_to_xy[tileIndex] = std::make_pair(x,y); + } + bel_to_site_index.reserve(sites.getSiteCount() * 4); bel_to_loc.reserve(sites.getSiteCount() * 4); site_index_to_bel.resize(sites.getSiteCount()); @@ -67,11 +77,8 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const auto &site = sites.getSite(i); const auto &pd = site.getPrimitiveDefPtr(); const auto &type = pd->getName(); - const auto &tileInfo = tiles.getTileInfo(site.getTileIndex()); - if (!boost::regex_match(tileInfo.getName(), what, re_loc)) - throw; - const auto x = boost::lexical_cast(what.str(1)); - const auto y = boost::lexical_cast(what.str(2)); + int x, y; + std::tie(x,y) = tile_to_xy[site.getTileIndex()]; if (type == "SLICEL" || type == "SLICEM") { bel_to_site_index.push_back(i); @@ -129,8 +136,8 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const boost::regex re_BOUNCE_NS("(BYP|FAN)_BOUNCE_[NS]3_\\d"); const boost::regex re_FAN("FAN(_ALT)?\\d"); const boost::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); - const boost::regex bufg_i("(CMT|CLK)_BUFG_BUFGCTRL\\d+_I0"); - const boost::regex bufg_o("(CMT|CLK)_BUFG_BUFGCTRL\\d+_O"); + const boost::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); + const boost::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); const boost::regex int_clk("CLK(_L)?[01]"); const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); std::unordered_map> delay_lookup; @@ -234,7 +241,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str wire_to_tilewire.shrink_to_fit(); wire_to_delay.shrink_to_fit(); num_wires = wire_to_tilewire.size(); - wire_is_clk.resize(num_wires); + wire_is_global.resize(num_wires); wire_to_pips_downhill.resize(num_wires); // std::unordered_map arc_to_pip; @@ -262,8 +269,9 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const bool clk_tile = boost::starts_with(tileTypeName, "CLK"); const bool int_tile = boost::starts_with(tileTypeName, "INT"); - if (clk_tile) - wire_is_clk[w.index] = clk_tile; + const bool global_tile = boost::starts_with(tileTypeName, "CLK") || boost::starts_with(tileTypeName, "HCLK") || boost::starts_with(tileTypeName, "CFG"); + if (global_tile) + wire_is_global[w.index] = true; for (const auto &a : arcs) { // Disable BUFG I0 -> O routethrough diff --git a/xc7/arch.h b/xc7/arch.h index 01a9475b..b3145b6d 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -324,7 +324,8 @@ struct TorcInfo std::vector pip_to_dst_wire; int width; int height; - std::vector wire_is_clk; + std::vector wire_is_global; + std::vector> tile_to_xy; TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); private: @@ -348,7 +349,8 @@ private: ar & pip_to_arc; ar & num_pips; ar & pip_to_dst_wire; - ar & wire_is_clk; + ar & wire_is_global; + ar & tile_to_xy; } }; extern std::unique_ptr torc_info; diff --git a/xc7/delay.cc b/xc7/delay.cc index a2ffc870..722e6932 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -101,14 +101,13 @@ void ice40DelayFuzzerMain(Context *ctx) delay_t Arch::estimateDelay(WireId src, WireId dst) const { const auto &src_tw = torc_info->wire_to_tilewire[src.index]; - const auto &src_info = torc_info->tiles.getTileInfo(src_tw.getTileIndex()); + const auto &src_loc = torc_info->tile_to_xy[src_tw.getTileIndex()]; const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; - const auto &dst_info = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); + const auto &dst_loc = torc_info->tile_to_xy[dst_tw.getTileIndex()]; - if (!torc_info->wire_is_clk[src.index]) { - auto abs_delta_x = abs(src_info.getCol() - dst_info.getCol()); - auto abs_delta_y = abs(src_info.getRow() - dst_info.getRow()); -#if 1 + if (!torc_info->wire_is_global[src.index] || torc_info->wire_is_global[dst.index]) { + auto abs_delta_x = abs(dst_loc.first - src_loc.first); + auto abs_delta_y = abs(dst_loc.second - src_loc.second); auto div_LH = std::div(abs_delta_x, 12); auto div_LV = std::div(abs_delta_y, 18); auto div_LVB = std::div(div_LV.rem, 12); @@ -123,13 +122,10 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + (num_H1 + num_V1) * 150; -#else - return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); -#endif } else { - auto src_y = src_info.getRow(); - auto dst_y = dst_info.getRow(); + auto src_y = src_loc.second; + auto dst_y = dst_loc.second; src_y -= src_y % 50; dst_y -= dst_y % 50; auto abs_delta_y = abs(src_y - dst_y); @@ -144,7 +140,6 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const auto sink_loc = getBelLocation(sink.cell->bel); auto abs_delta_x = abs(driver_loc.x - sink_loc.x); auto abs_delta_y = abs(driver_loc.y - sink_loc.y); -#if 1 auto div_LH = std::div(abs_delta_x, 12); auto div_LV = std::div(abs_delta_y, 18); auto div_LVB = std::div(div_LV.rem, 12); @@ -159,9 +154,6 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const return div_LH.quot * 360 + div_LVB.quot * 300 + div_LV.quot * 350 + (div_H6.quot + div_H4.quot + div_V6.quot + div_V4.quot) * 210 + (div_H2.quot + div_V2.quot) * 170 + (num_H1 + num_V1) * 150; -#else - return std::max(150, 33 * abs_delta_x + 66 * abs_delta_y); -#endif } NEXTPNR_NAMESPACE_END From 236ca15b49d454ce8d341ce641980f8506cf439c Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 6 Dec 2018 18:02:10 -0800 Subject: [PATCH 142/174] Place blinky BUFG in dedicated location for input pin --- xc7/blinky.pcf | 1 + 1 file changed, 1 insertion(+) diff --git a/xc7/blinky.pcf b/xc7/blinky.pcf index 6c2e5149..1b85ac5f 100644 --- a/xc7/blinky.pcf +++ b/xc7/blinky.pcf @@ -3,6 +3,7 @@ COMP "led1" LOCATE = SITE "M15" LEVEL 1; COMP "led2" LOCATE = SITE "G14" LEVEL 1; COMP "led3" LOCATE = SITE "D18" LEVEL 1; COMP "clki" LOCATE = SITE "K17" LEVEL 1; +COMP "clk_gb" LOCATE = SITE "BUFGCTRL_X0Y31" LEVEL 1; NET "clki" PERIOD = 8 nS ; PIN "clki_pin" = BEL "clki.PAD" PINNAME PAD; PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; From 550271b338d45077cc0ca789416de3529ad3470b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Dec 2018 22:22:30 +0000 Subject: [PATCH 143/174] Cleanup XDL generation --- xc7/cells.cc | 52 ++++++++++++++++++++++++++++++++++++---------------- xc7/xdl.cc | 27 +++++++++++++++------------ 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index 817fbab6..68da9907 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -48,8 +48,6 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri new_cell->params[ctx->id("NEG_CLK")] = "0"; new_cell->params[ctx->id("CARRY_ENABLE")] = "0"; new_cell->params[ctx->id("DFF_ENABLE")] = "0"; - new_cell->params[ctx->id("SET_NORESET")] = "0"; - new_cell->params[ctx->id("ASYNC_SR")] = "0"; new_cell->params[ctx->id("CIN_CONST")] = "0"; new_cell->params[ctx->id("CIN_SET")] = "0"; @@ -290,34 +288,56 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l replace_port(dff, ctx->id("C"), lc, ctx->id("CLK")); if (citer != config.end()) { - if (*citer == 'C' || *citer == 'P') - lc->params[ctx->id("ASYNC_SR")] = "1"; - else - lc->params[ctx->id("ASYNC_SR")] = "0"; + auto gnd_net = ctx->nets.at(ctx->id("$PACKER_GND_NET")).get(); if (*citer == 'S') { citer++; - replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "1"; + if (get_net_or_empty(dff, ctx->id("S")) != gnd_net) { + lc->params[ctx->id("SR")] = "SRHIGH"; + lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; + replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); + } + else + disconnect_port(ctx, dff, ctx->id("S")); } else if (*citer == 'R') { citer++; - replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "0"; + if (get_net_or_empty(dff, ctx->id("R")) != gnd_net) { + lc->params[ctx->id("SR")] = "SRLOW"; + lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; + replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); + } + else + disconnect_port(ctx, dff, ctx->id("R")); } else if (*citer == 'C') { citer++; - replace_port(dff, ctx->id("CLR"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "0"; + if (get_net_or_empty(dff, ctx->id("CLR")) != gnd_net) { + lc->params[ctx->id("SR")] = "SRLOW"; + lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; + replace_port(dff, ctx->id("CLR"), lc, ctx->id("SR")); + } + else + disconnect_port(ctx, dff, ctx->id("CLR")); } else { NPNR_ASSERT(*citer == 'P'); citer++; - replace_port(dff, ctx->id("PRE"), lc, ctx->id("SR")); - lc->params[ctx->id("SET_NORESET")] = "1"; + if (get_net_or_empty(dff, ctx->id("PRE")) != gnd_net) { + lc->params[ctx->id("SR")] = "SRHIGH"; + lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; + replace_port(dff, ctx->id("PRE"), lc, ctx->id("SR")); + } + else + disconnect_port(ctx, dff, ctx->id("PRE")); } } if (citer != config.end() && *citer == 'E') { - replace_port(dff, ctx->id("CE"), lc, ctx->id("CE")); + auto vcc_net = ctx->nets.at(ctx->id("$PACKER_VCC_NET")).get(); + ++citer; + if (get_net_or_empty(dff, ctx->id("CE")) != vcc_net) + replace_port(dff, ctx->id("CE"), lc, ctx->id("CE")); + else + disconnect_port(ctx, dff, ctx->id("CE")); } NPNR_ASSERT(citer == config.end()); @@ -331,7 +351,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l auto it = dff->params.find(ctx->id("INIT")); if (it != dff->params.end()) - lc->params[ctx->id("DFF_INIT")] = it->second; + lc->params[ctx->id("FFINIT")] = it->second == "1" ? "INIT1" : "INIT0"; } void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 81b11c00..fabffbfc 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -111,7 +111,7 @@ DesignSharedPtr create_torc_design(const Context *ctx) // Assume from Yosys that INIT masks of less than 32 bits are output as uint32_t if (lut_inputs.size() < 6) { auto init_as_uint = boost::lexical_cast(init); - NPNR_ASSERT(init_as_uint <= (1ull << (1u << lut_inputs.size()))); + NPNR_ASSERT(init_as_uint <= ((1ull << (1u << lut_inputs.size())) - 1)); if (lut_inputs.empty()) value += init; else { @@ -173,16 +173,19 @@ DesignSharedPtr create_torc_design(const Context *ctx) boost::replace_all(name, ":", "\\:"); instPtr->setConfig(setting, name, "#FF"); instPtr->setConfig(setting + "MUX", "", "O6"); - instPtr->setConfig(setting + "INIT", "", "INIT" + cell.second->params.at(ctx->id("DFF_INIT"))); - assert(cell.second->params.at(ctx->id("SET_NORESET")) == "0"); // TODO - instPtr->setConfig(setting + "SR", "", "SRLOW"); + instPtr->setConfig(setting + "INIT", "", cell.second->params.at(ctx->id("FFINIT"))); - NPNR_ASSERT(!cell.second->lcInfo.negClk); // TODO - instPtr->setConfig("CLKINV", "", "CLK"); + if (cell.second->lcInfo.negClk) + instPtr->setConfig("CLKINV", "", "CLK_B"); + + if (get_net_or_empty(cell.second.get(), ctx->id("SR"))) { + instPtr->setConfig(setting + "SR", "", cell.second->params.at(ctx->id("SR"))); + instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); + instPtr->setConfig("SRUSEDMUX", "", "IN"); + } + if (get_net_or_empty(cell.second.get(), ctx->id("CE"))) + instPtr->setConfig("CEUSEDMUX", "", "IN"); - instPtr->setConfig("SRUSEDMUX", "", "IN"); - instPtr->setConfig("CEUSEDMUX", "", "IN"); - instPtr->setConfig("SYNC_ATTR", "", "ASYNC"); } } else if (cell.second->type == id_IOB33) { if (get_net_or_empty(cell.second.get(), id_I)) { @@ -195,9 +198,6 @@ DesignSharedPtr create_torc_design(const Context *ctx) instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } - } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) { - for (const auto& i : cell.second->params) - instPtr->setConfig(i.first.str(ctx), "", i.second); } else if (cell.second->type == id_IOB18) { if (get_net_or_empty(cell.second.get(), id_I)) { instPtr->setConfig("IUSED", "", "0"); @@ -209,6 +209,9 @@ DesignSharedPtr create_torc_design(const Context *ctx) instPtr->setConfig("DRIVE", "", "12"); instPtr->setConfig("SLEW", "", "SLOW"); } + } else if (cell.second->type == id_BUFGCTRL || cell.second->type == id_PS7 || cell.second->type == id_MMCME2_ADV) { + for (const auto& i : cell.second->params) + instPtr->setConfig(i.first.str(ctx), "", i.second); } else log_error("Unsupported cell type '%s'.\n", cell.second->type.c_str(ctx)); } From cadafffbecd03eed053a5c52f986d842a13633f3 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Dec 2018 22:23:15 +0000 Subject: [PATCH 144/174] Missing files --- xc7/cells.cc | 46 +++++++++++++++++++++++----------------------- xc7/constids.inc | 4 ++++ xc7/pack.cc | 2 +- xc7/xdl.cc | 4 ++-- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index 68da9907..b7aefce6 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -285,48 +285,48 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l lc->params[ctx->id("DFF_ENABLE")] = "1"; std::string config = dff->type.str(ctx).substr(2); auto citer = config.begin(); - replace_port(dff, ctx->id("C"), lc, ctx->id("CLK")); + replace_port(dff, id_C, lc, id_CLK); if (citer != config.end()) { auto gnd_net = ctx->nets.at(ctx->id("$PACKER_GND_NET")).get(); if (*citer == 'S') { citer++; - if (get_net_or_empty(dff, ctx->id("S")) != gnd_net) { - lc->params[ctx->id("SR")] = "SRHIGH"; + if (get_net_or_empty(dff, id_S) != gnd_net) { + lc->params[id_SR] = "SRHIGH"; lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; - replace_port(dff, ctx->id("S"), lc, ctx->id("SR")); + replace_port(dff, id_S, lc, id_SR); } else - disconnect_port(ctx, dff, ctx->id("S")); + disconnect_port(ctx, dff, id_S); } else if (*citer == 'R') { citer++; - if (get_net_or_empty(dff, ctx->id("R")) != gnd_net) { - lc->params[ctx->id("SR")] = "SRLOW"; + if (get_net_or_empty(dff, id_R) != gnd_net) { + lc->params[id_SR] = "SRLOW"; lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; - replace_port(dff, ctx->id("R"), lc, ctx->id("SR")); + replace_port(dff, id_R, lc, id_SR); } else - disconnect_port(ctx, dff, ctx->id("R")); + disconnect_port(ctx, dff, id_R); } else if (*citer == 'C') { citer++; - if (get_net_or_empty(dff, ctx->id("CLR")) != gnd_net) { - lc->params[ctx->id("SR")] = "SRLOW"; + if (get_net_or_empty(dff, id_CLR) != gnd_net) { + lc->params[id_SR] = "SRLOW"; lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; - replace_port(dff, ctx->id("CLR"), lc, ctx->id("SR")); + replace_port(dff, id_CLR, lc, id_SR); } else - disconnect_port(ctx, dff, ctx->id("CLR")); + disconnect_port(ctx, dff, id_CLR); } else { NPNR_ASSERT(*citer == 'P'); citer++; - if (get_net_or_empty(dff, ctx->id("PRE")) != gnd_net) { - lc->params[ctx->id("SR")] = "SRHIGH"; + if (get_net_or_empty(dff, id_PRE) != gnd_net) { + lc->params[id_SR] = "SRHIGH"; lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; - replace_port(dff, ctx->id("PRE"), lc, ctx->id("SR")); + replace_port(dff, id_PRE, lc, id_SR); } else - disconnect_port(ctx, dff, ctx->id("PRE")); + disconnect_port(ctx, dff, id_PRE); } } @@ -410,14 +410,14 @@ bool is_clock_port(const BaseCtx *ctx, const PortRef &port) if (port.cell == nullptr) return false; if (is_ff(ctx, port.cell)) - return port.port == ctx->id("C"); + return port.port == id_C; if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == ctx->id("CLK"); + return port.port == id_CLK; if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") || port.port == ctx->id("WCLKN"); if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) - return port.port == ctx->id("CLK"); + return port.port == id_CLK; return false; } @@ -426,9 +426,9 @@ bool is_reset_port(const BaseCtx *ctx, const PortRef &port) if (port.cell == nullptr) return false; if (is_ff(ctx, port.cell)) - return port.port == ctx->id("R") || port.port == ctx->id("S"); + return port.port == id_R || port.port == id_S; if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == ctx->id("SR"); + return port.port == id_SR; if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) return port.port == ctx->id("IRSTTOP") || port.port == ctx->id("IRSTBOT") || port.port == ctx->id("ORSTTOP") || port.port == ctx->id("ORSTBOT"); @@ -442,7 +442,7 @@ bool is_enable_port(const BaseCtx *ctx, const PortRef &port) if (is_ff(ctx, port.cell)) return port.port == ctx->id("E"); if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == ctx->id("CEN"); + return port.port == id_CEN; // FIXME // if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) // return port.port == ctx->id("CE"); diff --git a/xc7/constids.inc b/xc7/constids.inc index d9fee532..7fae17e6 100644 --- a/xc7/constids.inc +++ b/xc7/constids.inc @@ -14,6 +14,10 @@ X(COUT) X(CEN) X(CLK) X(SR) +X(S) +X(R) +X(PRE) +X(CLR) X(MASK_0) X(MASK_1) diff --git a/xc7/pack.cc b/xc7/pack.cc index 5137757f..14ec4fe7 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -309,7 +309,7 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne !constval) { uc->ports[user.port].net = nullptr; } else if ((is_sb_mac16(ctx, uc) || uc->type == ctx->id("ICESTORM_DSP")) && - (user.port != ctx->id("CLK") && + (user.port != id_CLK && ((constval && user.port == ctx->id("CE")) || (!constval && user.port != ctx->id("CE"))))) { uc->ports[user.port].net = nullptr; } else if (is_ram(ctx, uc) && !constval && user.port != ctx->id("RCLK") && user.port != ctx->id("RCLKN") && diff --git a/xc7/xdl.cc b/xc7/xdl.cc index fabffbfc..3940f070 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -178,8 +178,8 @@ DesignSharedPtr create_torc_design(const Context *ctx) if (cell.second->lcInfo.negClk) instPtr->setConfig("CLKINV", "", "CLK_B"); - if (get_net_or_empty(cell.second.get(), ctx->id("SR"))) { - instPtr->setConfig(setting + "SR", "", cell.second->params.at(ctx->id("SR"))); + if (get_net_or_empty(cell.second.get(), id_SR)) { + instPtr->setConfig(setting + "SR", "", cell.second->params.at(id_SR)); instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); instPtr->setConfig("SRUSEDMUX", "", "IN"); } From 0146312707e91bad72b79842ca79dc9dda84e695 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Dec 2018 14:31:24 -0800 Subject: [PATCH 145/174] Fixes --- xc7/blinky.sh | 2 +- xc7/cells.cc | 4 ++-- xc7/xdl.cc | 10 ++++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/xc7/blinky.sh b/xc7/blinky.sh index 1ba77434..dff168e0 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex yosys blinky.ys -../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 +- ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 xdl -xdl2ncd blinky.xdl bitgen -w blinky.ncd -g UnconstrainedPins:Allow trce blinky.ncd -v 10 diff --git a/xc7/cells.cc b/xc7/cells.cc index b7aefce6..e95de384 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -285,7 +285,7 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l lc->params[ctx->id("DFF_ENABLE")] = "1"; std::string config = dff->type.str(ctx).substr(2); auto citer = config.begin(); - replace_port(dff, id_C, lc, id_CLK); + replace_port(dff, ctx->id("C"), lc, id_CLK); if (citer != config.end()) { auto gnd_net = ctx->nets.at(ctx->id("$PACKER_GND_NET")).get(); @@ -410,7 +410,7 @@ bool is_clock_port(const BaseCtx *ctx, const PortRef &port) if (port.cell == nullptr) return false; if (is_ff(ctx, port.cell)) - return port.port == id_C; + return port.port == ctx->id("C"); if (port.cell->type == ctx->id("ICESTORM_LC")) return port.port == id_CLK; if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 3940f070..317b4108 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -176,13 +176,15 @@ DesignSharedPtr create_torc_design(const Context *ctx) instPtr->setConfig(setting + "INIT", "", cell.second->params.at(ctx->id("FFINIT"))); if (cell.second->lcInfo.negClk) - instPtr->setConfig("CLKINV", "", "CLK_B"); + instPtr->setConfig("CLKINV", "", "CLK_B"); + else + instPtr->setConfig("CLKINV", "", "CLK"); if (get_net_or_empty(cell.second.get(), id_SR)) { - instPtr->setConfig(setting + "SR", "", cell.second->params.at(id_SR)); - instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); + instPtr->setConfig(setting + "SR", "", cell.second->params.at(id_SR)); + instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); instPtr->setConfig("SRUSEDMUX", "", "IN"); - } + } if (get_net_or_empty(cell.second.get(), ctx->id("CE"))) instPtr->setConfig("CEUSEDMUX", "", "IN"); From 9c0fd6816eb2d5377cd59258a1d30ac00bfe1ba5 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Dec 2018 14:48:53 -0800 Subject: [PATCH 146/174] Add X back into predictDelay() for global resources --- xc7/delay.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index 722e6932..921f65d3 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -105,6 +105,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_loc = torc_info->tile_to_xy[dst_tw.getTileIndex()]; + auto abs_delta_x = abs(dst_loc.first - src_loc.first); if (!torc_info->wire_is_global[src.index] || torc_info->wire_is_global[dst.index]) { auto abs_delta_x = abs(dst_loc.first - src_loc.first); auto abs_delta_y = abs(dst_loc.second - src_loc.second); @@ -129,7 +130,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const src_y -= src_y % 50; dst_y -= dst_y % 50; auto abs_delta_y = abs(src_y - dst_y); - return abs_delta_y * 64; // arbitrary factor + return abs_delta_x + abs_delta_y; } } From d37a57800b0a4c9d610fd7a8000a9de35441a458 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Fri, 7 Dec 2018 20:22:30 -0800 Subject: [PATCH 147/174] Tune predictDelay --- xc7/delay.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/xc7/delay.cc b/xc7/delay.cc index 921f65d3..1c94d3b6 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -127,8 +127,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const else { auto src_y = src_loc.second; auto dst_y = dst_loc.second; - src_y -= src_y % 50; - dst_y -= dst_y % 50; + dst_y -= (dst_y % 52) - 26; auto abs_delta_y = abs(src_y - dst_y); return abs_delta_x + abs_delta_y; } From 097062c5cb5c600e0a4a74937e7bf3a3d336a4a7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 8 Dec 2018 22:49:39 -0800 Subject: [PATCH 148/174] Remove pip_to_dst_wire lookup --- xc7/arch.cc | 93 +++++++++++++++++++++++++++++----------------------- xc7/arch.h | 23 ++++++------- xc7/delay.cc | 9 +++-- 3 files changed, 68 insertions(+), 57 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 96c574d6..ee8b3f78 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -138,8 +138,6 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const boost::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); const boost::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); const boost::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); - const boost::regex int_clk("CLK(_L)?[01]"); - const boost::regex gclk("GCLK_(L_)?B\\d+(_EAST|_WEST)?"); std::unordered_map> delay_lookup; Tilewire currentTilewire; WireId w; @@ -259,57 +257,64 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const bool clb = boost::starts_with( tileTypeName, "CLB"); // Disable all CLB route-throughs (i.e. LUT in->out, LUT A->AMUX, for now) - arcs.clear(); - const_cast(*ddb).expandSegmentSinks(currentTilewire, arcs, DDB::eExpandDirectionNone, - false /* inUseTied */, true /*inUseRegular */, - true /* inUseIrregular */, !clb /* inUseRoutethrough */); - auto &pips = wire_to_pips_downhill[w.index]; - pips.reserve(arcs.size()); const bool clk_tile = boost::starts_with(tileTypeName, "CLK"); - const bool int_tile = boost::starts_with(tileTypeName, "INT"); - const bool global_tile = boost::starts_with(tileTypeName, "CLK") || boost::starts_with(tileTypeName, "HCLK") || boost::starts_with(tileTypeName, "CFG"); - if (global_tile) - wire_is_global[w.index] = true; + bool global_tile = false; - for (const auto &a : arcs) { - // Disable BUFG I0 -> O routethrough - if (clk_tile) { - ewi.set(a.getSourceTilewire()); - if (boost::regex_match(ewi.mWireName, bufg_i)) { - ewi.set(a.getSinkTilewire()); - if (boost::regex_match(ewi.mWireName, bufg_o)) - continue; + arcs.clear(); + //const_cast(*ddb).expandSegmentSinks(currentTilewire, arcs, DDB::eExpandDirectionNone, + // false /* inUseTied */, true /*inUseRegular */, + // true /* inUseIrregular */, !clb /* inUseRoutethrough */); + { + // expand the segment + TilewireVector segment; + const_cast(*ddb).expandSegment(currentTilewire, segment, DDB::eExpandDirectionNone); + // expand all of the arcs + TilewireVector::const_iterator sep = segment.begin(); + TilewireVector::const_iterator see = segment.end(); + while(sep < see) { + // expand the tilewire sinks + const Tilewire& tilewire = *sep++; + + const auto &tileInfo = tiles.getTileInfo(tilewire.getTileIndex()); + const auto &tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); + global_tile = global_tile || boost::starts_with(tileTypeName, "CLK") || boost::starts_with(tileTypeName, "HCLK") || boost::starts_with(tileTypeName, "CFG"); + + TilewireVector sinks; + const_cast(*ddb).expandTilewireSinks(tilewire, sinks, false /*inUseTied*/, true /*inUseRegular*/, true /*inUseIrregular*/, + !clb /* inUseRoutethrough */); + // rewrite the sinks as arcs + TilewireVector::const_iterator sip = sinks.begin(); + TilewireVector::const_iterator sie = sinks.end(); + while(sip < sie) { + Arc a(tilewire, *sip++); + + // Disable BUFG I0 -> O routethrough + if (clk_tile) { + ewi.set(a.getSourceTilewire()); + if (boost::regex_match(ewi.mWireName, bufg_i)) { + ewi.set(a.getSinkTilewire()); + if (boost::regex_match(ewi.mWireName, bufg_o)) + continue; + } + } + + pips.emplace_back(p); + pip_to_arc.emplace_back(a); + // arc_to_pip.emplace(a, p.index); + ++p.index; } } - // Disable CLK inputs from being driven from the fabric (must be from global clock network) - else if (int_tile) { - ewi.set(a.getSinkTilewire()); - if (boost::regex_match(ewi.mWireName, int_clk)) { - ewi.set(a.getSourceTilewire()); - if (!boost::regex_match(ewi.mWireName, gclk)) - continue; - } - } - pips.emplace_back(p); - pip_to_arc.emplace_back(a); - // arc_to_pip.emplace(a, p.index); - const auto &tw = a.getSinkTilewire(); - pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); - ++p.index; } pips.shrink_to_fit(); + + if (global_tile) + wire_is_global[w.index] = true; } pip_to_arc.shrink_to_fit(); num_pips = pip_to_arc.size(); - pip_to_dst_wire.reserve(num_pips); - for (const auto &arc : pip_to_arc) { - const auto &tw = arc.getSinkTilewire(); - pip_to_dst_wire.emplace_back(tilewire_to_wire(tw)); - } - height = (int)tiles.getRowCount(); width = (int)tiles.getColCount(); } @@ -685,6 +690,12 @@ IdString Arch::getPipName(PipId pip) const //#endif } +//IdString Arch::getPipType(PipId pip) const +//{ +// NPNR_ASSERT(pip != PipId()); +// return IdString(); +//} + std::vector> Arch::getPipAttrs(PipId pip) const { std::vector> ret; diff --git a/xc7/arch.h b/xc7/arch.h index b3145b6d..f0b48d43 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -321,7 +321,6 @@ struct TorcInfo std::vector> wire_to_pips_downhill; std::vector pip_to_arc; int num_pips; - std::vector pip_to_dst_wire; int width; int height; std::vector wire_is_global; @@ -348,7 +347,6 @@ private: ar & wire_to_pips_downhill; ar & pip_to_arc; ar & num_pips; - ar & pip_to_dst_wire; ar & wire_is_global; ar & tile_to_xy; } @@ -814,15 +812,16 @@ struct Arch : BaseCtx Loc getPipLocation(PipId pip) const { - const auto &arc = torc_info->pip_to_arc[pip.index]; - const auto &tw = arc.getSourceTilewire(); - const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex()); + //const auto &arc = torc_info->pip_to_arc[pip.index]; + //const auto &tw = arc.getSourceTilewire(); + //const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex()); - Loc loc; - loc.x = tile_info.getCol(); - loc.y = tile_info.getRow(); - loc.z = 0; - return loc; + //Loc loc; + //loc.x = tile_info.getCol(); + //loc.y = tile_info.getRow(); + //loc.z = 0; + //return loc; + throw; } IdString getPipName(PipId pip) const; @@ -844,7 +843,9 @@ struct Arch : BaseCtx WireId getPipDstWire(PipId pip) const { NPNR_ASSERT(pip != PipId()); - return torc_info->pip_to_dst_wire[pip.index]; + const auto &arc = torc_info->pip_to_arc[pip.index]; + const auto &tw = arc.getSinkTilewire(); + return torc_info->tilewire_to_wire(tw); } DelayInfo getPipDelay(PipId pip) const diff --git a/xc7/delay.cc b/xc7/delay.cc index 1c94d3b6..8b8b0ae7 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -105,8 +105,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const const auto &dst_tw = torc_info->wire_to_tilewire[dst.index]; const auto &dst_loc = torc_info->tile_to_xy[dst_tw.getTileIndex()]; - auto abs_delta_x = abs(dst_loc.first - src_loc.first); - if (!torc_info->wire_is_global[src.index] || torc_info->wire_is_global[dst.index]) { + if (!torc_info->wire_is_global[src.index]) { auto abs_delta_x = abs(dst_loc.first - src_loc.first); auto abs_delta_y = abs(dst_loc.second - src_loc.second); auto div_LH = std::div(abs_delta_x, 12); @@ -127,9 +126,9 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const else { auto src_y = src_loc.second; auto dst_y = dst_loc.second; - dst_y -= (dst_y % 52) - 26; - auto abs_delta_y = abs(src_y - dst_y); - return abs_delta_x + abs_delta_y; + auto div_src_y = std::div(src_y, 52); + auto div_dst_y = std::div(dst_y, 52); + return abs(div_dst_y.quot - div_src_y.quot) * 52 + abs(div_dst_y.rem - div_src_y.rem); } } From e87b96fe4a05d6040ea4820456c00a9dbc6ee69f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Sat, 8 Dec 2018 22:49:55 -0800 Subject: [PATCH 149/174] Add xc7 specific hack for global network routing --- common/router1.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/common/router1.cc b/common/router1.cc index cbc0df90..a93d7f51 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -512,6 +512,20 @@ struct Router1 WireId next_wire = ctx->getPipDstWire(pip); next_delay += ctx->getWireDelay(next_wire).maxDelay(); +#ifdef ARCH_XC7 + if (ctx->isGlobalNet(net_info)) { + if (torc_info->wire_is_global[src_wire.index] && !torc_info->wire_is_global[next_wire.index]) { + const auto &arc = torc_info->pip_to_arc[pip.index]; + const auto &next_tw = arc.getSinkTilewire(); + const auto &next_loc = torc_info->tile_to_xy[next_tw.getTileIndex()]; + const auto &dst_tw = torc_info->wire_to_tilewire[dst_wire.index]; + const auto &dst_loc = torc_info->tile_to_xy[dst_tw.getTileIndex()]; + if (next_loc.second != dst_loc.second || next_loc.first != dst_loc.first) + continue; + } + } +#endif + WireId conflictWireWire = WireId(), conflictPipWire = WireId(); NetInfo *conflictWireNet = nullptr, *conflictPipNet = nullptr; From b2b02c9c3b4b68aa5e2e7b0be55001899db72f51 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 18 Dec 2018 16:42:18 -0800 Subject: [PATCH 150/174] Prefer INT/CLB tile as "anchor" tilewire --- xc7/arch.cc | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index ee8b3f78..b3c302a3 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -139,6 +139,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const boost::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); const boost::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); std::unordered_map> delay_lookup; + std::unordered_map segment_to_anchor; Tilewire currentTilewire; WireId w; w.index = 0; @@ -153,8 +154,28 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const auto ¤tSegment = segments.getTilewireSegment(currentTilewire); if (!currentSegment.isTrivial()) { - if (currentSegment.getAnchorTileIndex() != tileIndex) + auto r = segment_to_anchor.emplace(currentSegment, currentSegment.getAnchorTileIndex()); + if (r.second) { + TilewireVector segment; + const_cast(*ddb).expandSegment(currentTilewire, segment, DDB::eExpandDirectionNone); + // expand all of the arcs + TilewireVector::const_iterator sep = segment.begin(); + TilewireVector::const_iterator see = segment.end(); + while(sep < see) { + // expand the tilewire sinks + const Tilewire& tilewire = *sep++; + + const auto &tileInfo = tiles.getTileInfo(tilewire.getTileIndex()); + const auto &tileTypeName = tiles.getTileTypeName(tileInfo.getTypeIndex()); + if (boost::starts_with(tileTypeName, "INT") || boost::starts_with(tileTypeName, "CLB")) { + r.first->second = tilewire.getTileIndex(); + break; + } + } + } + if (r.first->second != tileIndex) continue; + segment_to_wire.emplace(currentSegment, w); } else trivial_to_wire.emplace(currentTilewire, w); @@ -236,6 +257,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str ++w.index; } } + segment_to_anchor.clear(); wire_to_tilewire.shrink_to_fit(); wire_to_delay.shrink_to_fit(); num_wires = wire_to_tilewire.size(); From a8a00ff3fbf29798d104ba53151a7b249694d62f Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 18 Dec 2018 18:20:23 -0800 Subject: [PATCH 151/174] Disable entering HROW from INT_[LR].CLK[01] --- xc7/arch.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/xc7/arch.cc b/xc7/arch.cc index b3c302a3..bb569d16 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -138,6 +138,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str const boost::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); const boost::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); const boost::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); + const boost::regex hrow("CLK_HROW_CLK[01]_[34]"); std::unordered_map> delay_lookup; std::unordered_map segment_to_anchor; Tilewire currentTilewire; @@ -322,6 +323,13 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str } } + // Disable entering HROW from INT_[LR].CLK[01] + if (boost::starts_with(tileTypeName, "CLK_HROW")) { + ewi.set(a.getSourceTilewire()); + if (boost::regex_match(ewi.mWireName, hrow)) + continue; + } + pips.emplace_back(p); pip_to_arc.emplace_back(a); // arc_to_pip.emplace(a, p.index); From f2b6e525d52b4bc0d3a4921958f27e380054bfb1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Tue, 18 Dec 2018 18:23:00 -0800 Subject: [PATCH 152/174] Add imux_wire to guide router --- common/router1.cc | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/common/router1.cc b/common/router1.cc index a93d7f51..0b46dbb1 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -445,6 +445,26 @@ struct Router1 auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); ripup_flag = false; +#ifdef ARCH_XC7 + // Work around the fact that BUFG inputs have a logical location far away from its IMUX by introducing an "imux_wire" to guide A* routing + auto imux_wire = dst_wire; + const auto &dst_tw = torc_info->wire_to_tilewire[dst_wire.index]; + + const auto &tileInfo = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); + const auto tileTypeName = torc_info->tiles.getTileTypeName(tileInfo.getTypeIndex()); + if (boost::starts_with(tileTypeName, "CLK")) { + TilewireVector sources; + const_cast(*torc_info->ddb).expandTilewireSources(dst_tw, sources, false /*inUseTied*/, true /*inUseRegular*/, false /*inUseIrregular*/, false /*inUseRoutethrough*/); + std::cout << ctx->getWireName(torc_info->tilewire_to_wire(dst_tw)).str(ctx); + if (sources.size() == 1) { + imux_wire = torc_info->tilewire_to_wire(sources.front()); + std::cout << " -> " << ctx->getWireName(imux_wire).str(ctx) << std::endl; + } + else + std::cout << " has " << sources.size() << " sources" << std::endl; + } +#endif + if (ctx->debug) { log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info), int(net_info->users.size())); @@ -513,6 +533,7 @@ struct Router1 next_delay += ctx->getWireDelay(next_wire).maxDelay(); #ifdef ARCH_XC7 + // For BUFG routing, do not exit the global network until the destination tile is reached if (ctx->isGlobalNet(net_info)) { if (torc_info->wire_is_global[src_wire.index] && !torc_info->wire_is_global[next_wire.index]) { const auto &arc = torc_info->pip_to_arc[pip.index]; @@ -632,7 +653,11 @@ struct Router1 next_qw.penalty = next_penalty; next_qw.bonus = next_bonus; if (cfg.useEstimate) { +#ifdef ARCH_XC7 + next_qw.togo = ctx->estimateDelay(next_wire, imux_wire); +#else next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); +#endif delay_t this_est = next_qw.delay + next_qw.togo; if (this_est / 2 - cfg.estimatePrecision > best_est) continue; From 6a09f2a8565b6085a8ca730a42951bbcf2f721cb Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 26 Dec 2018 17:10:52 -0800 Subject: [PATCH 153/174] Remove fasm writer --- xc7/main.cc | 6 ----- xc7/xdl.cc | 75 ----------------------------------------------------- xc7/xdl.h | 1 - 3 files changed, 82 deletions(-) diff --git a/xc7/main.cc b/xc7/main.cc index 1ff585b3..cac9a397 100644 --- a/xc7/main.cc +++ b/xc7/main.cc @@ -56,7 +56,6 @@ po::options_description Xc7CommandHandler::getArchOptions() specific.add_options()("package", po::value(), "set device package"); specific.add_options()("pcf", po::value(), "PCF constraints file to ingest"); specific.add_options()("xdl", po::value(), "XDL file to write"); - specific.add_options()("fasm", po::value(), "FASM file to write"); // specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); return specific; } @@ -84,11 +83,6 @@ void Xc7CommandHandler::customBitstream(Context *ctx) std::ofstream f(filename); write_xdl(ctx, f); } - if (vm.count("fasm")) { - std::string filename = vm["fasm"].as(); - std::ofstream f(filename); - write_fasm(ctx, f); - } } void Xc7CommandHandler::setupArchContext(Context *ctx) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index 317b4108..ef1be83e 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -282,79 +282,4 @@ void write_xdl(const Context *ctx, std::ostream &out) exporter(designPtr); } -void write_fasm(const Context *ctx, std::ostream &out) -{ - auto designPtr = create_torc_design(ctx); - - static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); - boost::smatch what; - - // export the instances - Circuit::InstanceSharedPtrConstIterator pi = designPtr->instancesBegin(); - Circuit::InstanceSharedPtrConstIterator ei = designPtr->instancesEnd(); - for (; pi < ei; ++pi) { - std::stringstream ss; - ss << (*pi)->getTile() << '.'; - const auto& type = (*pi)->getType(); - if (type == "SLICEL") { - const auto& site_name = (*pi)->getSite(); - if (!boost::regex_match(site_name, what, re_loc)) - throw; - - const auto x = boost::lexical_cast(what.str(1)); - ss << type << "_X" << static_cast(x & 1) << '.'; - - out << "# " << (*pi)->getName() << std::endl; - - auto pc = (*pi)->configBegin(); - auto ec = (*pi)->configEnd(); - for (; pc != ec; ++pc) - if (pc->first == "A6LUT" || pc->first == "B6LUT" || pc->first == "C6LUT" || pc->first == "D6LUT") { - auto name = pc->second.getName(); - boost::replace_all(name, "\\:", ":"); - auto it = ctx->cells.find(ctx->id(name)); - if (it == ctx->cells.end()) it = ctx->cells.find(ctx->id(name + "_LC")); - assert(it != ctx->cells.end()); - auto cell = it->second.get(); - const auto &init = cell->params[ctx->id("INIT")]; - if (cell->lcInfo.inputCount <= 5) { - auto num_bits = (1 << cell->lcInfo.inputCount); - auto init_as_uint = boost::lexical_cast(init); - out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT"; - out << "[" << num_bits-1 << ":0]" << "="; - out << num_bits << "'b"; - for (auto i = 0; i < num_bits; ++i) - out << ((init_as_uint >> i) & 1 ? '1' : '0'); - out << std::endl; - } - else { - out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[31:0]="; - out << "32'b" << boost::adaptors::reverse(init.substr(0,32)) << std::endl; - out << ss.str() << pc->first[0] << pc->first.substr(2,std::string::npos) << ".INIT[63:32]="; - out << "32'b" << boost::adaptors::reverse(init.substr(32,32)) << std::endl; - } - } - else - out << ss.str() << pc->first << '.' << pc->second.getValue() << std::endl; - - out << std::endl; - } - } - - // export the nets - Circuit::NetSharedPtrConstIterator pn = designPtr->netsBegin(); - Circuit::NetSharedPtrConstIterator en = designPtr->netsEnd(); - for (; pn < en; ++pn) { - - out << "# " << (*pn)->getName() << std::endl; - - auto pp = (*pn)->pipsBegin(); - auto ep = (*pn)->pipsEnd(); - for (; pp != ep; ++pp) - out << pp->getTileName() << "." << pp->getSourceWireName() << "." << pp->getSinkWireName() << std::endl; - - out << std::endl; - } -} - NEXTPNR_NAMESPACE_END diff --git a/xc7/xdl.h b/xc7/xdl.h index 19ee10cc..19bc5478 100644 --- a/xc7/xdl.h +++ b/xc7/xdl.h @@ -27,7 +27,6 @@ NEXTPNR_NAMESPACE_BEGIN void write_xdl(const Context *ctx, std::ostream &out); -void write_fasm(const Context *ctx, std::ostream &out); NEXTPNR_NAMESPACE_END From a630758ca7f65b412a4dd2e717902f669df15fd1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 26 Dec 2018 18:14:23 -0800 Subject: [PATCH 154/174] Cleanup --- xc7/arch.cc | 371 ++-------------------------------------- xc7/arch.h | 70 +------- xc7/arch_place.cc | 116 +++---------- xc7/blinky.sh | 2 +- xc7/cells.cc | 224 +------------------------ xc7/delay.cc | 73 -------- xc7/pack.cc | 418 +--------------------------------------------- 7 files changed, 56 insertions(+), 1218 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index bb569d16..6ec2d521 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -28,27 +28,8 @@ #include "router1.h" #include "util.h" -#include -#include -#include -#include -#include -#include -#include -struct nextpnr_binary_iarchive : public boost::archive::binary_iarchive { - nextpnr_binary_iarchive(boost::iostreams::filtering_istreambuf &ifs, NEXTPNR_NAMESPACE::BaseCtx* ctx, const std::string& inDeviceName, const std::string& inPackageName) : boost::archive::binary_iarchive(ifs), ctx(ctx), inDeviceName(inDeviceName), inPackageName(inPackageName) {} - NEXTPNR_NAMESPACE::BaseCtx *ctx; - std::string inDeviceName, inPackageName; -}; -struct nextpnr_binary_oarchive : public boost::archive::binary_oarchive { - nextpnr_binary_oarchive(boost::iostreams::filtering_ostreambuf &ofs, NEXTPNR_NAMESPACE::BaseCtx* ctx) : boost::archive::binary_oarchive(ofs), ctx(ctx) {} - NEXTPNR_NAMESPACE::BaseCtx *ctx; -}; - #include "torc/common/DirectoryTree.hpp" -//#define TORC_INFO_DB "torc_info.ar" - NEXTPNR_NAMESPACE_BEGIN std::unique_ptr torc_info; @@ -369,29 +350,7 @@ Arch::Arch(ArchArgs args) : args(args) { torc::common::DirectoryTree directoryTree("/opt/torc/src/torc"); if (args.type == ArchArgs::Z020) { -#ifdef TORC_INFO_DB - std::ifstream ifs(TORC_INFO_DB, std::ios::binary); - if (ifs) { - boost::iostreams::filtering_istreambuf fifs; - fifs.push(boost::iostreams::zlib_decompressor()); - fifs.push(ifs); - nextpnr_binary_iarchive ia(fifs, this, "xc7z020", args.package); - ia >> torc_info; - } else -#endif - { - torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", args.package)); -#ifdef TORC_INFO_DB - std::ofstream ofs(TORC_INFO_DB, std::ios::binary); - if (ofs) { - boost::iostreams::filtering_ostreambuf fofs; - fofs.push(boost::iostreams::zlib_compressor()); - fofs.push(ofs); - nextpnr_binary_oarchive oa(fofs, this); - oa << torc_info; - } -#endif - } + torc_info = std::unique_ptr(new TorcInfo(this, "xc7z020", args.package)); } else if (args.type == ArchArgs::VX980) { torc_info = std::unique_ptr(new TorcInfo(this, "xc7vx980t", args.package)); } else { @@ -406,21 +365,9 @@ Arch::Arch(ArchArgs args) : args(args) log_info("Number of pips: %d\n", torc_info->num_pips); } - // package_info = nullptr; - // for (int i = 0; i < chip_info->num_packages; i++) { - // if (chip_info->packages_data[i].name.get() == 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_carry.resize(chip_info->num_bels); bel_to_cell.resize(torc_info->num_bels); wire_to_net.resize(torc_info->num_wires); pip_to_net.resize(torc_info->num_pips); - // switches_locked.resize(chip_info->num_switches); } // ----------------------------------------------------------------------- @@ -429,6 +376,8 @@ std::string Arch::getChipName() const { if (args.type == ArchArgs::Z020) { return "z020"; + } else if (args.type == ArchArgs::VX980) { + return "vx980"; } else { log_error("Unsupported XC7 chip type.\n"); } @@ -440,6 +389,8 @@ IdString Arch::archArgsToId(ArchArgs args) const { if (args.type == ArchArgs::Z020) return id("z020"); + if (args.type == ArchArgs::VX980) + return id("vx980"); return IdString(); } @@ -564,49 +515,12 @@ WireId Arch::getBelPinWire(BelId bel, IdString pin) const pin_name.c_str()); return torc_info->tilewire_to_wire(tw); - - // NPNR_ASSERT(bel != BelId()); - // - // int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - // const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - // - // if (num_bel_wires < 7) { - // for (int i = 0; i < num_bel_wires; i++) { - // if (bel_wires[i].port == pin.index) { - // ret.index = bel_wires[i].wire_index; - // break; - // } - // } - // } else { - // int b = 0, e = num_bel_wires - 1; - // while (b <= e) { - // int i = (b + e) / 2; - // if (bel_wires[i].port == pin.index) { - // ret.index = bel_wires[i].wire_index; - // break; - // } - // if (bel_wires[i].port > pin.index) - // e = i - 1; - // else - // b = i + 1; - // } - // } - // - //return ret; } std::vector Arch::getBelPins(BelId bel) const { std::vector ret; - -/* NPNR_ASSERT(bel != BelId()); - - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - - for (int i = 0; i < num_bel_wires; i++) - ret.push_back(IdString(bel_wires[i].port)); -*/ + NPNR_ASSERT("TODO"); return ret; } @@ -615,54 +529,17 @@ std::vector Arch::getBelPins(BelId bel) const WireId Arch::getWireByName(IdString name) const { WireId ret; - if (wire_by_name.empty()) { for (int i = 0; i < chip_info->num_wires; i++) wire_by_name[id(chip_info->wire_data[i].name.get())] = i; } - - // auto it = wire_by_name.find(name); - // if (it != wire_by_name.end()) - // ret.index = it->second; - return ret; } IdString Arch::getWireType(WireId wire) const { NPNR_ASSERT(wire != WireId()); - // switch (chip_info->wire_data[wire.index].type) { - // case WireInfoPOD::WIRE_TYPE_NONE: - // return IdString(); - // case WireInfoPOD::WIRE_TYPE_GLB2LOCAL: - // return id("GLB2LOCAL"); - // case WireInfoPOD::WIRE_TYPE_GLB_NETWK: - // return id("GLB_NETWK"); - // case WireInfoPOD::WIRE_TYPE_LOCAL: - // return id("LOCAL"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_IN: - // return id("LUTFF_IN"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: - // return id("LUTFF_IN_LUT"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_LOUT: - // return id("LUTFF_LOUT"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: - // return id("LUTFF_OUT"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_COUT: - // return id("LUTFF_COUT"); - // case WireInfoPOD::WIRE_TYPE_LUTFF_GLOBAL: - // return id("LUTFF_GLOBAL"); - // case WireInfoPOD::WIRE_TYPE_CARRY_IN_MUX: - // return id("CARRY_IN_MUX"); - // case WireInfoPOD::WIRE_TYPE_SP4_V: - // return id("SP4_V"); - // case WireInfoPOD::WIRE_TYPE_SP4_H: - // return id("SP4_H"); - // case WireInfoPOD::WIRE_TYPE_SP12_V: - // return id("SP12_V"); - // case WireInfoPOD::WIRE_TYPE_SP12_H: - // return id("SP12_H"); - // } + NPNR_ASSERT("TODO"); return IdString(); } @@ -670,6 +547,7 @@ IdString Arch::getWireType(WireId wire) const std::vector> Arch::getWireAttrs(WireId wire) const { std::vector> ret; + NPNR_ASSERT("TODO"); return ret; } @@ -678,19 +556,7 @@ std::vector> Arch::getWireAttrs(WireId wire) co PipId Arch::getPipByName(IdString name) const { PipId ret; - -/* if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[getPipName(pip)] = i; - } - } - - auto it = pip_by_name.find(name); - if (it != pip_by_name.end()) - ret.index = it->second; -*/ + NPNR_ASSERT("TODO"); return ret; } @@ -703,33 +569,12 @@ IdString Arch::getPipName(PipId pip) const std::stringstream pip_name; pip_name << ewi_src.mTileName << "." << ewi_src.mWireName << ".->." << ewi_dst.mWireName; return id(pip_name.str()); - - //#if 1 - // int x = chip_info->pip_data[pip.index].x; - // int y = chip_info->pip_data[pip.index].y; - // - // std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); - // std::replace(src_name.begin(), src_name.end(), '/', '.'); - // - // std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); - // std::replace(dst_name.begin(), dst_name.end(), '/', '.'); - // - // return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); - //#else - // return id(chip_info->pip_data[pip.index].name.get()); - //#endif } -//IdString Arch::getPipType(PipId pip) const -//{ -// NPNR_ASSERT(pip != PipId()); -// return IdString(); -//} - std::vector> Arch::getPipAttrs(PipId pip) const { std::vector> ret; - + NPNR_ASSERT("TODO"); return ret; } @@ -739,11 +584,7 @@ BelId Arch::getPackagePinBel(const std::string &pin) const { return getBelByName std::string Arch::getBelPackagePin(BelId bel) const { - // for (int i = 0; i < package_info->num_pins; i++) { - // if (package_info->pins[i].bel_index == bel.index) { - // return std::string(package_info->pins[i].name.get()); - // } - // } + NPNR_ASSERT("TODO"); return ""; } @@ -762,39 +603,7 @@ IdString Arch::getGroupName(GroupId group) const std::string suffix; switch (group.type) { - case GroupId::TYPE_FRAME: - suffix = "tile"; - break; - case GroupId::TYPE_MAIN_SW: - suffix = "main_sw"; - break; - case GroupId::TYPE_LOCAL_SW: - suffix = "local_sw"; - break; - case GroupId::TYPE_LC0_SW: - suffix = "lc0_sw"; - break; - case GroupId::TYPE_LC1_SW: - suffix = "lc1_sw"; - break; - case GroupId::TYPE_LC2_SW: - suffix = "lc2_sw"; - break; - case GroupId::TYPE_LC3_SW: - suffix = "lc3_sw"; - break; - case GroupId::TYPE_LC4_SW: - suffix = "lc4_sw"; - break; - case GroupId::TYPE_LC5_SW: - suffix = "lc5_sw"; - break; - case GroupId::TYPE_LC6_SW: - suffix = "lc6_sw"; - break; - case GroupId::TYPE_LC7_SW: - suffix = "lc7_sw"; - break; + NPNR_ASSERT("TODO"); default: return IdString(); } @@ -805,52 +614,7 @@ IdString Arch::getGroupName(GroupId group) const std::vector Arch::getGroups() const { std::vector ret; -/* - for (int y = 0; y < chip_info->height; y++) { - for (int x = 0; x < chip_info->width; x++) { - TileType type = chip_info->tile_grid[y * chip_info->width + x]; - if (type == TILE_NONE) - continue; - - GroupId group; - group.type = GroupId::TYPE_FRAME; - group.x = x; - group.y = y; - // ret.push_back(group); - - group.type = GroupId::TYPE_MAIN_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LOCAL_SW; - ret.push_back(group); - - if (type == TILE_LOGIC) { - group.type = GroupId::TYPE_LC0_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC1_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC2_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC3_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC4_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC5_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC6_SW; - ret.push_back(group); - - group.type = GroupId::TYPE_LC7_SW; - ret.push_back(group); - } - } - }*/ + NPNR_ASSERT("TODO"); return ret; } @@ -869,12 +633,14 @@ std::vector Arch::getGroupWires(GroupId group) const std::vector Arch::getGroupPips(GroupId group) const { std::vector ret; + NPNR_ASSERT("TODO"); return ret; } std::vector Arch::getGroupGroups(GroupId group) const { std::vector ret; + NPNR_ASSERT("TODO"); return ret; } @@ -929,6 +695,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const std::vector Arch::getDecalGraphics(DecalId decal) const { std::vector ret; + NPNR_ASSERT("TODO"); return ret; } @@ -1078,109 +845,3 @@ void Arch::assignCellInfo(CellInfo *cell) } NEXTPNR_NAMESPACE_END - -// outside of any namespace -BOOST_SERIALIZATION_SPLIT_FREE(Segments::SegmentReference) -BOOST_SERIALIZATION_SPLIT_FREE(CompactSegmentIndex) -BOOST_SERIALIZATION_SPLIT_FREE(TileIndex) -BOOST_SERIALIZATION_SPLIT_FREE(Arc) -BOOST_SERIALIZATION_SPLIT_FREE(Tilewire) -BOOST_SERIALIZATION_SPLIT_FREE(WireIndex) -BOOST_SERIALIZATION_SPLIT_FREE(SiteIndex) -BOOST_SERIALIZATION_SPLIT_FREE(NEXTPNR_NAMESPACE::IdString) - -namespace boost { namespace serialization { - -template -inline void load_construct_data( - Archive & ar, NEXTPNR_NAMESPACE::TorcInfo * t, const unsigned int file_version -){ - const auto& inDeviceName = static_cast(ar).inDeviceName; - const auto& inPackageName = static_cast(ar).inPackageName; - ::new(t)NEXTPNR_NAMESPACE::TorcInfo(inDeviceName, inPackageName); -} - -template -void save(Archive& ar, const Segments::SegmentReference& o, unsigned int) { - ar & o.getCompactSegmentIndex(); - ar & o.getAnchorTileIndex(); -} -template -void load(Archive& ar, Segments::SegmentReference& o, unsigned int) { - CompactSegmentIndex i; - TileIndex j; - ar & i; - ar & j; - o = Segments::SegmentReference(i, j); -} -#define SERIALIZE_POD(__T__) \ -template \ -void save(Archive& ar, const __T__& o, unsigned int) { \ - ar & static_cast<__T__::pod>(o); \ -} \ -template \ -void load(Archive& ar, __T__& o, unsigned int) { \ - __T__::pod i; \ - ar & i; \ - o = __T__(i); \ -} -SERIALIZE_POD(CompactSegmentIndex) -SERIALIZE_POD(TileIndex) -SERIALIZE_POD(WireIndex) -SERIALIZE_POD(SiteIndex) -template -void save(Archive& ar, const Arc& o, unsigned int) { - ar & o.getSourceTilewire(); - ar & o.getSinkTilewire(); -} -template -void load(Archive& ar, Arc& o, unsigned int) { - Tilewire s, t; - ar & s; - ar & t; - o = Arc(s, t); -} -template -void save(Archive& ar, const Tilewire& o, unsigned int) { - ar & o.getTileIndex(); - ar & o.getWireIndex(); -} -template -void load(Archive& ar, Tilewire& o, unsigned int) { - TileIndex i; - WireIndex j; - ar & i; - ar & j; - o.setTileIndex(TileIndex(i)); - o.setWireIndex(WireIndex(j)); -} -template -void serialize(Archive& ar, NEXTPNR_NAMESPACE::Loc& o, unsigned int) { - ar & o.x; - ar & o.y; - ar & o.z; -} -template -void serialize(Archive& ar, NEXTPNR_NAMESPACE::DelayInfo& o, unsigned int) { - ar & o.delay; -} -template -void save(Archive& ar, const NEXTPNR_NAMESPACE::IdString& o, unsigned int) { - const std::string i = o.str(static_cast(ar).ctx); - ar & i; -} -template -void load(Archive& ar, NEXTPNR_NAMESPACE::IdString& o, unsigned int) { - std::string i; - ar & i; - o = static_cast(ar).ctx->id(i); -} -#define SERIALIZE_INDEX(__T__) \ -template \ -void serialize(Archive& ar, __T__& o, unsigned int) { \ - ar & o.index; \ -} -SERIALIZE_INDEX(NEXTPNR_NAMESPACE::BelId) -SERIALIZE_INDEX(NEXTPNR_NAMESPACE::WireId) -SERIALIZE_INDEX(NEXTPNR_NAMESPACE::PipId) -}} // namespace boost::serialization diff --git a/xc7/arch.h b/xc7/arch.h index f0b48d43..75f8530a 100644 --- a/xc7/arch.h +++ b/xc7/arch.h @@ -21,8 +21,6 @@ #error Include "arch.h" via "nextpnr.h" only. #endif -#include - #include "torc/Architecture.hpp" #include "torc/Common.hpp" using namespace torc::architecture; @@ -327,29 +325,6 @@ struct TorcInfo std::vector> tile_to_xy; TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); -private: - friend class boost::serialization::access; - //TorcInfo(const std::string &inDeviceName, const std::string &inPackageName); - //template friend inline void load_construct_data(Archive &ar, T *t, const unsigned int file_version); - template - void serialize(Archive & ar, const unsigned int /*version*/) - { - ar & bel_to_site_index; - ar & num_bels; - ar & site_index_to_bel; - ar & site_index_to_type; - ar & bel_to_loc; - ar & segment_to_wire; - ar & trivial_to_wire; - ar & wire_to_tilewire; - ar & num_wires; - ar & wire_to_delay; - ar & wire_to_pips_downhill; - ar & pip_to_arc; - ar & num_pips; - ar & wire_is_global; - ar & tile_to_xy; - } }; extern std::unique_ptr torc_info; @@ -675,7 +650,6 @@ struct Arch : BaseCtx auto pip = it->second.pip; if (pip != PipId()) { pip_to_net[pip.index] = nullptr; - // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; } net_wires.erase(it); @@ -708,10 +682,7 @@ struct Arch : BaseCtx BelPinRange getWireBelPins(WireId wire) const { BelPinRange range; - // NPNR_ASSERT(wire != WireId()); - // range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get(); - // range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins; - throw; + NPNR_ASSERT("TODO"); return range; } @@ -731,10 +702,8 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] == nullptr); - // NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == nullptr); pip_to_net[pip.index] = net; - // switches_locked[chip_info->pip_data[pip.index].switch_index] = net; WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] == nullptr); @@ -749,7 +718,6 @@ struct Arch : BaseCtx { NPNR_ASSERT(pip != PipId()); NPNR_ASSERT(pip_to_net[pip.index] != nullptr); - // NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != nullptr); WireId dst = getPipDstWire(pip); NPNR_ASSERT(wire_to_net[dst.index] != nullptr); @@ -757,7 +725,6 @@ struct Arch : BaseCtx pip_to_net[pip.index]->wires.erase(dst); pip_to_net[pip.index] = nullptr; - // switches_locked[chip_info->pip_data[pip.index].switch_index] = nullptr; refreshUiPip(pip); refreshUiWire(dst); } @@ -765,25 +732,6 @@ struct Arch : BaseCtx bool checkPipAvail(PipId pip) const { NPNR_ASSERT(pip != PipId()); - // auto &pi = chip_info->pip_data[pip.index]; - // auto &si = chip_info->bits_info->switches[pi.switch_index]; - - // if (switches_locked[pi.switch_index] != nullptr) - // return false; - - // if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) { - // NPNR_ASSERT(si.bel >= 0); - // if (bel_to_cell[si.bel] != nullptr) - // return false; - //} - - // if (pi.flags & PipInfoPOD::FLAG_NOCARRY) { - // NPNR_ASSERT(si.bel >= 0); - // if (bel_carry[si.bel]) - // return false; - //} - - // return true; return pip_to_net[pip.index] == nullptr; } @@ -798,7 +746,6 @@ struct Arch : BaseCtx NetInfo *getConflictingPipNet(PipId pip) const { NPNR_ASSERT(pip != PipId()); - // return switches_locked[chip_info->pip_data[pip.index].switch_index]; return pip_to_net[pip.index]; } @@ -812,16 +759,9 @@ struct Arch : BaseCtx Loc getPipLocation(PipId pip) const { - //const auto &arc = torc_info->pip_to_arc[pip.index]; - //const auto &tw = arc.getSourceTilewire(); - //const auto &tile_info = torc_info->tiles.getTileInfo(tw.getTileIndex()); - - //Loc loc; - //loc.x = tile_info.getCol(); - //loc.y = tile_info.getRow(); - //loc.z = 0; - //return loc; - throw; + Loc loc; + NPNR_ASSERT("TODO"); + return loc; } IdString getPipName(PipId pip) const; @@ -980,6 +920,4 @@ struct Arch : BaseCtx float placer_constraintWeight = 10; }; -// void ice40DelayFuzzerMain(Context *ctx); - NEXTPNR_NAMESPACE_END diff --git a/xc7/arch_place.cc b/xc7/arch_place.cc index fd09006e..7d1e32e4 100644 --- a/xc7/arch_place.cc +++ b/xc7/arch_place.cc @@ -29,43 +29,14 @@ NEXTPNR_NAMESPACE_BEGIN bool Arch::logicCellsCompatible(const CellInfo **it, const size_t size) const { - // bool dffs_exist = false, dffs_neg = false; - // const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; - // - // for (auto cell : boost::make_iterator_range(it, it+size)) { - // NPNR_ASSERT(cell->belType == id_ICESTORM_LC); - // if (cell->lcInfo.dffEnable) { - // if (!dffs_exist) { - // dffs_exist = true; - // cen = cell->lcInfo.cen; - // clk = cell->lcInfo.clk; - // sr = cell->lcInfo.sr; - // - // if (cell->lcInfo.negClk) { - // dffs_neg = true; - // } - // } else { - // if (cen != cell->lcInfo.cen) - // return false; - // if (clk != cell->lcInfo.clk) - // return false; - // if (sr != cell->lcInfo.sr) - // return false; - // if (dffs_neg != cell->lcInfo.negClk) - // return false; - // } - // } - // locals_count += cell->lcInfo.inputCount; - // } - // - // return locals_count <= 32; + // TODO: Check clock, clock-enable, and set-reset compatiility return true; } bool Arch::isBelLocationValid(BelId bel) const { - if (getBelType(bel) == id_ICESTORM_LC) { - std::array bel_cells; + if (getBelType(bel) == id("XC7_LC")) { + std::array bel_cells; size_t num_cells = 0; Loc bel_loc = getBelLocation(bel); for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { @@ -85,70 +56,23 @@ bool Arch::isBelLocationValid(BelId bel) const bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - // if (cell->type == id_ICESTORM_LC) { - // NPNR_ASSERT(getBelType(bel) == id_ICESTORM_LC); - // - // std::array bel_cells; - // size_t num_cells = 0; - // - // Loc bel_loc = getBelLocation(bel); - // for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { - // CellInfo *ci_other = getBoundBelCell(bel_other); - // if (ci_other != nullptr && bel_other != bel) - // bel_cells[num_cells++] = ci_other; - // } - // - // bel_cells[num_cells++] = cell; - // return logicCellsCompatible(bel_cells.data(), num_cells); - // } else if (cell->type == id_SB_IO) { - // // Do not allow placement of input SB_IOs on blocks where there a PLL is outputting to. - // - // // Find shared PLL by looking for driving bel siblings from D_IN_0 - // // that are a PLL clock output. - // auto wire = getBelPinWire(bel, id_D_IN_0); - // IdString pll_bel_pin; - // BelId pll_bel; - // for (auto pin : getWireBelPins(wire)) { - // if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { - // pll_bel = pin.bel; - // pll_bel_pin = pin.pin; - // break; - // } - // } - // // Is there a PLL that shares this IO buffer? - // if (pll_bel.index != -1) { - // auto pll_cell = getBoundBelCell(pll_bel); - // // Is a PLL placed in this PLL bel? - // if (pll_cell != nullptr) { - // // Is the shared port driving a net? - // auto pi = pll_cell->ports[pll_bel_pin]; - // if (pi.net != nullptr) { - // // Are we perhaps a PAD INPUT Bel that can be placed here? - // if (pll_cell->attrs[id("BEL_PAD_INPUT")] == getBelName(bel).str(this)) { - // return true; - // } - // return false; - // } - // } - // } - // return getBelPackagePin(bel) != ""; - // } else if (cell->type == id_SB_GB) { - // NPNR_ASSERT(cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net != nullptr); - // const NetInfo *net = cell->ports.at(id_GLOBAL_BUFFER_OUTPUT).net; - // IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT)); - // int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); - // if (net->is_reset && net->is_enable) - // return false; - // else if (net->is_reset) - // return (glb_id % 2) == 0; - // else if (net->is_enable) - // return (glb_id % 2) == 1; - // else - // return true; - // } else { - // // TODO: IO cell clock checks - return true; - // } + if (cell->type == id("XC7_LC")) { + std::array bel_cells; + size_t num_cells = 0; + + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { + CellInfo *ci_other = getBoundBelCell(bel_other); + if (ci_other != nullptr && bel_other != bel) + bel_cells[num_cells++] = ci_other; + } + + bel_cells[num_cells++] = cell; + return logicCellsCompatible(bel_cells.data(), num_cells); + } + else { + return true; + } } NEXTPNR_NAMESPACE_END diff --git a/xc7/blinky.sh b/xc7/blinky.sh index dff168e0..1ba77434 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,7 +1,7 @@ #!/bin/bash set -ex yosys blinky.ys -- ../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 xdl -xdl2ncd blinky.xdl bitgen -w blinky.ncd -g UnconstrainedPins:Allow trce blinky.ncd -v 10 diff --git a/xc7/cells.cc b/xc7/cells.cc index e95de384..07cb30b0 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -68,190 +68,15 @@ std::unique_ptr create_xc7_cell(Context *ctx, IdString type, std::stri add_port(ctx, new_cell.get(), "OMUX", PORT_OUT); add_port(ctx, new_cell.get(), "COUT", PORT_OUT); } else if (type == ctx->id("IOBUF")) { - if (ctx->args.type == ArchArgs::Z020) { - new_cell->type = id_IOB33; - } else { - new_cell->type = id_IOB18; - } - //new_cell->params[ctx->id("PIN_TYPE")] = "0"; - //new_cell->params[ctx->id("PULLUP")] = "0"; - //new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; - //new_cell->params[ctx->id("IOSTANDARD")] = "SB_LVCMOS"; - - // add_port(ctx, new_cell.get(), "PACKAGE_PIN", PORT_INOUT); - // - // add_port(ctx, new_cell.get(), "LATCH_INPUT_VALUE", PORT_IN); - // add_port(ctx, new_cell.get(), "CLOCK_ENABLE", PORT_IN); - // add_port(ctx, new_cell.get(), "INPUT_CLK", PORT_IN); - // add_port(ctx, new_cell.get(), "OUTPUT_CLK", PORT_IN); - // - // add_port(ctx, new_cell.get(), "OUTPUT_ENABLE", PORT_IN); - // add_port(ctx, new_cell.get(), "D_OUT_0", PORT_IN); - // add_port(ctx, new_cell.get(), "D_OUT_1", PORT_IN); - // - // add_port(ctx, new_cell.get(), "D_IN_0", PORT_OUT); - // add_port(ctx, new_cell.get(), "D_IN_1", PORT_OUT); + if (ctx->args.type == ArchArgs::Z020) + new_cell->type = id_IOB33; + else + new_cell->type = id_IOB18; add_port(ctx, new_cell.get(), "I", PORT_OUT); add_port(ctx, new_cell.get(), "O", PORT_IN); - // } else if (type == ctx->id("ICESTORM_RAM")) { - // new_cell->params[ctx->id("NEG_CLK_W")] = "0"; - // new_cell->params[ctx->id("NEG_CLK_R")] = "0"; - // new_cell->params[ctx->id("WRITE_MODE")] = "0"; - // new_cell->params[ctx->id("READ_MODE")] = "0"; - // - // add_port(ctx, new_cell.get(), "RCLK", PORT_IN); - // add_port(ctx, new_cell.get(), "RCLKE", PORT_IN); - // add_port(ctx, new_cell.get(), "RE", PORT_IN); - // - // add_port(ctx, new_cell.get(), "WCLK", PORT_IN); - // add_port(ctx, new_cell.get(), "WCLKE", PORT_IN); - // add_port(ctx, new_cell.get(), "WE", PORT_IN); - // - // for (int i = 0; i < 16; i++) { - // add_port(ctx, new_cell.get(), "WDATA_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "MASK_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "RDATA_" + std::to_string(i), PORT_OUT); - // } - // - // for (int i = 0; i < 11; i++) { - // add_port(ctx, new_cell.get(), "RADDR_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "WADDR_" + std::to_string(i), PORT_IN); - // } - // } else if (type == ctx->id("ICESTORM_LFOSC")) { - // add_port(ctx, new_cell.get(), "CLKLFEN", PORT_IN); - // add_port(ctx, new_cell.get(), "CLKLFPU", PORT_IN); - // add_port(ctx, new_cell.get(), "CLKLF", PORT_OUT); - // add_port(ctx, new_cell.get(), "CLKLF_FABRIC", PORT_OUT); - // } else if (type == ctx->id("ICESTORM_HFOSC")) { - // new_cell->params[ctx->id("CLKHF_DIV")] = "0b00"; - // new_cell->params[ctx->id("TRIM_EN")] = "0b0"; - // - // add_port(ctx, new_cell.get(), "CLKHFEN", PORT_IN); - // add_port(ctx, new_cell.get(), "CLKHFPU", PORT_IN); - // add_port(ctx, new_cell.get(), "CLKHF", PORT_OUT); - // add_port(ctx, new_cell.get(), "CLKHF_FABRIC", PORT_OUT); - // for (int i = 0; i < 10; i++) - // add_port(ctx, new_cell.get(), "TRIM" + std::to_string(i), PORT_IN); } else if (type == id_BUFGCTRL) { add_port(ctx, new_cell.get(), "I0", PORT_IN); add_port(ctx, new_cell.get(), "O", PORT_OUT); - // } else if (type == ctx->id("ICESTORM_SPRAM")) { - // add_port(ctx, new_cell.get(), "WREN", PORT_IN); - // add_port(ctx, new_cell.get(), "CHIPSELECT", PORT_IN); - // add_port(ctx, new_cell.get(), "CLOCK", PORT_IN); - // add_port(ctx, new_cell.get(), "STANDBY", PORT_IN); - // add_port(ctx, new_cell.get(), "SLEEP", PORT_IN); - // add_port(ctx, new_cell.get(), "POWEROFF", PORT_IN); - // - // for (int i = 0; i < 16; i++) { - // add_port(ctx, new_cell.get(), "DATAIN_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "DATAOUT_" + std::to_string(i), PORT_OUT); - // } - // for (int i = 0; i < 14; i++) { - // add_port(ctx, new_cell.get(), "ADDRESS_" + std::to_string(i), PORT_IN); - // } - // for (int i = 0; i < 4; i++) { - // add_port(ctx, new_cell.get(), "MASKWREN_" + std::to_string(i), PORT_IN); - // } - // } else if (type == ctx->id("ICESTORM_DSP")) { - // new_cell->params[ctx->id("NEG_TRIGGER")] = "0"; - // - // new_cell->params[ctx->id("C_REG")] = "0"; - // new_cell->params[ctx->id("A_REG")] = "0"; - // new_cell->params[ctx->id("B_REG")] = "0"; - // new_cell->params[ctx->id("D_REG")] = "0"; - // new_cell->params[ctx->id("TOP_8x8_MULT_REG")] = "0"; - // new_cell->params[ctx->id("BOT_8x8_MULT_REG")] = "0"; - // new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG1")] = "0"; - // new_cell->params[ctx->id("PIPELINE_16x16_MULT_REG2")] = "0"; - // - // new_cell->params[ctx->id("TOPOUTPUT_SELECT")] = "0"; - // new_cell->params[ctx->id("TOPADDSUB_LOWERINPUT")] = "0"; - // new_cell->params[ctx->id("TOPADDSUB_UPPERINPUT")] = "0"; - // new_cell->params[ctx->id("TOPADDSUB_CARRYSELECT")] = "0"; - // - // new_cell->params[ctx->id("BOTOUTPUT_SELECT")] = "0"; - // new_cell->params[ctx->id("BOTADDSUB_LOWERINPUT")] = "0"; - // new_cell->params[ctx->id("BOTADDSUB_UPPERINPUT")] = "0"; - // new_cell->params[ctx->id("BOTADDSUB_CARRYSELECT")] = "0"; - // - // new_cell->params[ctx->id("MODE_8x8")] = "0"; - // new_cell->params[ctx->id("A_SIGNED")] = "0"; - // new_cell->params[ctx->id("B_SIGNED")] = "0"; - // - // add_port(ctx, new_cell.get(), "CLK", PORT_IN); - // add_port(ctx, new_cell.get(), "CE", PORT_IN); - // for (int i = 0; i < 16; i++) { - // add_port(ctx, new_cell.get(), "C_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "A_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "B_" + std::to_string(i), PORT_IN); - // add_port(ctx, new_cell.get(), "D_" + std::to_string(i), PORT_IN); - // } - // add_port(ctx, new_cell.get(), "AHOLD", PORT_IN); - // add_port(ctx, new_cell.get(), "BHOLD", PORT_IN); - // add_port(ctx, new_cell.get(), "CHOLD", PORT_IN); - // add_port(ctx, new_cell.get(), "DHOLD", PORT_IN); - // - // add_port(ctx, new_cell.get(), "IRSTTOP", PORT_IN); - // add_port(ctx, new_cell.get(), "IRSTBOT", PORT_IN); - // add_port(ctx, new_cell.get(), "ORSTTOP", PORT_IN); - // add_port(ctx, new_cell.get(), "ORSTBOT", PORT_IN); - // - // add_port(ctx, new_cell.get(), "OLOADTOP", PORT_IN); - // add_port(ctx, new_cell.get(), "OLOADBOT", PORT_IN); - // - // add_port(ctx, new_cell.get(), "ADDSUBTOP", PORT_IN); - // add_port(ctx, new_cell.get(), "ADDSUBBOT", PORT_IN); - // - // add_port(ctx, new_cell.get(), "OHOLDTOP", PORT_IN); - // add_port(ctx, new_cell.get(), "OHOLDBOT", PORT_IN); - // - // add_port(ctx, new_cell.get(), "CI", PORT_IN); - // add_port(ctx, new_cell.get(), "ACCUMCI", PORT_IN); - // add_port(ctx, new_cell.get(), "SIGNEXTIN", PORT_IN); - // - // for (int i = 0; i < 32; i++) { - // add_port(ctx, new_cell.get(), "O_" + std::to_string(i), PORT_OUT); - // } - // - // add_port(ctx, new_cell.get(), "CO", PORT_OUT); - // add_port(ctx, new_cell.get(), "ACCUMCO", PORT_OUT); - // add_port(ctx, new_cell.get(), "SIGNEXTOUT", PORT_OUT); - // - // } else if (type == ctx->id("ICESTORM_PLL")) { - // new_cell->params[ctx->id("DELAY_ADJMODE_FB")] = "0"; - // new_cell->params[ctx->id("DELAY_ADJMODE_REL")] = "0"; - // - // new_cell->params[ctx->id("DIVF")] = "0"; - // new_cell->params[ctx->id("DIVQ")] = "0"; - // new_cell->params[ctx->id("DIVR")] = "0"; - // - // new_cell->params[ctx->id("FDA_FEEDBACK")] = "0"; - // new_cell->params[ctx->id("FDA_RELATIVE")] = "0"; - // new_cell->params[ctx->id("FEEDBACK_PATH")] = "0"; - // new_cell->params[ctx->id("FILTER_RANGE")] = "0"; - // - // new_cell->params[ctx->id("PLLOUT_SELECT_A")] = "0"; - // new_cell->params[ctx->id("PLLOUT_SELECT_B")] = "0"; - // - // new_cell->params[ctx->id("PLLTYPE")] = "0"; - // new_cell->params[ctx->id("SHIFTREG_DIVMODE")] = "0"; - // new_cell->params[ctx->id("TEST_MODE")] = "0"; - // - // add_port(ctx, new_cell.get(), "BYPASS", PORT_IN); - // add_port(ctx, new_cell.get(), "DYNAMICDELAY", PORT_IN); - // add_port(ctx, new_cell.get(), "EXTFEEDBACK", PORT_IN); - // add_port(ctx, new_cell.get(), "LATCHINPUTVALUE", PORT_IN); - // add_port(ctx, new_cell.get(), "REFERENCECLK", PORT_IN); - // add_port(ctx, new_cell.get(), "RESETB", PORT_IN); - // - // add_port(ctx, new_cell.get(), "SCLK", PORT_IN); - // add_port(ctx, new_cell.get(), "SDI", PORT_IN); - // add_port(ctx, new_cell.get(), "SDI", PORT_OUT); - // - // add_port(ctx, new_cell.get(), "LOCK", PORT_OUT); - // add_port(ctx, new_cell.get(), "PLLOUT_A", PORT_OUT); - // add_port(ctx, new_cell.get(), "PLLOUT_B", PORT_OUT); } else { log_error("unable to create XC7 cell of type %s\n", type.c_str(ctx)); } @@ -390,34 +215,11 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) } } -uint8_t sb_pll40_type(const BaseCtx *ctx, const CellInfo *cell) -{ - if (cell->type == ctx->id("SB_PLL40_PAD")) - return 2; - if (cell->type == ctx->id("SB_PLL40_2_PAD")) - return 4; - if (cell->type == ctx->id("SB_PLL40_2F_PAD")) - return 5; - if (cell->type == ctx->id("SB_PLL40_CORE")) - return 3; - if (cell->type == ctx->id("SB_PLL40_2F_CORE")) - return 7; - NPNR_ASSERT(0); -} - bool is_clock_port(const BaseCtx *ctx, const PortRef &port) { if (port.cell == nullptr) return false; - if (is_ff(ctx, port.cell)) - return port.port == ctx->id("C"); - if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == id_CLK; - if (is_ram(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_RAM")) - return port.port == ctx->id("RCLK") || port.port == ctx->id("WCLK") || port.port == ctx->id("RCLKN") || - port.port == ctx->id("WCLKN"); - if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) - return port.port == id_CLK; + NPNR_ASSERT("TODO"); return false; } @@ -425,13 +227,7 @@ bool is_reset_port(const BaseCtx *ctx, const PortRef &port) { if (port.cell == nullptr) return false; - if (is_ff(ctx, port.cell)) - return port.port == id_R || port.port == id_S; - if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == id_SR; - if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) - return port.port == ctx->id("IRSTTOP") || port.port == ctx->id("IRSTBOT") || port.port == ctx->id("ORSTTOP") || - port.port == ctx->id("ORSTBOT"); + NPNR_ASSERT("TODO"); return false; } @@ -439,13 +235,7 @@ bool is_enable_port(const BaseCtx *ctx, const PortRef &port) { if (port.cell == nullptr) return false; - if (is_ff(ctx, port.cell)) - return port.port == ctx->id("E"); - if (port.cell->type == ctx->id("ICESTORM_LC")) - return port.port == id_CEN; - // FIXME - // if (is_sb_mac16(ctx, port.cell) || port.cell->type == ctx->id("ICESTORM_DSP")) - // return port.port == ctx->id("CE"); + NPNR_ASSERT("TODO"); return false; } diff --git a/xc7/delay.cc b/xc7/delay.cc index 8b8b0ae7..67f96b98 100644 --- a/xc7/delay.cc +++ b/xc7/delay.cc @@ -25,79 +25,6 @@ NEXTPNR_NAMESPACE_BEGIN #define NUM_FUZZ_ROUTES 100000 -void ice40DelayFuzzerMain(Context *ctx) -{ - // std::vector srcWires, dstWires; - // - // for (int i = 0; i < ctx->chip_info->num_wires; i++) { - // WireId wire; - // wire.index = i; - // - // switch (ctx->chip_info->wire_data[i].type) { - // case WireInfoPOD::WIRE_TYPE_LUTFF_OUT: - // srcWires.push_back(wire); - // break; - // - // case WireInfoPOD::WIRE_TYPE_LUTFF_IN_LUT: - // dstWires.push_back(wire); - // break; - // - // default: - // break; - // } - // } - // - // ctx->shuffle(srcWires); - // ctx->shuffle(dstWires); - // - // int index = 0; - // int cnt = 0; - // - // while (cnt < NUM_FUZZ_ROUTES) { - // if (index >= int(srcWires.size()) || index >= int(dstWires.size())) { - // index = 0; - // ctx->shuffle(srcWires); - // ctx->shuffle(dstWires); - // } - // - // WireId src = srcWires[index]; - // WireId dst = dstWires[index++]; - // std::unordered_map route; - // - //#if NUM_FUZZ_ROUTES <= 1000 - // if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, false)) - // continue; - //#else - // if (!ctx->getActualRouteDelay(src, dst, nullptr, &route, true)) - // continue; - //#endif - // - // WireId cursor = dst; - // delay_t delay = 0; - // - // while (1) { - // delay += ctx->getWireDelay(cursor).maxDelay(); - // - // printf("%s %d %d %s %s %d %d\n", cursor == dst ? "dst" : "src", - // int(ctx->chip_info->wire_data[cursor.index].x), int(ctx->chip_info->wire_data[cursor.index].y), - // ctx->getWireType(cursor).c_str(ctx), ctx->getWireName(cursor).c_str(ctx), int(delay), - // int(ctx->estimateDelay(cursor, dst))); - // - // if (cursor == src) - // break; - // - // PipId pip = route.at(cursor); - // delay += ctx->getPipDelay(pip).maxDelay(); - // cursor = ctx->getPipSrcWire(pip); - // } - // - // cnt++; - // - // if (cnt % 100 == 0) - // fprintf(stderr, "Fuzzed %d arcs.\n", cnt); - // } -} - delay_t Arch::estimateDelay(WireId src, WireId dst) const { const auto &src_tw = torc_info->wire_to_tilewire[src.index]; diff --git a/xc7/pack.cc b/xc7/pack.cc index 14ec4fe7..a4b57f2a 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -128,172 +128,15 @@ static bool net_is_constant(const Context *ctx, NetInfo *net, bool &value) // Pack carry logic static void pack_carries(Context *ctx) { - log_info("Packing carries..\n"); - std::unordered_set exhausted_cells; - std::unordered_set packed_cells; - std::vector> new_cells; - - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - if (is_carry(ctx, ci)) { - packed_cells.insert(cell.first); - - CellInfo *carry_ci_lc; - bool ci_value; - bool ci_const = net_is_constant(ctx, ci->ports.at(ctx->id("CI")).net, ci_value); - if (ci_const) { - carry_ci_lc = nullptr; - } else { - carry_ci_lc = net_only_drives(ctx, ci->ports.at(ctx->id("CI")).net, is_lc, ctx->id("I3"), false); - } - - std::set i0_matches, i1_matches; - NetInfo *i0_net = ci->ports.at(ctx->id("I0")).net; - NetInfo *i1_net = ci->ports.at(ctx->id("I1")).net; - // Find logic cells connected to both I0 and I1 - if (i0_net) { - for (auto usr : i0_net->users) { - if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I1")) { - if (ctx->cells.find(usr.cell->name) != ctx->cells.end() && - exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) { - // This clause stops us double-packing cells - i0_matches.insert(usr.cell->name); - if (!i1_net) { - // I1 is don't care when disconnected, duplicate I0 - i1_matches.insert(usr.cell->name); - } - } - } - } - } - if (i1_net) { - for (auto usr : i1_net->users) { - if (is_lc(ctx, usr.cell) && usr.port == ctx->id("I2")) { - if (ctx->cells.find(usr.cell->name) != ctx->cells.end() && - exhausted_cells.find(usr.cell->name) == exhausted_cells.end()) { - // This clause stops us double-packing cells - i1_matches.insert(usr.cell->name); - if (!i0_net) { - // I0 is don't care when disconnected, duplicate I1 - i0_matches.insert(usr.cell->name); - } - } - } - } - } - - std::set carry_lcs; - std::set_intersection(i0_matches.begin(), i0_matches.end(), i1_matches.begin(), i1_matches.end(), - std::inserter(carry_lcs, carry_lcs.end())); - CellInfo *carry_lc = nullptr; - if (carry_ci_lc && carry_lcs.find(carry_ci_lc->name) != carry_lcs.end()) { - carry_lc = carry_ci_lc; - } else { - // No LC to pack into matching I0/I1, insert a new one - std::unique_ptr created_lc = - create_xc7_cell(ctx, ctx->id("XC7_LC"), cell.first.str(ctx) + "$CARRY"); - carry_lc = created_lc.get(); - created_lc->ports.at(ctx->id("I1")).net = i0_net; - if (i0_net) { - PortRef pr; - pr.cell = created_lc.get(); - pr.port = ctx->id("I1"); - i0_net->users.push_back(pr); - } - created_lc->ports.at(ctx->id("I2")).net = i1_net; - if (i1_net) { - PortRef pr; - pr.cell = created_lc.get(); - pr.port = ctx->id("I2"); - i1_net->users.push_back(pr); - } - new_cells.push_back(std::move(created_lc)); - } - carry_lc->params[ctx->id("CARRY_ENABLE")] = "1"; - replace_port(ci, ctx->id("CI"), carry_lc, ctx->id("CIN")); - replace_port(ci, ctx->id("CO"), carry_lc, ctx->id("COUT")); - if (i0_net) { - auto &i0_usrs = i0_net->users; - i0_usrs.erase(std::remove_if(i0_usrs.begin(), i0_usrs.end(), [ci, ctx](const PortRef &pr) { - return pr.cell == ci && pr.port == ctx->id("I0"); - })); - } - if (i1_net) { - auto &i1_usrs = i1_net->users; - i1_usrs.erase(std::remove_if(i1_usrs.begin(), i1_usrs.end(), [ci, ctx](const PortRef &pr) { - return pr.cell == ci && pr.port == ctx->id("I1"); - })); - } - - // Check for constant driver on CIN - if (carry_lc->ports.at(ctx->id("CIN")).net != nullptr) { - IdString cin_net = carry_lc->ports.at(ctx->id("CIN")).net->name; - if (cin_net == ctx->id("$PACKER_GND_NET") || cin_net == ctx->id("$PACKER_VCC_NET")) { - carry_lc->params[ctx->id("CIN_CONST")] = "1"; - carry_lc->params[ctx->id("CIN_SET")] = cin_net == ctx->id("$PACKER_VCC_NET") ? "1" : "0"; - carry_lc->ports.at(ctx->id("CIN")).net = nullptr; - auto &cin_users = ctx->nets.at(cin_net)->users; - cin_users.erase( - std::remove_if(cin_users.begin(), cin_users.end(), [carry_lc, ctx](const PortRef &pr) { - return pr.cell == carry_lc && pr.port == ctx->id("CIN"); - })); - } - } - exhausted_cells.insert(carry_lc->name); - } - } - for (auto pcell : packed_cells) { - ctx->cells.erase(pcell); - } - for (auto &ncell : new_cells) { - ctx->cells[ncell->name] = std::move(ncell); - } + //log_info("Packing carries..\n"); + // TODO } // "Pack" RAMs static void pack_ram(Context *ctx) { - log_info("Packing RAMs..\n"); - - std::unordered_set packed_cells; - std::vector> new_cells; - - for (auto cell : sorted(ctx->cells)) { - CellInfo *ci = cell.second; - if (is_ram(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_RAM"), ci->name.str(ctx) + "_RAM"); - packed_cells.insert(ci->name); - for (auto param : ci->params) - packed->params[param.first] = param.second; - packed->params[ctx->id("NEG_CLK_W")] = - std::to_string(ci->type == ctx->id("SB_RAM40_4KNW") || ci->type == ctx->id("SB_RAM40_4KNRNW")); - packed->params[ctx->id("NEG_CLK_R")] = - std::to_string(ci->type == ctx->id("SB_RAM40_4KNR") || ci->type == ctx->id("SB_RAM40_4KNRNW")); - packed->type = ctx->id("ICESTORM_RAM"); - for (auto port : ci->ports) { - PortInfo &pi = port.second; - std::string newname = pi.name.str(ctx); - size_t bpos = newname.find('['); - if (bpos != std::string::npos) { - newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); - } - if (pi.name == ctx->id("RCLKN")) - newname = "RCLK"; - else if (pi.name == ctx->id("WCLKN")) - newname = "WCLK"; - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); - } - new_cells.push_back(std::move(packed)); - } - } - - for (auto pcell : packed_cells) { - ctx->cells.erase(pcell); - } - for (auto &ncell : new_cells) { - ctx->cells[ncell->name] = std::move(ncell); - } + //log_info("Packing RAMs..\n"); + // TODO } // Merge a net into a constant net @@ -308,14 +151,6 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, NetInfo *constne if ((is_lut(ctx, uc) || is_lc(ctx, uc) || is_carry(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { uc->ports[user.port].net = nullptr; - } else if ((is_sb_mac16(ctx, uc) || uc->type == ctx->id("ICESTORM_DSP")) && - (user.port != id_CLK && - ((constval && user.port == ctx->id("CE")) || (!constval && user.port != ctx->id("CE"))))) { - uc->ports[user.port].net = nullptr; - } else if (is_ram(ctx, uc) && !constval && user.port != ctx->id("RCLK") && user.port != ctx->id("RCLKN") && - user.port != ctx->id("WCLK") && user.port != ctx->id("WCLKN") && user.port != ctx->id("RCLKE") && - user.port != ctx->id("WCLKE")) { - uc->ports[user.port].net = nullptr; } else { uc->ports[user.port].net = constnet; constnet->users.push_back(user); @@ -421,9 +256,9 @@ static void pack_io(Context *ctx) } } else { // Create a IOBUF buffer - std::unique_ptr ice_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx)); - nxio_to_sb(ctx, ci, ice_cell.get()); - new_cells.push_back(std::move(ice_cell)); + std::unique_ptr xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx)); + nxio_to_sb(ctx, ci, xc7_cell.get()); + new_cells.push_back(std::move(xc7_cell)); sb = new_cells.back().get(); } packed_cells.insert(ci->name); @@ -443,8 +278,7 @@ static bool is_logic_port(BaseCtx *ctx, const PortRef &port) { if (is_clock_port(ctx, port) || is_reset_port(ctx, port) || is_enable_port(ctx, port)) return false; - return !is_sb_io(ctx, port.cell) && !is_sb_pll40(ctx, port.cell) && !is_sb_pll40_pad(ctx, port.cell) && - port.cell->type != ctx->id("SB_GB"); + return !is_sb_io(ctx, port.cell) && port.cell->type != id_BUFGCTRL; } static void insert_global(Context *ctx, NetInfo *net, bool is_reset, bool is_cen, bool is_logic) @@ -855,242 +689,6 @@ static void pack_special(Context *ctx) ci->params.emplace(ctx->id("VREF_START"), "01"); ci->params[ctx->id("COMPENSATION")] = "INTERNAL"; - } else if (is_sb_lfosc(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_LFOSC"), ci->name.str(ctx) + "_OSC"); - packed_cells.insert(ci->name); - replace_port(ci, ctx->id("CLKLFEN"), packed.get(), ctx->id("CLKLFEN")); - replace_port(ci, ctx->id("CLKLFPU"), packed.get(), ctx->id("CLKLFPU")); - if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME - replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF_FABRIC")); - } else { - replace_port(ci, ctx->id("CLKLF"), packed.get(), ctx->id("CLKLF")); - } - new_cells.push_back(std::move(packed)); - } else if (is_sb_hfosc(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_HFOSC"), ci->name.str(ctx) + "_OSC"); - packed_cells.insert(ci->name); - packed->params[ctx->id("CLKHF_DIV")] = str_or_default(ci->params, ctx->id("CLKHF_DIV"), "0b00"); - replace_port(ci, ctx->id("CLKHFEN"), packed.get(), ctx->id("CLKHFEN")); - replace_port(ci, ctx->id("CLKHFPU"), packed.get(), ctx->id("CLKHFPU")); - if (/*bool_or_default(ci->attrs, ctx->id("ROUTE_THROUGH_FABRIC"))*/ true) { // FIXME - replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF_FABRIC")); - } else { - replace_port(ci, ctx->id("CLKHF"), packed.get(), ctx->id("CLKHF")); - } - new_cells.push_back(std::move(packed)); - } else if (is_sb_spram(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_SPRAM"), ci->name.str(ctx) + "_RAM"); - packed_cells.insert(ci->name); - for (auto port : ci->ports) { - PortInfo &pi = port.second; - std::string newname = pi.name.str(ctx); - size_t bpos = newname.find('['); - if (bpos != std::string::npos) { - newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); - } - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); - } - new_cells.push_back(std::move(packed)); - } else if (is_sb_mac16(ctx, ci)) { - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_DSP"), ci->name.str(ctx) + "_DSP"); - packed_cells.insert(ci->name); - for (auto attr : ci->attrs) - packed->attrs[attr.first] = attr.second; - for (auto param : ci->params) - packed->params[param.first] = param.second; - - for (auto port : ci->ports) { - PortInfo &pi = port.second; - std::string newname = pi.name.str(ctx); - size_t bpos = newname.find('['); - if (bpos != std::string::npos) { - newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); - } - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); - } - new_cells.push_back(std::move(packed)); - } else if (is_sb_pll40(ctx, ci)) { - bool is_pad = is_sb_pll40_pad(ctx, ci); - bool is_core = !is_pad; - - std::unique_ptr packed = - create_xc7_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL"); - packed->attrs[ctx->id("TYPE")] = ci->type.str(ctx); - packed_cells.insert(ci->name); - - for (auto attr : ci->attrs) - packed->attrs[attr.first] = attr.second; - for (auto param : ci->params) - packed->params[param.first] = param.second; - - auto feedback_path = packed->params[ctx->id("FEEDBACK_PATH")]; - packed->params[ctx->id("FEEDBACK_PATH")] = - feedback_path == "DELAY" - ? "0" - : feedback_path == "SIMPLE" ? "1" - : feedback_path == "PHASE_AND_DELAY" - ? "2" - : feedback_path == "EXTERNAL" ? "6" : feedback_path; - packed->params[ctx->id("PLLTYPE")] = std::to_string(sb_pll40_type(ctx, ci)); - - NetInfo *pad_packagepin_net = nullptr; - - for (auto port : ci->ports) { - PortInfo &pi = port.second; - std::string newname = pi.name.str(ctx); - size_t bpos = newname.find('['); - if (bpos != std::string::npos) { - newname = newname.substr(0, bpos) + "_" + newname.substr(bpos + 1, (newname.size() - bpos) - 2); - } - if (pi.name == ctx->id("PLLOUTCOREA")) - newname = "PLLOUT_A"; - if (pi.name == ctx->id("PLLOUTCOREB")) - newname = "PLLOUT_B"; - if (pi.name == ctx->id("PLLOUTCORE")) - newname = "PLLOUT_A"; - - if (pi.name == ctx->id("PACKAGEPIN")) { - if (!is_pad) { - log_error(" PLL '%s' has a PACKAGEPIN but is not a PAD PLL", ci->name.c_str(ctx)); - } else { - // We drop this port and instead place the PLL adequately below. - pad_packagepin_net = port.second.net; - NPNR_ASSERT(pad_packagepin_net != nullptr); - continue; - } - } - if (pi.name == ctx->id("REFERENCECLK")) { - if (!is_core) - log_error(" PLL '%s' has a REFERENCECLK but is not a CORE PLL", ci->name.c_str(ctx)); - } - - replace_port(ci, ctx->id(pi.name.c_str(ctx)), packed.get(), ctx->id(newname)); - } - - // If PLL is not constrained already, do that - we need this - // information to then constrain the LOCK LUT. - BelId pll_bel; - bool constrained = false; - if (packed->attrs.find(ctx->id("BEL")) == packed->attrs.end()) { - for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) != id_ICESTORM_PLL) - continue; - - // A PAD PLL must have its' PACKAGEPIN on the SB_IO that's shared - // with PLLOUT_A. - if (is_pad) { - auto pll_sb_io_belpin = ctx->getIOBSharingPLLPin(bel, id_PLLOUT_A); - NPNR_ASSERT(pad_packagepin_net != nullptr); - auto pll_packagepin_driver = pad_packagepin_net->driver; - NPNR_ASSERT(pll_packagepin_driver.cell != nullptr); - if (pll_packagepin_driver.cell->type != ctx->id("SB_IO")) { - log_error(" PLL '%s' has a PACKAGEPIN driven by " - "an %s, should be directly connected to an input SB_IO\n", - ci->name.c_str(ctx), pll_packagepin_driver.cell->type.c_str(ctx)); - } - - auto packagepin_cell = pll_packagepin_driver.cell; - auto packagepin_bel_name = packagepin_cell->attrs.find(ctx->id("BEL")); - if (packagepin_bel_name == packagepin_cell->attrs.end()) { - log_error(" PLL '%s' PACKAGEPIN SB_IO '%s' is unconstrained\n", ci->name.c_str(ctx), - packagepin_cell->name.c_str(ctx)); - } - auto packagepin_bel = ctx->getBelByName(ctx->id(packagepin_bel_name->second)); - if (pll_sb_io_belpin.bel != packagepin_bel) { - log_error(" PLL '%s' PACKAGEPIN is connected to pin %s, can only be pin %s\n", - ci->name.c_str(ctx), ctx->getBelPackagePin(packagepin_bel).c_str(), - ctx->getBelPackagePin(pll_sb_io_belpin.bel).c_str()); - } - if (pad_packagepin_net->users.size() != 1) { - log_error(" PLL '%s' clock input '%s' can only drive PLL\n", ci->name.c_str(ctx), - pad_packagepin_net->name.c_str(ctx)); - } - // Set an attribute about this PLL's PAD SB_IO. - packed->attrs[ctx->id("BEL_PAD_INPUT")] = packagepin_bel_name->second; - // Remove the connection from the SB_IO to the PLL. - packagepin_cell->ports.erase(pll_packagepin_driver.port); - } - - log_info(" constrained '%s' to %s\n", packed->name.c_str(ctx), ctx->getBelName(bel).c_str(ctx)); - packed->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx); - pll_bel = bel; - constrained = true; - } - if (!constrained) { - log_error(" could not constrain '%s' to any PLL Bel\n", packed->name.c_str(ctx)); - } - } - - // Delete the original PACKAGEPIN net if needed. - if (pad_packagepin_net != nullptr) { - for (auto user : pad_packagepin_net->users) { - user.cell->ports.erase(user.port); - } - ctx->nets.erase(pad_packagepin_net->name); - pad_packagepin_net = nullptr; - } - - // The LOCK signal on iCE40 PLLs goes through the neigh_op_bnl_1 wire. - // In practice, this means the LOCK signal can only directly reach LUT - // inputs. - // If we have a net connected to LOCK, make sure it only drives LUTs. - auto port = packed->ports[ctx->id("LOCK")]; - if (port.net != nullptr) { - bool found_lut = false; - bool all_luts = true; - unsigned int lut_count = 0; - for (const auto &user : port.net->users) { - NPNR_ASSERT(user.cell != nullptr); - if (user.cell->type == ctx->id("XC7_LC")) { - found_lut = true; - lut_count++; - } else { - all_luts = false; - } - } - - if (found_lut && all_luts) { - // Every user is a LUT, carry on now. - } else if (found_lut && !all_luts && lut_count < 8) { - // Strategy: create a pass-through LUT, move all non-LUT users behind it. - log_info(" LUT strategy for %s: move non-LUT users to new LUT\n", port.name.c_str(ctx)); - auto pt = spliceLUT(ctx, packed.get(), port.name, true); - new_cells.push_back(std::move(pt)); - } else { - // Strategy: create a pass-through LUT, move every user behind it. - log_info(" LUT strategy for %s: move all users to new LUT\n", port.name.c_str(ctx)); - auto pt = spliceLUT(ctx, packed.get(), port.name, false); - new_cells.push_back(std::move(pt)); - } - - // Find wire that will be driven by this port. - const auto pll_out_wire = ctx->getBelPinWire(pll_bel, port.name); - NPNR_ASSERT(pll_out_wire != WireId()); - - // Now, constrain all LUTs on the output of the signal to be at - // the correct Bel relative to the PLL Bel. - // int x = ctx->chip_info->wire_data[pll_out_wire.index].x; - // int y = ctx->chip_info->wire_data[pll_out_wire.index].y; - // int z = 0; - // for (const auto &user : port.net->users) { - // NPNR_ASSERT(user.cell != nullptr); - // NPNR_ASSERT(user.cell->type == ctx->id("XC7_LC")); - - // // TODO(q3k): handle when the Bel might be already the - // // target of another constraint. - // NPNR_ASSERT(z < 8); - // auto target_bel = ctx->getBelByLocation(Loc(x, y, z++)); - // auto target_bel_name = ctx->getBelName(target_bel).str(ctx); - // user.cell->attrs[ctx->id("BEL")] = target_bel_name; - // log_info(" constrained '%s' to %s\n", user.cell->name.c_str(ctx), target_bel_name.c_str()); - //} - } - - new_cells.push_back(std::move(packed)); } } From a0a6281d0d727250b473a9a9a16254f17a01c029 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Wed, 26 Dec 2018 18:15:01 -0800 Subject: [PATCH 155/174] Remove HACK for BUFG routing --- common/router1.cc | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 0b46dbb1..61075d84 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -445,26 +445,6 @@ struct Router1 auto dst_wire = ctx->getNetinfoSinkWire(net_info, net_info->users[user_idx]); ripup_flag = false; -#ifdef ARCH_XC7 - // Work around the fact that BUFG inputs have a logical location far away from its IMUX by introducing an "imux_wire" to guide A* routing - auto imux_wire = dst_wire; - const auto &dst_tw = torc_info->wire_to_tilewire[dst_wire.index]; - - const auto &tileInfo = torc_info->tiles.getTileInfo(dst_tw.getTileIndex()); - const auto tileTypeName = torc_info->tiles.getTileTypeName(tileInfo.getTypeIndex()); - if (boost::starts_with(tileTypeName, "CLK")) { - TilewireVector sources; - const_cast(*torc_info->ddb).expandTilewireSources(dst_tw, sources, false /*inUseTied*/, true /*inUseRegular*/, false /*inUseIrregular*/, false /*inUseRoutethrough*/); - std::cout << ctx->getWireName(torc_info->tilewire_to_wire(dst_tw)).str(ctx); - if (sources.size() == 1) { - imux_wire = torc_info->tilewire_to_wire(sources.front()); - std::cout << " -> " << ctx->getWireName(imux_wire).str(ctx) << std::endl; - } - else - std::cout << " has " << sources.size() << " sources" << std::endl; - } -#endif - if (ctx->debug) { log("Routing arc %d on net %s (%d arcs total):\n", user_idx, ctx->nameOf(net_info), int(net_info->users.size())); From 5072d184ab81fef1927d673efcdbfb2c5bd8ff72 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:10:12 -0800 Subject: [PATCH 156/174] One more thing --- common/router1.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/common/router1.cc b/common/router1.cc index 61075d84..2c3f6683 100644 --- a/common/router1.cc +++ b/common/router1.cc @@ -633,11 +633,7 @@ struct Router1 next_qw.penalty = next_penalty; next_qw.bonus = next_bonus; if (cfg.useEstimate) { -#ifdef ARCH_XC7 - next_qw.togo = ctx->estimateDelay(next_wire, imux_wire); -#else next_qw.togo = ctx->estimateDelay(next_wire, dst_wire); -#endif delay_t this_est = next_qw.delay + next_qw.togo; if (this_est / 2 - cfg.estimatePrecision > best_est) continue; From 60fc4735bfc10cb64d3acd60182037acc14c3fc2 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:24:52 -0800 Subject: [PATCH 157/174] Add torc as submodule --- .gitmodules | 3 +++ torc | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 torc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..c0b8228d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "torc"] + path = torc + url = https://github.com/eddiehung/torc diff --git a/torc b/torc new file mode 160000 index 00000000..a5a4ec05 --- /dev/null +++ b/torc @@ -0,0 +1 @@ +Subproject commit a5a4ec057eae3ed07ed2acb9da13404808e37211 From 64f3f252701280532cc3a47f48d6feabf1605628 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:25:07 -0800 Subject: [PATCH 158/174] Update xc7/family.cmake to use submodule torc --- xc7/family.cmake | 130 ++++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 64 deletions(-) diff --git a/xc7/family.cmake b/xc7/family.cmake index c3eab64a..9de869ee 100644 --- a/xc7/family.cmake +++ b/xc7/family.cmake @@ -1,71 +1,73 @@ -include_directories(/opt/torc/src) -#include_directories(torc/externals/zlib) - +add_dependencies(nextpnr-${family} torc) +add_custom_target(torc ALL + COMMAND $(MAKE) > /dev/null 2> /dev/null + COMMENT "Building torc (may take some time...)" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/torc/src) find_package(Boost REQUIRED COMPONENTS serialization iostreams ${boost_libs} ${boost_python_lib}) +include_directories(torc/src) target_link_libraries( - nextpnr-${family} - PRIVATE /opt/torc/src/torc/architecture/Arc.o - PRIVATE /opt/torc/src/torc/architecture/ArcUsage.o - PRIVATE /opt/torc/src/torc/architecture/Array.o - PRIVATE /opt/torc/src/torc/architecture/DDB.o - PRIVATE /opt/torc/src/torc/architecture/DDBConsoleStreams.o - PRIVATE /opt/torc/src/torc/architecture/DDBStreamHelper.o - PRIVATE /opt/torc/src/torc/architecture/DigestStream.o - PRIVATE /opt/torc/src/torc/architecture/ExtendedWireInfo.o - PRIVATE /opt/torc/src/torc/architecture/InstancePin.o - PRIVATE /opt/torc/src/torc/architecture/OutputStreamHelpers.o - PRIVATE /opt/torc/src/torc/architecture/Package.o - PRIVATE /opt/torc/src/torc/architecture/Pad.o - PRIVATE /opt/torc/src/torc/architecture/PrimitiveConn.o - PRIVATE /opt/torc/src/torc/architecture/PrimitiveDef.o - PRIVATE /opt/torc/src/torc/architecture/PrimitiveElement.o - PRIVATE /opt/torc/src/torc/architecture/PrimitiveElementPin.o - PRIVATE /opt/torc/src/torc/architecture/PrimitivePin.o - PRIVATE /opt/torc/src/torc/architecture/Segments.o - PRIVATE /opt/torc/src/torc/architecture/Site.o - PRIVATE /opt/torc/src/torc/architecture/Sites.o - PRIVATE /opt/torc/src/torc/architecture/Tiles.o - PRIVATE /opt/torc/src/torc/architecture/TileInfo.o - PRIVATE /opt/torc/src/torc/architecture/Tilewire.o - PRIVATE /opt/torc/src/torc/architecture/Versions.o - PRIVATE /opt/torc/src/torc/architecture/VprExporter.o - PRIVATE /opt/torc/src/torc/architecture/WireInfo.o - PRIVATE /opt/torc/src/torc/architecture/WireUsage.o - PRIVATE /opt/torc/src/torc/architecture/XdlImporter.o - PRIVATE /opt/torc/src/torc/architecture/XilinxDatabaseTypes.o + nextpnr-${family} PRIVATE - PRIVATE /opt/torc/src/torc/common/Annotated.o - PRIVATE /opt/torc/src/torc/common/DeviceDesignator.o - PRIVATE /opt/torc/src/torc/common/Devices.o - PRIVATE /opt/torc/src/torc/common/DirectoryTree.o - PRIVATE /opt/torc/src/torc/common/DottedVersion.o - PRIVATE /opt/torc/src/torc/common/NullOutputStream.o - PRIVATE boost_regex + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Arc.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/ArcUsage.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Array.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/DDB.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/DDBConsoleStreams.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/DDBStreamHelper.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/DigestStream.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/ExtendedWireInfo.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/InstancePin.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/OutputStreamHelpers.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Package.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Pad.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/PrimitiveConn.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/PrimitiveDef.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/PrimitiveElement.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/PrimitiveElementPin.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/PrimitivePin.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Segments.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Site.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Sites.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Tiles.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/TileInfo.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Tilewire.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/Versions.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/VprExporter.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/WireInfo.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/WireUsage.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/XdlImporter.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/architecture/XilinxDatabaseTypes.o - PRIVATE /opt/torc/src/torc/externals/zlib/zfstream.o - PRIVATE z + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/Annotated.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/DeviceDesignator.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/Devices.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/DirectoryTree.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/DottedVersion.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/common/NullOutputStream.o - PRIVATE /opt/torc/src/torc/physical/Circuit.o - PRIVATE /opt/torc/src/torc/physical/ConfigMap.o - PRIVATE /opt/torc/src/torc/physical/Config.o - PRIVATE /opt/torc/src/torc/physical/Design.o - PRIVATE /opt/torc/src/torc/physical/Factory.o - PRIVATE /opt/torc/src/torc/physical/Instance.o - PRIVATE /opt/torc/src/torc/physical/InstancePin.o - PRIVATE /opt/torc/src/torc/physical/InstanceReference.o - PRIVATE /opt/torc/src/torc/physical/Module.o - PRIVATE /opt/torc/src/torc/physical/ModuleTransformer.o - PRIVATE /opt/torc/src/torc/physical/Named.o - PRIVATE /opt/torc/src/torc/physical/Net.o - PRIVATE /opt/torc/src/torc/physical/OutputStreamHelpers.o - PRIVATE /opt/torc/src/torc/physical/Pip.o - PRIVATE /opt/torc/src/torc/physical/Port.o - PRIVATE /opt/torc/src/torc/physical/Progenitor.o - PRIVATE /opt/torc/src/torc/physical/Progeny.o - PRIVATE /opt/torc/src/torc/physical/Renamable.o - PRIVATE /opt/torc/src/torc/physical/Routethrough.o - PRIVATE /opt/torc/src/torc/physical/TilewirePlaceholder.o - PRIVATE /opt/torc/src/torc/physical/XdlExporter.o -# PRIVATE /opt/torc/src/torc/physical/XdlImporter.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/externals/zlib/zfstream.o + z + + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Circuit.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/ConfigMap.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Config.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Design.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Factory.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Instance.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/InstancePin.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/InstanceReference.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Module.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/ModuleTransformer.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Named.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Net.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/OutputStreamHelpers.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Pip.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Port.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Progenitor.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Progeny.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Renamable.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/Routethrough.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/TilewirePlaceholder.o + ${CMAKE_CURRENT_SOURCE_DIR}/torc/src/torc/physical/XdlExporter.o ) From ab35983000f5749a2ed7f52b58803eda3027d683 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:25:22 -0800 Subject: [PATCH 159/174] Use std::regex not boost::regex (even though Torc still depends on latter) --- xc7/arch.cc | 47 ++++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/xc7/arch.cc b/xc7/arch.cc index 6ec2d521..87864a3d 100644 --- a/xc7/arch.cc +++ b/xc7/arch.cc @@ -20,6 +20,7 @@ #include #include +#include #include "cells.h" #include "gfx.h" #include "log.h" @@ -36,12 +37,12 @@ std::unique_ptr torc_info; TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::string &inPackageName) : TorcInfo(inDeviceName, inPackageName) { - static const boost::regex re_loc(".+_X(\\d+)Y(\\d+)"); - boost::cmatch what; + static const std::regex re_loc(".+_X(\\d+)Y(\\d+)"); + std::cmatch what; tile_to_xy.resize(tiles.getTileCount()); for (TileIndex tileIndex(0); tileIndex < tiles.getTileCount(); tileIndex++) { const auto &tileInfo = tiles.getTileInfo(tileIndex); - if (!boost::regex_match(tileInfo.getName(), what, re_loc)) + if (!std::regex_match(tileInfo.getName(), what, re_loc)) throw; const auto x = boost::lexical_cast(what.str(1)); const auto y = boost::lexical_cast(what.str(2)); @@ -68,7 +69,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_site_index.push_back(i); site_index_to_type[i] = id_SLICE_LUT6; const auto site_name = site.getName(); - if (!boost::regex_match(site_name.c_str(), what, re_loc)) + if (!std::regex_match(site_name.c_str(), what, re_loc)) throw; const auto sx = boost::lexical_cast(what.str(1)); if ((sx & 1) == 0) { @@ -110,16 +111,16 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str bel_to_site_index.shrink_to_fit(); bel_to_loc.shrink_to_fit(); - const boost::regex re_124("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); - const boost::regex re_L("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); - const boost::regex re_BYP("BYP(_ALT)?\\d"); - const boost::regex re_BYP_B("BYP_[BL]\\d"); - const boost::regex re_BOUNCE_NS("(BYP|FAN)_BOUNCE_[NS]3_\\d"); - const boost::regex re_FAN("FAN(_ALT)?\\d"); - const boost::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); - const boost::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); - const boost::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); - const boost::regex hrow("CLK_HROW_CLK[01]_[34]"); + const std::regex re_124("(.+_)?[NESW][NESWLR](\\d)((BEG(_[NS])?)|(END(_[NS])?)|[A-E])?\\d(_\\d)?"); + const std::regex re_L("(.+_)?L(H|V|VB)(_L)?\\d+(_\\d)?"); + const std::regex re_BYP("BYP(_ALT)?\\d"); + const std::regex re_BYP_B("BYP_[BL]\\d"); + const std::regex re_BOUNCE_NS("(BYP|FAN)_BOUNCE_[NS]3_\\d"); + const std::regex re_FAN("FAN(_ALT)?\\d"); + const std::regex re_CLB_I1_6("CLBL[LM]_(L|LL|M)_[A-D]([1-6])"); + const std::regex bufg_i("CLK_BUFG_BUFGCTRL\\d+_I0"); + const std::regex bufg_o("CLK_BUFG_BUFGCTRL\\d+_O"); + const std::regex hrow("CLK_HROW_CLK[01]_[34]"); std::unordered_map> delay_lookup; std::unordered_map segment_to_anchor; Tilewire currentTilewire; @@ -171,7 +172,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str for (WireIndex wireIndex(0); wireIndex < wireCount; wireIndex++) { const WireInfo &wireInfo = tiles.getWireInfo(tileTypeIndex, wireIndex); auto wire_name = wireInfo.getName(); - if (boost::regex_match(wire_name, what, re_124)) { + if (std::regex_match(wire_name, what, re_124)) { switch (what.str(2)[0]) { case '1': tile_delays[wireIndex] = 150; @@ -188,7 +189,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str default: throw; } - } else if (boost::regex_match(wire_name, what, re_L)) { + } else if (std::regex_match(wire_name, what, re_L)) { std::string l(what[2]); if (l == "H") tile_delays[wireIndex] = 360; @@ -198,12 +199,12 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str tile_delays[wireIndex] = 350; else throw; - } else if (boost::regex_match(wire_name, what, re_BYP)) { + } else if (std::regex_match(wire_name, what, re_BYP)) { tile_delays[wireIndex] = 190; - } else if (boost::regex_match(wire_name, what, re_BYP_B)) { - } else if (boost::regex_match(wire_name, what, re_FAN)) { + } else if (std::regex_match(wire_name, what, re_BYP_B)) { + } else if (std::regex_match(wire_name, what, re_FAN)) { tile_delays[wireIndex] = 190; - } else if (boost::regex_match(wire_name, what, re_CLB_I1_6)) { + } else if (std::regex_match(wire_name, what, re_CLB_I1_6)) { switch (what.str(2)[0]) { case '1': tile_delays[wireIndex] = 280; @@ -297,9 +298,9 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str // Disable BUFG I0 -> O routethrough if (clk_tile) { ewi.set(a.getSourceTilewire()); - if (boost::regex_match(ewi.mWireName, bufg_i)) { + if (std::regex_match(ewi.mWireName, bufg_i)) { ewi.set(a.getSinkTilewire()); - if (boost::regex_match(ewi.mWireName, bufg_o)) + if (std::regex_match(ewi.mWireName, bufg_o)) continue; } } @@ -307,7 +308,7 @@ TorcInfo::TorcInfo(BaseCtx *ctx, const std::string &inDeviceName, const std::str // Disable entering HROW from INT_[LR].CLK[01] if (boost::starts_with(tileTypeName, "CLK_HROW")) { ewi.set(a.getSourceTilewire()); - if (boost::regex_match(ewi.mWireName, hrow)) + if (std::regex_match(ewi.mWireName, hrow)) continue; } From cbc01f0f7194e1bf5f0f6bf3f38670265b423bf9 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:39:41 -0800 Subject: [PATCH 160/174] Revert "Do not add "$iob" suffix" This reverts commit 10d6db6d94873068809e26c9e3e724683f0339b1. --- xc7/pack.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/pack.cc b/xc7/pack.cc index a4b57f2a..7d4f571e 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -256,7 +256,7 @@ static void pack_io(Context *ctx) } } else { // Create a IOBUF buffer - std::unique_ptr xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx)); + std::unique_ptr xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); nxio_to_sb(ctx, ci, xc7_cell.get()); new_cells.push_back(std::move(xc7_cell)); sb = new_cells.back().get(); From 9790cea186c8ac6c3b22989f7717c06cc69a206a Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:43:10 -0800 Subject: [PATCH 161/174] Revert "Revert "Do not add "$iob" suffix"" This reverts commit cbc01f0f7194e1bf5f0f6bf3f38670265b423bf9. --- xc7/pack.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/pack.cc b/xc7/pack.cc index 7d4f571e..a4b57f2a 100644 --- a/xc7/pack.cc +++ b/xc7/pack.cc @@ -256,7 +256,7 @@ static void pack_io(Context *ctx) } } else { // Create a IOBUF buffer - std::unique_ptr xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx) + "$iob"); + std::unique_ptr xc7_cell = create_xc7_cell(ctx, ctx->id("IOBUF"), ci->name.str(ctx)); nxio_to_sb(ctx, ci, xc7_cell.get()); new_cells.push_back(std::move(xc7_cell)); sb = new_cells.back().get(); From 5b438116e519dc1be00236ae5c44a6e3f25e322b Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:53:11 -0800 Subject: [PATCH 162/174] Always set SYNC_ATTR otherwise netgen fails --- xc7/cells.cc | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/xc7/cells.cc b/xc7/cells.cc index 07cb30b0..601aacca 100644 --- a/xc7/cells.cc +++ b/xc7/cells.cc @@ -118,40 +118,40 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l if (*citer == 'S') { citer++; if (get_net_or_empty(dff, id_S) != gnd_net) { - lc->params[id_SR] = "SRHIGH"; - lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; + lc->params[id_SR] = "SRHIGH"; replace_port(dff, id_S, lc, id_SR); - } + } else disconnect_port(ctx, dff, id_S); + lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; } else if (*citer == 'R') { citer++; if (get_net_or_empty(dff, id_R) != gnd_net) { - lc->params[id_SR] = "SRLOW"; - lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; + lc->params[id_SR] = "SRLOW"; replace_port(dff, id_R, lc, id_SR); - } + } else disconnect_port(ctx, dff, id_R); + lc->params[ctx->id("SYNC_ATTR")] = "SYNC"; } else if (*citer == 'C') { citer++; if (get_net_or_empty(dff, id_CLR) != gnd_net) { - lc->params[id_SR] = "SRLOW"; - lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; + lc->params[id_SR] = "SRLOW"; replace_port(dff, id_CLR, lc, id_SR); - } + } else disconnect_port(ctx, dff, id_CLR); + lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; } else { NPNR_ASSERT(*citer == 'P'); citer++; if (get_net_or_empty(dff, id_PRE) != gnd_net) { - lc->params[id_SR] = "SRHIGH"; - lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; + lc->params[id_SR] = "SRHIGH"; replace_port(dff, id_PRE, lc, id_SR); - } + } else disconnect_port(ctx, dff, id_PRE); + lc->params[ctx->id("SYNC_ATTR")] = "ASYNC"; } } From afc89a60e8cb60286d09d97b79194fdb0cdb5d9e Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 21:56:15 -0800 Subject: [PATCH 163/174] Write SYNC_ATTR to xdl too --- xc7/xdl.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xc7/xdl.cc b/xc7/xdl.cc index ef1be83e..2687d738 100644 --- a/xc7/xdl.cc +++ b/xc7/xdl.cc @@ -182,9 +182,9 @@ DesignSharedPtr create_torc_design(const Context *ctx) if (get_net_or_empty(cell.second.get(), id_SR)) { instPtr->setConfig(setting + "SR", "", cell.second->params.at(id_SR)); - instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); instPtr->setConfig("SRUSEDMUX", "", "IN"); } + instPtr->setConfig("SYNC_ATTR", "", cell.second->params.at(ctx->id("SYNC_ATTR"))); if (get_net_or_empty(cell.second.get(), ctx->id("CE"))) instPtr->setConfig("CEUSEDMUX", "", "IN"); From 88e7267510903a9aac9d321fc02c891381541ddf Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:02:22 -0800 Subject: [PATCH 164/174] Remove ps7.vh --- xc7/ps7.vh | 328 ----------------------------------------------------- 1 file changed, 328 deletions(-) delete mode 100644 xc7/ps7.vh diff --git a/xc7/ps7.vh b/xc7/ps7.vh deleted file mode 100644 index 445e67aa..00000000 --- a/xc7/ps7.vh +++ /dev/null @@ -1,328 +0,0 @@ -(* keep *) -PS7 ps7_stub( - .DDRARB ('b0), - .DMA0ACLK ('b0), - .DMA0DAREADY ('b0), - .DMA0DRLAST ('b0), - .DMA0DRTYPE ('b0), - .DMA0DRVALID ('b0), - .DMA1ACLK ('b0), - .DMA1DAREADY ('b0), - .DMA1DRLAST ('b0), - .DMA1DRTYPE ('b0), - .DMA1DRVALID ('b0), - .DMA2ACLK ('b0), - .DMA2DAREADY ('b0), - .DMA2DRLAST ('b0), - .DMA2DRTYPE ('b0), - .DMA2DRVALID ('b0), - .DMA3ACLK ('b0), - .DMA3DAREADY ('b0), - .DMA3DRLAST ('b0), - .DMA3DRTYPE ('b0), - .DMA3DRVALID ('b0), - .EMIOCAN0PHYRX ('b0), - .EMIOCAN1PHYRX ('b0), - .EMIOENET0EXTINTIN ('b0), - .EMIOENET0GMIICOL ('b0), - .EMIOENET0GMIICRS ('b0), - .EMIOENET0GMIIRXCLK ('b0), - .EMIOENET0GMIIRXD ('b0), - .EMIOENET0GMIIRXDV ('b0), - .EMIOENET0GMIIRXER ('b0), - .EMIOENET0GMIITXCLK ('b0), - .EMIOENET0MDIOI ('b0), - .EMIOENET1EXTINTIN ('b0), - .EMIOENET1GMIICOL ('b0), - .EMIOENET1GMIICRS ('b0), - .EMIOENET1GMIIRXCLK ('b0), - .EMIOENET1GMIIRXD ('b0), - .EMIOENET1GMIIRXDV ('b0), - .EMIOENET1GMIIRXER ('b0), - .EMIOENET1GMIITXCLK ('b0), - .EMIOENET1MDIOI ('b0), - .EMIOGPIOI ('b0), - .EMIOI2C0SCLI ('b0), - .EMIOI2C0SDAI ('b0), - .EMIOI2C1SCLI ('b0), - .EMIOI2C1SDAI ('b0), - .EMIOPJTAGTCK ('b0), - .EMIOPJTAGTDI ('b0), - .EMIOPJTAGTMS ('b0), - .EMIOSDIO0CDN ('b0), - .EMIOSDIO0CLKFB ('b0), - .EMIOSDIO0CMDI ('b0), - .EMIOSDIO0DATAI ('b0), - .EMIOSDIO0WP ('b0), - .EMIOSDIO1CDN ('b0), - .EMIOSDIO1CLKFB ('b0), - .EMIOSDIO1CMDI ('b0), - .EMIOSDIO1DATAI ('b0), - .EMIOSDIO1WP ('b0), - .EMIOSPI0MI ('b0), - .EMIOSPI0SCLKI ('b0), - .EMIOSPI0SI ('b0), - .EMIOSPI0SSIN ('b0), - .EMIOSPI1MI ('b0), - .EMIOSPI1SCLKI ('b0), - .EMIOSPI1SI ('b0), - .EMIOSPI1SSIN ('b0), - .EMIOSRAMINTIN ('b0), - .EMIOTRACECLK ('b0), - .EMIOTTC0CLKI ('b0), - .EMIOTTC1CLKI ('b0), - .EMIOUART0CTSN ('b0), - .EMIOUART0DCDN ('b0), - .EMIOUART0DSRN ('b0), - .EMIOUART0RIN ('b0), - .EMIOUART0RX ('b0), - .EMIOUART1CTSN ('b0), - .EMIOUART1DCDN ('b0), - .EMIOUART1DSRN ('b0), - .EMIOUART1RIN ('b0), - .EMIOUART1RX ('b0), - .EMIOUSB0VBUSPWRFAULT ('b0), - .EMIOUSB1VBUSPWRFAULT ('b0), - .EMIOWDTCLKI ('b0), - .EVENTEVENTI ('b0), - .FCLKCLKTRIGN ('b0), - .FPGAIDLEN ('b0), - .FTMDTRACEINATID ('b0), - .FTMDTRACEINCLOCK ('b0), - .FTMDTRACEINDATA ('b0), - .FTMDTRACEINVALID ('b0), - .FTMTF2PDEBUG ('b0), - .FTMTF2PTRIG ('b0), - .FTMTP2FTRIGACK ('b0), - .IRQF2P ('b0), - .MAXIGP0ACLK ('b0), - .MAXIGP0ARREADY ('b0), - .MAXIGP0AWREADY ('b0), - .MAXIGP0BID ('b0), - .MAXIGP0BRESP ('b0), - .MAXIGP0BVALID ('b0), - .MAXIGP0RDATA ('b0), - .MAXIGP0RID ('b0), - .MAXIGP0RLAST ('b0), - .MAXIGP0RRESP ('b0), - .MAXIGP0RVALID ('b0), - .MAXIGP0WREADY ('b0), - .MAXIGP1ACLK ('b0), - .MAXIGP1ARREADY ('b0), - .MAXIGP1AWREADY ('b0), - .MAXIGP1BID ('b0), - .MAXIGP1BRESP ('b0), - .MAXIGP1BVALID ('b0), - .MAXIGP1RDATA ('b0), - .MAXIGP1RID ('b0), - .MAXIGP1RLAST ('b0), - .MAXIGP1RRESP ('b0), - .MAXIGP1RVALID ('b0), - .MAXIGP1WREADY ('b0), - .SAXIACPACLK ('b0), - .SAXIACPARADDR ('b0), - .SAXIACPARBURST ('b0), - .SAXIACPARCACHE ('b0), - .SAXIACPARID ('b0), - .SAXIACPARLEN ('b0), - .SAXIACPARLOCK ('b0), - .SAXIACPARPROT ('b0), - .SAXIACPARQOS ('b0), - .SAXIACPARSIZE ('b0), - .SAXIACPARUSER ('b0), - .SAXIACPARVALID ('b0), - .SAXIACPAWADDR ('b0), - .SAXIACPAWBURST ('b0), - .SAXIACPAWCACHE ('b0), - .SAXIACPAWID ('b0), - .SAXIACPAWLEN ('b0), - .SAXIACPAWLOCK ('b0), - .SAXIACPAWPROT ('b0), - .SAXIACPAWQOS ('b0), - .SAXIACPAWSIZE ('b0), - .SAXIACPAWUSER ('b0), - .SAXIACPAWVALID ('b0), - .SAXIACPBREADY ('b0), - .SAXIACPRREADY ('b0), - .SAXIACPWDATA ('b0), - .SAXIACPWID ('b0), - .SAXIACPWLAST ('b0), - .SAXIACPWSTRB ('b0), - .SAXIACPWVALID ('b0), - .SAXIGP0ACLK ('b0), - .SAXIGP0ARADDR ('b0), - .SAXIGP0ARBURST ('b0), - .SAXIGP0ARCACHE ('b0), - .SAXIGP0ARID ('b0), - .SAXIGP0ARLEN ('b0), - .SAXIGP0ARLOCK ('b0), - .SAXIGP0ARPROT ('b0), - .SAXIGP0ARQOS ('b0), - .SAXIGP0ARSIZE ('b0), - .SAXIGP0ARVALID ('b0), - .SAXIGP0AWADDR ('b0), - .SAXIGP0AWBURST ('b0), - .SAXIGP0AWCACHE ('b0), - .SAXIGP0AWID ('b0), - .SAXIGP0AWLEN ('b0), - .SAXIGP0AWLOCK ('b0), - .SAXIGP0AWPROT ('b0), - .SAXIGP0AWQOS ('b0), - .SAXIGP0AWSIZE ('b0), - .SAXIGP0AWVALID ('b0), - .SAXIGP0BREADY ('b0), - .SAXIGP0RREADY ('b0), - .SAXIGP0WDATA ('b0), - .SAXIGP0WID ('b0), - .SAXIGP0WLAST ('b0), - .SAXIGP0WSTRB ('b0), - .SAXIGP0WVALID ('b0), - .SAXIGP1ACLK ('b0), - .SAXIGP1ARADDR ('b0), - .SAXIGP1ARBURST ('b0), - .SAXIGP1ARCACHE ('b0), - .SAXIGP1ARID ('b0), - .SAXIGP1ARLEN ('b0), - .SAXIGP1ARLOCK ('b0), - .SAXIGP1ARPROT ('b0), - .SAXIGP1ARQOS ('b0), - .SAXIGP1ARSIZE ('b0), - .SAXIGP1ARVALID ('b0), - .SAXIGP1AWADDR ('b0), - .SAXIGP1AWBURST ('b0), - .SAXIGP1AWCACHE ('b0), - .SAXIGP1AWID ('b0), - .SAXIGP1AWLEN ('b0), - .SAXIGP1AWLOCK ('b0), - .SAXIGP1AWPROT ('b0), - .SAXIGP1AWQOS ('b0), - .SAXIGP1AWSIZE ('b0), - .SAXIGP1AWVALID ('b0), - .SAXIGP1BREADY ('b0), - .SAXIGP1RREADY ('b0), - .SAXIGP1WDATA ('b0), - .SAXIGP1WID ('b0), - .SAXIGP1WLAST ('b0), - .SAXIGP1WSTRB ('b0), - .SAXIGP1WVALID ('b0), - .SAXIHP0ACLK ('b0), - .SAXIHP0ARADDR ('b0), - .SAXIHP0ARBURST ('b0), - .SAXIHP0ARCACHE ('b0), - .SAXIHP0ARID ('b0), - .SAXIHP0ARLEN ('b0), - .SAXIHP0ARLOCK ('b0), - .SAXIHP0ARPROT ('b0), - .SAXIHP0ARQOS ('b0), - .SAXIHP0ARSIZE ('b0), - .SAXIHP0ARVALID ('b0), - .SAXIHP0AWADDR ('b0), - .SAXIHP0AWBURST ('b0), - .SAXIHP0AWCACHE ('b0), - .SAXIHP0AWID ('b0), - .SAXIHP0AWLEN ('b0), - .SAXIHP0AWLOCK ('b0), - .SAXIHP0AWPROT ('b0), - .SAXIHP0AWQOS ('b0), - .SAXIHP0AWSIZE ('b0), - .SAXIHP0AWVALID ('b0), - .SAXIHP0BREADY ('b0), - .SAXIHP0RDISSUECAP1EN ('b0), - .SAXIHP0RREADY ('b0), - .SAXIHP0WDATA ('b0), - .SAXIHP0WID ('b0), - .SAXIHP0WLAST ('b0), - .SAXIHP0WRISSUECAP1EN ('b0), - .SAXIHP0WSTRB ('b0), - .SAXIHP0WVALID ('b0), - .SAXIHP1ACLK ('b0), - .SAXIHP1ARADDR ('b0), - .SAXIHP1ARBURST ('b0), - .SAXIHP1ARCACHE ('b0), - .SAXIHP1ARID ('b0), - .SAXIHP1ARLEN ('b0), - .SAXIHP1ARLOCK ('b0), - .SAXIHP1ARPROT ('b0), - .SAXIHP1ARQOS ('b0), - .SAXIHP1ARSIZE ('b0), - .SAXIHP1ARVALID ('b0), - .SAXIHP1AWADDR ('b0), - .SAXIHP1AWBURST ('b0), - .SAXIHP1AWCACHE ('b0), - .SAXIHP1AWID ('b0), - .SAXIHP1AWLEN ('b0), - .SAXIHP1AWLOCK ('b0), - .SAXIHP1AWPROT ('b0), - .SAXIHP1AWQOS ('b0), - .SAXIHP1AWSIZE ('b0), - .SAXIHP1AWVALID ('b0), - .SAXIHP1BREADY ('b0), - .SAXIHP1RDISSUECAP1EN ('b0), - .SAXIHP1RREADY ('b0), - .SAXIHP1WDATA ('b0), - .SAXIHP1WID ('b0), - .SAXIHP1WLAST ('b0), - .SAXIHP1WRISSUECAP1EN ('b0), - .SAXIHP1WSTRB ('b0), - .SAXIHP1WVALID ('b0), - .SAXIHP2ACLK ('b0), - .SAXIHP2ARADDR ('b0), - .SAXIHP2ARBURST ('b0), - .SAXIHP2ARCACHE ('b0), - .SAXIHP2ARID ('b0), - .SAXIHP2ARLEN ('b0), - .SAXIHP2ARLOCK ('b0), - .SAXIHP2ARPROT ('b0), - .SAXIHP2ARQOS ('b0), - .SAXIHP2ARSIZE ('b0), - .SAXIHP2ARVALID ('b0), - .SAXIHP2AWADDR ('b0), - .SAXIHP2AWBURST ('b0), - .SAXIHP2AWCACHE ('b0), - .SAXIHP2AWID ('b0), - .SAXIHP2AWLEN ('b0), - .SAXIHP2AWLOCK ('b0), - .SAXIHP2AWPROT ('b0), - .SAXIHP2AWQOS ('b0), - .SAXIHP2AWSIZE ('b0), - .SAXIHP2AWVALID ('b0), - .SAXIHP2BREADY ('b0), - .SAXIHP2RDISSUECAP1EN ('b0), - .SAXIHP2RREADY ('b0), - .SAXIHP2WDATA ('b0), - .SAXIHP2WID ('b0), - .SAXIHP2WLAST ('b0), - .SAXIHP2WRISSUECAP1EN ('b0), - .SAXIHP2WSTRB ('b0), - .SAXIHP2WVALID ('b0), - .SAXIHP3ACLK ('b0), - .SAXIHP3ARADDR ('b0), - .SAXIHP3ARBURST ('b0), - .SAXIHP3ARCACHE ('b0), - .SAXIHP3ARID ('b0), - .SAXIHP3ARLEN ('b0), - .SAXIHP3ARLOCK ('b0), - .SAXIHP3ARPROT ('b0), - .SAXIHP3ARQOS ('b0), - .SAXIHP3ARSIZE ('b0), - .SAXIHP3ARVALID ('b0), - .SAXIHP3AWADDR ('b0), - .SAXIHP3AWBURST ('b0), - .SAXIHP3AWCACHE ('b0), - .SAXIHP3AWID ('b0), - .SAXIHP3AWLEN ('b0), - .SAXIHP3AWLOCK ('b0), - .SAXIHP3AWPROT ('b0), - .SAXIHP3AWQOS ('b0), - .SAXIHP3AWSIZE ('b0), - .SAXIHP3AWVALID ('b0), - .SAXIHP3BREADY ('b0), - .SAXIHP3RDISSUECAP1EN ('b0), - .SAXIHP3RREADY ('b0), - .SAXIHP3WDATA ('b0), - .SAXIHP3WID ('b0), - .SAXIHP3WLAST ('b0), - .SAXIHP3WRISSUECAP1EN ('b0), - .SAXIHP3WSTRB ('b0), - .SAXIHP3WVALID ('b0) -); From e00d6000d77c6e6c08a0765a1fb04bed92b17866 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:02:33 -0800 Subject: [PATCH 165/174] Fix blinky.sh and blinky_sim.sh --- xc7/blinky.sh | 10 +-------- xc7/blinky.v | 6 ++---- xc7/blinky_sim.ys | 54 +++++++++++++++++++++++++++++++++++++++++++++++ xc7/blinky_tb.v | 25 ---------------------- xc7/blinky_tb.vhd | 25 ++++++++++++++++++++++ 5 files changed, 82 insertions(+), 38 deletions(-) create mode 100644 xc7/blinky_sim.ys delete mode 100644 xc7/blinky_tb.v create mode 100644 xc7/blinky_tb.vhd diff --git a/xc7/blinky.sh b/xc7/blinky.sh index 1ba77434..6bc68573 100755 --- a/xc7/blinky.sh +++ b/xc7/blinky.sh @@ -1,14 +1,6 @@ #!/bin/bash set -ex yosys blinky.ys -../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 150 +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 125 xdl -xdl2ncd blinky.xdl bitgen -w blinky.ncd -g UnconstrainedPins:Allow -trce blinky.ncd -v 10 -#netgen -ofmt verilog -w blinky.ncd blinky_chip.v -tm blinky -insert_glbl true -#iverilog -o blinky_tb blinky_chip.v blinky_tb.v -y/opt/Xilinx/14.7/ISE_DS/ISE/verilog/src/simprims/ -#vvp -N ./blinky_tb - -#xdl -xdl2ncd blinky.xdl -nopips blinky_map.ncd -#par -w blinky_map.ncd blinky_par.ncd blinky.pcf -#bitgen -w blinky_par.ncd -g UnconstrainedPins:Allow diff --git a/xc7/blinky.v b/xc7/blinky.v index ad8f1de7..10ec23a3 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -5,8 +5,6 @@ module blinky ( output led2, output led3 ); - //`include "ps7.vh" - BUFGCTRL clk_gb ( .I0(clki), .CE0(1'b1), @@ -19,7 +17,7 @@ module blinky ( ); localparam BITS = 4; - localparam LOG2DELAY = 23; + parameter LOG2DELAY = 23; reg [BITS+LOG2DELAY-1:0] counter = 0; reg [BITS-1:0] outcnt; @@ -29,5 +27,5 @@ module blinky ( outcnt <= counter >> LOG2DELAY; end - assign {led0, led1, led2, led3} = outcnt /*^ (outcnt >> 1)*/; + assign {led0, led1, led2, led3} = outcnt ^ (outcnt >> 1); endmodule diff --git a/xc7/blinky_sim.ys b/xc7/blinky_sim.ys new file mode 100644 index 00000000..732e1e31 --- /dev/null +++ b/xc7/blinky_sim.ys @@ -0,0 +1,54 @@ +read_verilog blinky.v +chparam -set LOG2DELAY 0 + +#synth_xilinx -top blinky + +#begin: + read_verilog -lib +/xilinx/cells_sim.v + read_verilog -lib +/xilinx/cells_xtra.v +# read_verilog -lib +/xilinx/brams_bb.v +# read_verilog -lib +/xilinx/drams_bb.v + hierarchy -check -top blinky + +#flatten: (only if -flatten) + proc + flatten + +#coarse: + synth -run coarse + +#bram: +# memory_bram -rules +/xilinx/brams.txt +# techmap -map +/xilinx/brams_map.v +# +#dram: +# memory_bram -rules +/xilinx/drams.txt +# techmap -map +/xilinx/drams_map.v + +fine: + opt -fast -full + memory_map + dffsr2dff +# dff2dffe + opt -full + techmap -map +/techmap.v #-map +/xilinx/arith_map.v + opt -fast + +map_luts: + abc -luts 2:2,3,6:5 #,10,20 [-dff] + clean + +map_cells: + techmap -map +/xilinx/cells_map.v + dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT + clean + +check: + hierarchy -check + stat + check -noinit + +#edif: (only if -edif) +# write_edif + +write_json blinky.json diff --git a/xc7/blinky_tb.v b/xc7/blinky_tb.v deleted file mode 100644 index 069dbe9c..00000000 --- a/xc7/blinky_tb.v +++ /dev/null @@ -1,25 +0,0 @@ -module blinky_tb; - reg clk; - always #5 clk = (clk === 1'b0); - - wire led0, led1, led2, led3; - - blinky uut ( - .\clki.PAD.PAD (clk), - .\led0.OUTBUF.OUT (led0), - .\led1.OUTBUF.OUT (led1), - .\led2.OUTBUF.OUT (led2), - .\led3.OUTBUF.OUT (led3) - ); - - initial begin - // $dumpfile("blinky_tb.vcd"); - // $dumpvars(0, blinky_tb); - $monitor(led0, led1, led2, led3); - //repeat (10) begin - // repeat (900000) @(posedge clk); - // $display(led0, led1, led2, led3); - //end - //$finish; - end -endmodule diff --git a/xc7/blinky_tb.vhd b/xc7/blinky_tb.vhd new file mode 100644 index 00000000..29b5030b --- /dev/null +++ b/xc7/blinky_tb.vhd @@ -0,0 +1,25 @@ +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; + +entity testbench is +end entity; +architecture rtl of testbench is + signal clk : STD_LOGIC; + signal led : STD_LOGIC_VECTOR(3 downto 0); +begin + process begin + clk <= '0'; + wait for 4 ns; + clk <= '1'; + wait for 4 ns; + end process; + + uut: entity work.name port map(clki_PAD_PAD => clk, led0_OUTBUF_OUT => led(0), led1_OUTBUF_OUT => led(1), led2_OUTBUF_OUT => led(2), led3_OUTBUF_OUT => led(3)); + +process +begin +report std_logic'image(led(3)) & std_logic'image(led(2)) & std_logic'image(led(1)) & std_logic'image(led(0)); +wait on led; +end process; + +end rtl; From 5cf0c559facae55da997afc23a287b586281d223 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:12:57 -0800 Subject: [PATCH 166/174] Remove files from tree --- xc7/125MHz_to_60MHz.v | 177 ------------------------------------------ xc7/attosoc.v | 127 ------------------------------ 2 files changed, 304 deletions(-) delete mode 100755 xc7/125MHz_to_60MHz.v delete mode 100644 xc7/attosoc.v diff --git a/xc7/125MHz_to_60MHz.v b/xc7/125MHz_to_60MHz.v deleted file mode 100755 index 72e474d8..00000000 --- a/xc7/125MHz_to_60MHz.v +++ /dev/null @@ -1,177 +0,0 @@ -// file: clk_wiz_v3_6.v -// -// (c) Copyright 2008 - 2011 Xilinx, Inc. All rights reserved. -// -// This file contains confidential and proprietary information -// of Xilinx, Inc. and is protected under U.S. and -// international copyright and other intellectual property -// laws. -// -// DISCLAIMER -// This disclaimer is not a license and does not grant any -// rights to the materials distributed herewith. Except as -// otherwise provided in a valid license issued to you by -// Xilinx, and to the maximum extent permitted by applicable -// law: (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND -// WITH ALL FAULTS, AND XILINX HEREBY DISCLAIMS ALL WARRANTIES -// AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY, INCLUDING -// BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON- -// INFRINGEMENT, OR FITNESS FOR ANY PARTICULAR PURPOSE; and -// (2) Xilinx shall not be liable (whether in contract or tort, -// including negligence, or under any other theory of -// liability) for any loss or damage of any kind or nature -// related to, arising under or in connection with these -// materials, including for any direct, or any indirect, -// special, incidental, or consequential loss or damage -// (including loss of data, profits, goodwill, or any type of -// loss or damage suffered as a result of any action brought -// by a third party) even if such damage or loss was -// reasonably foreseeable or Xilinx had been advised of the -// possibility of the same. -// -// CRITICAL APPLICATIONS -// Xilinx products are not designed or intended to be fail- -// safe, or for use in any application requiring fail-safe -// performance, such as life-support or safety devices or -// systems, Class III medical devices, nuclear facilities, -// applications related to the deployment of airbags, or any -// other applications that could lead to death, personal -// injury, or severe property or environmental damage -// (individually and collectively, "Critical -// Applications"). Customer assumes the sole risk and -// liability of any use of Xilinx products in Critical -// Applications, subject only to applicable laws and -// regulations governing limitations on product liability. -// -// THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS -// PART OF THIS FILE AT ALL TIMES. -// -//---------------------------------------------------------------------------- -// User entered comments -//---------------------------------------------------------------------------- -// None -// -//---------------------------------------------------------------------------- -// "Output Output Phase Duty Pk-to-Pk Phase" -// "Clock Freq (MHz) (degrees) Cycle (%) Jitter (ps) Error (ps)" -//---------------------------------------------------------------------------- -// CLK_OUT1____60.000______0.000______50.0______231.736____234.038 -// -//---------------------------------------------------------------------------- -// "Input Clock Freq (MHz) Input Jitter (UI)" -//---------------------------------------------------------------------------- -// __primary_________125.000____________0.010 - -`timescale 1ps/1ps - -(* CORE_GENERATION_INFO = "clk_wiz_v3_6,clk_wiz_v3_6,{component_name=clk_wiz_v3_6,use_phase_alignment=false,use_min_o_jitter=false,use_max_i_jitter=false,use_dyn_phase_shift=false,use_inclk_switchover=false,use_dyn_reconfig=false,feedback_source=FDBK_AUTO,primtype_sel=MMCM_ADV,num_out_clk=1,clkin1_period=8.000,clkin2_period=10.000,use_power_down=false,use_reset=false,use_locked=false,use_inclk_stopped=false,use_status=false,use_freeze=false,use_clk_valid=false,feedback_type=SINGLE,clock_mgr_type=MANUAL,manual_override=false}" *) -module clk_wiz_v3_6 - (// Clock in ports - input CLK_IN1, - // Clock out ports - output CLK_OUT1 - ); - - // Input buffering - //------------------------------------ - assign clkin1 = CLK_IN1; - - - // Clocking primitive - //------------------------------------ - // Instantiation of the MMCM primitive - // * Unused inputs are tied off - // * Unused outputs are labeled unused - wire [15:0] do_unused; - wire drdy_unused; - wire psdone_unused; - wire locked_unused; - wire clkfbout; - wire clkfboutb_unused; - wire clkout0b_unused; - wire clkout1_unused; - wire clkout1b_unused; - wire clkout2_unused; - wire clkout2b_unused; - wire clkout3_unused; - wire clkout3b_unused; - wire clkout4_unused; - wire clkout5_unused; - wire clkout6_unused; - wire clkfbstopped_unused; - wire clkinstopped_unused; - - MMCME2_ADV - #(.BANDWIDTH ("OPTIMIZED"), - .CLKOUT4_CASCADE ("FALSE"), - .COMPENSATION ("ZHOLD"), - .STARTUP_WAIT ("FALSE"), - .DIVCLK_DIVIDE (5), - .CLKFBOUT_MULT_F (40.500), - .CLKFBOUT_PHASE (0.000), - .CLKFBOUT_USE_FINE_PS ("FALSE"), - .CLKOUT0_DIVIDE_F (16.875), - .CLKOUT0_PHASE (0.000), - .CLKOUT0_DUTY_CYCLE (0.500), - .CLKOUT0_USE_FINE_PS ("FALSE"), - .CLKIN1_PERIOD (8.000), - .REF_JITTER1 (0.010)) - mmcm_adv_inst - // Output clocks - (.CLKFBOUT (clkfbout), - .CLKFBOUTB (clkfboutb_unused), - .CLKOUT0 (clkout0), - .CLKOUT0B (clkout0b_unused), - .CLKOUT1 (clkout1_unused), - .CLKOUT1B (clkout1b_unused), - .CLKOUT2 (clkout2_unused), - .CLKOUT2B (clkout2b_unused), - .CLKOUT3 (clkout3_unused), - .CLKOUT3B (clkout3b_unused), - .CLKOUT4 (clkout4_unused), - .CLKOUT5 (clkout5_unused), - .CLKOUT6 (clkout6_unused), - // Input clock control - .CLKFBIN (clkfbout), - .CLKIN1 (clkin1), - .CLKIN2 (1'b0), - // Tied to always select the primary input clock - .CLKINSEL (1'b1), - // Ports for dynamic reconfiguration - .DADDR (7'h0), - .DCLK (1'b0), - .DEN (1'b0), - .DI (16'h0), - .DO (do_unused), - .DRDY (drdy_unused), - .DWE (1'b0), - // Ports for dynamic phase shift - .PSCLK (1'b0), - .PSEN (1'b0), - .PSINCDEC (1'b0), - .PSDONE (psdone_unused), - // Other control and status signals - .LOCKED (locked_unused), - .CLKINSTOPPED (clkinstopped_unused), - .CLKFBSTOPPED (clkfbstopped_unused), - .PWRDWN (1'b0), - .RST (1'b0)); - - // Output buffering - //----------------------------------- - - //BUFG clkout1_buf - // (.O (CLK_OUT1), - // .I (clkout0)); - - // BUFG not currently supported - BUFGCTRL clkout1_buf ( - .I0(clkout0), - .CE0(1'b1), - .S0(1'b1), - .O(CLK_OUT1) - ); - - - -endmodule diff --git a/xc7/attosoc.v b/xc7/attosoc.v deleted file mode 100644 index 4921e298..00000000 --- a/xc7/attosoc.v +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ECP5 PicoRV32 demo - * - * Copyright (C) 2017 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. - * - */ - -`ifdef PICORV32_V -`error "attosoc.v must be read before picorv32.v!" -`endif - -`define PICORV32_REGS picosoc_regs - -module attosoc ( - input clk, - output reg [7:0] led -); - - reg [5:0] reset_cnt = 0; - wire resetn = &reset_cnt; - - always @(posedge clk) begin - reset_cnt <= reset_cnt + !resetn; - end - - parameter integer MEM_WORDS = 256; - parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000; // ROM at 0x0 - parameter integer ROM_BYTES = 256; - - reg [7:0] rom [0:ROM_BYTES-1]; - wire [31:0] rom_rdata = {rom[mem_addr+3], rom[mem_addr+2], rom[mem_addr+1], rom[mem_addr+0]}; - initial $readmemh("firmware.hex", rom); - - wire mem_valid; - wire mem_instr; - wire mem_ready; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [3:0] mem_wstrb; - wire [31:0] mem_rdata; - - wire rom_ready = mem_valid && mem_addr[31:24] == 8'h00; - - wire iomem_valid; - wire iomem_ready; - wire [31:0] iomem_addr; - wire [31:0] iomem_wdata; - wire [3:0] iomem_wstrb; - wire [31:0] iomem_rdata; - - assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01); - assign iomem_ready = 1'b1; - assign iomem_wstrb = mem_wstrb; - assign iomem_addr = mem_addr; - assign iomem_wdata = mem_wdata; - - wire [31:0] spimemio_cfgreg_do; - - - always @(posedge clk) - if (iomem_valid && iomem_wstrb[0]) - led <= iomem_wdata[7:0]; - - assign mem_ready = (iomem_valid && iomem_ready) || rom_ready; - - assign mem_rdata = rom_rdata; - - picorv32 #( - .STACKADDR(STACKADDR), - .PROGADDR_RESET(PROGADDR_RESET), - .PROGADDR_IRQ(32'h 0000_0000), - .BARREL_SHIFTER(0), - .COMPRESSED_ISA(0), - .ENABLE_MUL(0), - .ENABLE_DIV(0), - .ENABLE_IRQ(0), - .ENABLE_IRQ_QREGS(0) - ) cpu ( - .clk (clk ), - .resetn (resetn ), - .mem_valid (mem_valid ), - .mem_instr (mem_instr ), - .mem_ready (mem_ready ), - .mem_addr (mem_addr ), - .mem_wdata (mem_wdata ), - .mem_wstrb (mem_wstrb ), - .mem_rdata (mem_rdata ) - ); - - - -endmodule - -// Implementation note: -// Replace the following two modules with wrappers for your SRAM cells. - -module picosoc_regs ( - input clk, wen, - input [5:0] waddr, - input [5:0] raddr1, - input [5:0] raddr2, - input [31:0] wdata, - output [31:0] rdata1, - output [31:0] rdata2 -); - reg [31:0] regs [0:31]; - - always @(posedge clk) - if (wen) regs[waddr[4:0]] <= wdata; - - assign rdata1 = regs[raddr1[4:0]]; - assign rdata2 = regs[raddr2[4:0]]; -endmodule From ada90761140f409ead79b5539a6376b648f532d4 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:26:31 -0800 Subject: [PATCH 167/174] Remove stuff copied over from ice40 --- xc7/benchmark/.gitignore | 6 - xc7/benchmark/hx8kdemo.pcf | 40 - xc7/benchmark/hx8kdemo.v | 139 -- xc7/benchmark/picorv32.v | 2977 --------------------------------- xc7/benchmark/picosoc.v | 241 --- xc7/benchmark/report.ipynb | 91 - xc7/benchmark/simpleuart.v | 137 -- xc7/benchmark/spimemio.v | 579 ------- xc7/carry_tests/.gitignore | 4 - xc7/carry_tests/counter.v | 9 - xc7/carry_tests/counter_tb.v | 23 - xc7/carry_tests/test.pcf | 10 - xc7/carry_tests/test.sh | 9 - xc7/icebreaker.pcf | 14 - xc7/icebreaker.v | 31 - xc7/icebreaker.ys | 3 - xc7/pack_tests/.gitignore | 2 - xc7/pack_tests/ffmodes.v | 43 - xc7/pack_tests/locals.v | 27 - xc7/pack_tests/place_constr.v | 54 - xc7/pack_tests/test.pcf | 10 - xc7/pack_tests/test.sh | 16 - xc7/resource/chipdb.rc | 6 - xc7/resource/embed.cc | 30 - xc7/resource/resource.h | 5 - 25 files changed, 4506 deletions(-) delete mode 100644 xc7/benchmark/.gitignore delete mode 100644 xc7/benchmark/hx8kdemo.pcf delete mode 100644 xc7/benchmark/hx8kdemo.v delete mode 100644 xc7/benchmark/picorv32.v delete mode 100644 xc7/benchmark/picosoc.v delete mode 100644 xc7/benchmark/report.ipynb delete mode 100644 xc7/benchmark/simpleuart.v delete mode 100644 xc7/benchmark/spimemio.v delete mode 100644 xc7/carry_tests/.gitignore delete mode 100644 xc7/carry_tests/counter.v delete mode 100644 xc7/carry_tests/counter_tb.v delete mode 100644 xc7/carry_tests/test.pcf delete mode 100755 xc7/carry_tests/test.sh delete mode 100644 xc7/icebreaker.pcf delete mode 100644 xc7/icebreaker.v delete mode 100644 xc7/icebreaker.ys delete mode 100644 xc7/pack_tests/.gitignore delete mode 100644 xc7/pack_tests/ffmodes.v delete mode 100644 xc7/pack_tests/locals.v delete mode 100644 xc7/pack_tests/place_constr.v delete mode 100644 xc7/pack_tests/test.pcf delete mode 100755 xc7/pack_tests/test.sh delete mode 100644 xc7/resource/chipdb.rc delete mode 100644 xc7/resource/embed.cc delete mode 100644 xc7/resource/resource.h diff --git a/xc7/benchmark/.gitignore b/xc7/benchmark/.gitignore deleted file mode 100644 index 306b5c6e..00000000 --- a/xc7/benchmark/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -hx8kdemo.log -hx8kdemo.blif -hx8kdemo.json -hx8kdemo_[an][0-9].asc -hx8kdemo_[an][0-9].log -report_[an][0-9].txt diff --git a/xc7/benchmark/hx8kdemo.pcf b/xc7/benchmark/hx8kdemo.pcf deleted file mode 100644 index 418bae89..00000000 --- a/xc7/benchmark/hx8kdemo.pcf +++ /dev/null @@ -1,40 +0,0 @@ - -# Pinout for the iCE40-HX8K Breakout Board - -set_io clk J3 - -set_io flash_csb R12 -set_io flash_clk R11 -set_io flash_io0 P12 -set_io flash_io1 P11 - -# for QSPI mode the flash chip on the iCE40-HX8K Breakout Board -# must be replaced with one that supports QSPI and the IO2 and IO3 -# pins must be soldered to T9 and P8 (center on J3) -set_io flash_io2 T9 -set_io flash_io3 P8 - -set_io ser_tx B12 -set_io ser_rx B10 - -# left on J3 -set_io debug_ser_tx T1 -set_io debug_ser_rx R3 - -# right on J3 -set_io debug_flash_csb T15 -set_io debug_flash_clk R16 -set_io debug_flash_io0 N12 -set_io debug_flash_io1 P13 -set_io debug_flash_io2 T13 -set_io debug_flash_io3 T14 - -set_io leds[7] B5 # D9 -set_io leds[6] B4 # D8 -set_io leds[5] A2 # D7 -set_io leds[4] A1 # D6 -set_io leds[3] C5 # D5 -set_io leds[2] C4 # D4 -set_io leds[1] B3 # D3 -set_io leds[0] C3 # D2 - diff --git a/xc7/benchmark/hx8kdemo.v b/xc7/benchmark/hx8kdemo.v deleted file mode 100644 index 9b784f8f..00000000 --- a/xc7/benchmark/hx8kdemo.v +++ /dev/null @@ -1,139 +0,0 @@ -/* - * PicoSoC - A simple example SoC using PicoRV32 - * - * Copyright (C) 2017 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. - * - */ - -module hx8kdemo ( - input clk, - - output ser_tx, - input ser_rx, - - output [7:0] leds, - - output flash_csb, - output flash_clk, - inout flash_io0, - inout flash_io1, - inout flash_io2, - inout flash_io3, - - output debug_ser_tx, - output debug_ser_rx, - - output debug_flash_csb, - output debug_flash_clk, - output debug_flash_io0, - output debug_flash_io1, - output debug_flash_io2, - output debug_flash_io3 -); - reg [5:0] reset_cnt = 0; - wire resetn = &reset_cnt; - - always @(posedge clk) begin - reset_cnt <= reset_cnt + !resetn; - end - - wire flash_io0_oe, flash_io0_do, flash_io0_di; - wire flash_io1_oe, flash_io1_do, flash_io1_di; - wire flash_io2_oe, flash_io2_do, flash_io2_di; - wire flash_io3_oe, flash_io3_do, flash_io3_di; - - SB_IO #( - .PIN_TYPE(6'b 1010_01), - .PULLUP(1'b 0) - ) flash_io_buf [3:0] ( - .PACKAGE_PIN({flash_io3, flash_io2, flash_io1, flash_io0}), - .OUTPUT_ENABLE({flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}), - .D_OUT_0({flash_io3_do, flash_io2_do, flash_io1_do, flash_io0_do}), - .D_IN_0({flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}) - ); - - wire iomem_valid; - reg iomem_ready; - wire [3:0] iomem_wstrb; - wire [31:0] iomem_addr; - wire [31:0] iomem_wdata; - reg [31:0] iomem_rdata; - - reg [31:0] gpio; - assign leds = gpio; - - always @(posedge clk) begin - if (!resetn) begin - gpio <= 0; - end else begin - iomem_ready <= 0; - if (iomem_valid && !iomem_ready && iomem_addr[31:24] == 8'h 03) begin - iomem_ready <= 1; - iomem_rdata <= gpio; - if (iomem_wstrb[0]) gpio[ 7: 0] <= iomem_wdata[ 7: 0]; - if (iomem_wstrb[1]) gpio[15: 8] <= iomem_wdata[15: 8]; - if (iomem_wstrb[2]) gpio[23:16] <= iomem_wdata[23:16]; - if (iomem_wstrb[3]) gpio[31:24] <= iomem_wdata[31:24]; - end - end - end - - picosoc soc ( - .clk (clk ), - .resetn (resetn ), - - .ser_tx (ser_tx ), - .ser_rx (ser_rx ), - - .flash_csb (flash_csb ), - .flash_clk (flash_clk ), - - .flash_io0_oe (flash_io0_oe), - .flash_io1_oe (flash_io1_oe), - .flash_io2_oe (flash_io2_oe), - .flash_io3_oe (flash_io3_oe), - - .flash_io0_do (flash_io0_do), - .flash_io1_do (flash_io1_do), - .flash_io2_do (flash_io2_do), - .flash_io3_do (flash_io3_do), - - .flash_io0_di (flash_io0_di), - .flash_io1_di (flash_io1_di), - .flash_io2_di (flash_io2_di), - .flash_io3_di (flash_io3_di), - - .irq_5 (1'b0 ), - .irq_6 (1'b0 ), - .irq_7 (1'b0 ), - - .iomem_valid (iomem_valid ), - .iomem_ready (iomem_ready ), - .iomem_wstrb (iomem_wstrb ), - .iomem_addr (iomem_addr ), - .iomem_wdata (iomem_wdata ), - .iomem_rdata (iomem_rdata ) - ); - - assign debug_ser_tx = ser_tx; - assign debug_ser_rx = ser_rx; - - assign debug_flash_csb = flash_csb; - assign debug_flash_clk = flash_clk; - assign debug_flash_io0 = flash_io0_di; - assign debug_flash_io1 = flash_io1_di; - assign debug_flash_io2 = flash_io2_di; - assign debug_flash_io3 = flash_io3_di; -endmodule diff --git a/xc7/benchmark/picorv32.v b/xc7/benchmark/picorv32.v deleted file mode 100644 index af634b47..00000000 --- a/xc7/benchmark/picorv32.v +++ /dev/null @@ -1,2977 +0,0 @@ -/* - * PicoRV32 -- A Small RISC-V (RV32I) Processor Core - * - * Copyright (C) 2015 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. - * - */ - -`timescale 1 ns / 1 ps -// `default_nettype none -// `define DEBUGNETS -// `define DEBUGREGS -// `define DEBUGASM -// `define DEBUG - -`ifdef DEBUG - `define debug(debug_command) debug_command -`else - `define debug(debug_command) -`endif - -`ifdef FORMAL - `define FORMAL_KEEP (* keep *) - `define assert(assert_expr) assert(assert_expr) -`else - `ifdef DEBUGNETS - `define FORMAL_KEEP (* keep *) - `else - `define FORMAL_KEEP - `endif - `define assert(assert_expr) empty_statement -`endif - -// uncomment this for register file in extra module -// `define PICORV32_REGS picorv32_regs - -// this macro can be used to check if the verilog files in your -// design are read in the correct order. -`define PICORV32_V - - -/*************************************************************** - * picorv32 - ***************************************************************/ - -module picorv32 #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] LATCHED_MEM_RDATA = 0, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - input clk, resetn, - output reg trap, - - output reg mem_valid, - output reg mem_instr, - input mem_ready, - - output reg [31:0] mem_addr, - output reg [31:0] mem_wdata, - output reg [ 3:0] mem_wstrb, - input [31:0] mem_rdata, - - // Look-Ahead Interface - output mem_la_read, - output mem_la_write, - output [31:0] mem_la_addr, - output reg [31:0] mem_la_wdata, - output reg [ 3:0] mem_la_wstrb, - - // Pico Co-Processor Interface (PCPI) - output reg pcpi_valid, - output reg [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ Interface - input [31:0] irq, - output reg [31:0] eoi, - -`ifdef RISCV_FORMAL - output reg rvfi_valid, - output reg [63:0] rvfi_order, - output reg [31:0] rvfi_insn, - output reg rvfi_trap, - output reg rvfi_halt, - output reg rvfi_intr, - output reg [ 4:0] rvfi_rs1_addr, - output reg [ 4:0] rvfi_rs2_addr, - output reg [31:0] rvfi_rs1_rdata, - output reg [31:0] rvfi_rs2_rdata, - output reg [ 4:0] rvfi_rd_addr, - output reg [31:0] rvfi_rd_wdata, - output reg [31:0] rvfi_pc_rdata, - output reg [31:0] rvfi_pc_wdata, - output reg [31:0] rvfi_mem_addr, - output reg [ 3:0] rvfi_mem_rmask, - output reg [ 3:0] rvfi_mem_wmask, - output reg [31:0] rvfi_mem_rdata, - output reg [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output reg trace_valid, - output reg [35:0] trace_data -); - localparam integer irq_timer = 0; - localparam integer irq_ebreak = 1; - localparam integer irq_buserror = 2; - - localparam integer irqregs_offset = ENABLE_REGS_16_31 ? 32 : 16; - localparam integer regfile_size = (ENABLE_REGS_16_31 ? 32 : 16) + 4*ENABLE_IRQ*ENABLE_IRQ_QREGS; - localparam integer regindex_bits = (ENABLE_REGS_16_31 ? 5 : 4) + ENABLE_IRQ*ENABLE_IRQ_QREGS; - - localparam WITH_PCPI = ENABLE_PCPI || ENABLE_MUL || ENABLE_FAST_MUL || ENABLE_DIV; - - localparam [35:0] TRACE_BRANCH = {4'b 0001, 32'b 0}; - localparam [35:0] TRACE_ADDR = {4'b 0010, 32'b 0}; - localparam [35:0] TRACE_IRQ = {4'b 1000, 32'b 0}; - - reg [63:0] count_cycle, count_instr; - reg [31:0] reg_pc, reg_next_pc, reg_op1, reg_op2, reg_out; - reg [4:0] reg_sh; - - reg [31:0] next_insn_opcode; - reg [31:0] dbg_insn_opcode; - reg [31:0] dbg_insn_addr; - - wire dbg_mem_valid = mem_valid; - wire dbg_mem_instr = mem_instr; - wire dbg_mem_ready = mem_ready; - wire [31:0] dbg_mem_addr = mem_addr; - wire [31:0] dbg_mem_wdata = mem_wdata; - wire [ 3:0] dbg_mem_wstrb = mem_wstrb; - wire [31:0] dbg_mem_rdata = mem_rdata; - - assign pcpi_rs1 = reg_op1; - assign pcpi_rs2 = reg_op2; - - wire [31:0] next_pc; - - reg irq_delay; - reg irq_active; - reg [31:0] irq_mask; - reg [31:0] irq_pending; - reg [31:0] timer; - -`ifndef PICORV32_REGS - reg [31:0] cpuregs [0:regfile_size-1]; - - integer i; - initial begin - if (REGS_INIT_ZERO) begin - for (i = 0; i < regfile_size; i = i+1) - cpuregs[i] = 0; - end - end -`endif - - task empty_statement; - // This task is used by the `assert directive in non-formal mode to - // avoid empty statement (which are unsupported by plain Verilog syntax). - begin end - endtask - -`ifdef DEBUGREGS - wire [31:0] dbg_reg_x0 = 0; - wire [31:0] dbg_reg_x1 = cpuregs[1]; - wire [31:0] dbg_reg_x2 = cpuregs[2]; - wire [31:0] dbg_reg_x3 = cpuregs[3]; - wire [31:0] dbg_reg_x4 = cpuregs[4]; - wire [31:0] dbg_reg_x5 = cpuregs[5]; - wire [31:0] dbg_reg_x6 = cpuregs[6]; - wire [31:0] dbg_reg_x7 = cpuregs[7]; - wire [31:0] dbg_reg_x8 = cpuregs[8]; - wire [31:0] dbg_reg_x9 = cpuregs[9]; - wire [31:0] dbg_reg_x10 = cpuregs[10]; - wire [31:0] dbg_reg_x11 = cpuregs[11]; - wire [31:0] dbg_reg_x12 = cpuregs[12]; - wire [31:0] dbg_reg_x13 = cpuregs[13]; - wire [31:0] dbg_reg_x14 = cpuregs[14]; - wire [31:0] dbg_reg_x15 = cpuregs[15]; - wire [31:0] dbg_reg_x16 = cpuregs[16]; - wire [31:0] dbg_reg_x17 = cpuregs[17]; - wire [31:0] dbg_reg_x18 = cpuregs[18]; - wire [31:0] dbg_reg_x19 = cpuregs[19]; - wire [31:0] dbg_reg_x20 = cpuregs[20]; - wire [31:0] dbg_reg_x21 = cpuregs[21]; - wire [31:0] dbg_reg_x22 = cpuregs[22]; - wire [31:0] dbg_reg_x23 = cpuregs[23]; - wire [31:0] dbg_reg_x24 = cpuregs[24]; - wire [31:0] dbg_reg_x25 = cpuregs[25]; - wire [31:0] dbg_reg_x26 = cpuregs[26]; - wire [31:0] dbg_reg_x27 = cpuregs[27]; - wire [31:0] dbg_reg_x28 = cpuregs[28]; - wire [31:0] dbg_reg_x29 = cpuregs[29]; - wire [31:0] dbg_reg_x30 = cpuregs[30]; - wire [31:0] dbg_reg_x31 = cpuregs[31]; -`endif - - // Internal PCPI Cores - - wire pcpi_mul_wr; - wire [31:0] pcpi_mul_rd; - wire pcpi_mul_wait; - wire pcpi_mul_ready; - - wire pcpi_div_wr; - wire [31:0] pcpi_div_rd; - wire pcpi_div_wait; - wire pcpi_div_ready; - - reg pcpi_int_wr; - reg [31:0] pcpi_int_rd; - reg pcpi_int_wait; - reg pcpi_int_ready; - - generate if (ENABLE_FAST_MUL) begin - picorv32_pcpi_fast_mul pcpi_mul ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_mul_wr ), - .pcpi_rd (pcpi_mul_rd ), - .pcpi_wait (pcpi_mul_wait ), - .pcpi_ready(pcpi_mul_ready ) - ); - end else if (ENABLE_MUL) begin - picorv32_pcpi_mul pcpi_mul ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_mul_wr ), - .pcpi_rd (pcpi_mul_rd ), - .pcpi_wait (pcpi_mul_wait ), - .pcpi_ready(pcpi_mul_ready ) - ); - end else begin - assign pcpi_mul_wr = 0; - assign pcpi_mul_rd = 32'bx; - assign pcpi_mul_wait = 0; - assign pcpi_mul_ready = 0; - end endgenerate - - generate if (ENABLE_DIV) begin - picorv32_pcpi_div pcpi_div ( - .clk (clk ), - .resetn (resetn ), - .pcpi_valid(pcpi_valid ), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_div_wr ), - .pcpi_rd (pcpi_div_rd ), - .pcpi_wait (pcpi_div_wait ), - .pcpi_ready(pcpi_div_ready ) - ); - end else begin - assign pcpi_div_wr = 0; - assign pcpi_div_rd = 32'bx; - assign pcpi_div_wait = 0; - assign pcpi_div_ready = 0; - end endgenerate - - always @* begin - pcpi_int_wr = 0; - pcpi_int_rd = 32'bx; - pcpi_int_wait = |{ENABLE_PCPI && pcpi_wait, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_wait, ENABLE_DIV && pcpi_div_wait}; - pcpi_int_ready = |{ENABLE_PCPI && pcpi_ready, (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready, ENABLE_DIV && pcpi_div_ready}; - - (* parallel_case *) - case (1'b1) - ENABLE_PCPI && pcpi_ready: begin - pcpi_int_wr = ENABLE_PCPI ? pcpi_wr : 0; - pcpi_int_rd = ENABLE_PCPI ? pcpi_rd : 0; - end - (ENABLE_MUL || ENABLE_FAST_MUL) && pcpi_mul_ready: begin - pcpi_int_wr = pcpi_mul_wr; - pcpi_int_rd = pcpi_mul_rd; - end - ENABLE_DIV && pcpi_div_ready: begin - pcpi_int_wr = pcpi_div_wr; - pcpi_int_rd = pcpi_div_rd; - end - endcase - end - - - // Memory Interface - - reg [1:0] mem_state; - reg [1:0] mem_wordsize; - reg [31:0] mem_rdata_word; - reg [31:0] mem_rdata_q; - reg mem_do_prefetch; - reg mem_do_rinst; - reg mem_do_rdata; - reg mem_do_wdata; - - wire mem_xfer; - reg mem_la_secondword, mem_la_firstword_reg, last_mem_valid; - wire mem_la_firstword = COMPRESSED_ISA && (mem_do_prefetch || mem_do_rinst) && next_pc[1] && !mem_la_secondword; - wire mem_la_firstword_xfer = COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg); - - reg prefetched_high_word; - reg clear_prefetched_high_word; - reg [15:0] mem_16bit_buffer; - - wire [31:0] mem_rdata_latched_noshuffle; - wire [31:0] mem_rdata_latched; - - wire mem_la_use_prefetched_high_word = COMPRESSED_ISA && mem_la_firstword && prefetched_high_word && !clear_prefetched_high_word; - assign mem_xfer = (mem_valid && mem_ready) || (mem_la_use_prefetched_high_word && mem_do_rinst); - - wire mem_busy = |{mem_do_prefetch, mem_do_rinst, mem_do_rdata, mem_do_wdata}; - wire mem_done = resetn && ((mem_xfer && |mem_state && (mem_do_rinst || mem_do_rdata || mem_do_wdata)) || (&mem_state && mem_do_rinst)) && - (!mem_la_firstword || (~&mem_rdata_latched[1:0] && mem_xfer)); - - assign mem_la_write = resetn && !mem_state && mem_do_wdata; - assign mem_la_read = resetn && ((!mem_la_use_prefetched_high_word && !mem_state && (mem_do_rinst || mem_do_prefetch || mem_do_rdata)) || - (COMPRESSED_ISA && mem_xfer && (!last_mem_valid ? mem_la_firstword : mem_la_firstword_reg) && !mem_la_secondword && &mem_rdata_latched[1:0])); - assign mem_la_addr = (mem_do_prefetch || mem_do_rinst) ? {next_pc[31:2] + mem_la_firstword_xfer, 2'b00} : {reg_op1[31:2], 2'b00}; - - assign mem_rdata_latched_noshuffle = (mem_xfer || LATCHED_MEM_RDATA) ? mem_rdata : mem_rdata_q; - - assign mem_rdata_latched = COMPRESSED_ISA && mem_la_use_prefetched_high_word ? {16'bx, mem_16bit_buffer} : - COMPRESSED_ISA && mem_la_secondword ? {mem_rdata_latched_noshuffle[15:0], mem_16bit_buffer} : - COMPRESSED_ISA && mem_la_firstword ? {16'bx, mem_rdata_latched_noshuffle[31:16]} : mem_rdata_latched_noshuffle; - - always @(posedge clk) begin - if (!resetn) begin - mem_la_firstword_reg <= 0; - last_mem_valid <= 0; - end else begin - if (!last_mem_valid) - mem_la_firstword_reg <= mem_la_firstword; - last_mem_valid <= mem_valid && !mem_ready; - end - end - - always @* begin - (* full_case *) - case (mem_wordsize) - 0: begin - mem_la_wdata = reg_op2; - mem_la_wstrb = 4'b1111; - mem_rdata_word = mem_rdata; - end - 1: begin - mem_la_wdata = {2{reg_op2[15:0]}}; - mem_la_wstrb = reg_op1[1] ? 4'b1100 : 4'b0011; - case (reg_op1[1]) - 1'b0: mem_rdata_word = {16'b0, mem_rdata[15: 0]}; - 1'b1: mem_rdata_word = {16'b0, mem_rdata[31:16]}; - endcase - end - 2: begin - mem_la_wdata = {4{reg_op2[7:0]}}; - mem_la_wstrb = 4'b0001 << reg_op1[1:0]; - case (reg_op1[1:0]) - 2'b00: mem_rdata_word = {24'b0, mem_rdata[ 7: 0]}; - 2'b01: mem_rdata_word = {24'b0, mem_rdata[15: 8]}; - 2'b10: mem_rdata_word = {24'b0, mem_rdata[23:16]}; - 2'b11: mem_rdata_word = {24'b0, mem_rdata[31:24]}; - endcase - end - endcase - end - - always @(posedge clk) begin - if (mem_xfer) begin - mem_rdata_q <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; - next_insn_opcode <= COMPRESSED_ISA ? mem_rdata_latched : mem_rdata; - end - - if (COMPRESSED_ISA && mem_done && (mem_do_prefetch || mem_do_rinst)) begin - case (mem_rdata_latched[1:0]) - 2'b00: begin // Quadrant 0 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.ADDI4SPN - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= {2'b0, mem_rdata_latched[10:7], mem_rdata_latched[12:11], mem_rdata_latched[5], mem_rdata_latched[6], 2'b00}; - end - 3'b010: begin // C.LW - mem_rdata_q[31:20] <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - 3'b 110: begin // C.SW - {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {5'b0, mem_rdata_latched[5], mem_rdata_latched[12:10], mem_rdata_latched[6], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - endcase - end - 2'b01: begin // Quadrant 1 - case (mem_rdata_latched[15:13]) - 3'b 000: begin // C.ADDI - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - 3'b 010: begin // C.LI - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - 3'b 011: begin - if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[4:3], - mem_rdata_latched[5], mem_rdata_latched[2], mem_rdata_latched[6], 4'b 0000}); - end else begin // C.LUI - mem_rdata_q[31:12] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - end - 3'b100: begin - if (mem_rdata_latched[11:10] == 2'b00) begin // C.SRLI - mem_rdata_q[31:25] <= 7'b0000000; - mem_rdata_q[14:12] <= 3'b 101; - end - if (mem_rdata_latched[11:10] == 2'b01) begin // C.SRAI - mem_rdata_q[31:25] <= 7'b0100000; - mem_rdata_q[14:12] <= 3'b 101; - end - if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI - mem_rdata_q[14:12] <= 3'b111; - mem_rdata_q[31:20] <= $signed({mem_rdata_latched[12], mem_rdata_latched[6:2]}); - end - if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND - if (mem_rdata_latched[6:5] == 2'b00) mem_rdata_q[14:12] <= 3'b000; - if (mem_rdata_latched[6:5] == 2'b01) mem_rdata_q[14:12] <= 3'b100; - if (mem_rdata_latched[6:5] == 2'b10) mem_rdata_q[14:12] <= 3'b110; - if (mem_rdata_latched[6:5] == 2'b11) mem_rdata_q[14:12] <= 3'b111; - mem_rdata_q[31:25] <= mem_rdata_latched[6:5] == 2'b00 ? 7'b0100000 : 7'b0000000; - end - end - 3'b 110: begin // C.BEQZ - mem_rdata_q[14:12] <= 3'b000; - { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= - $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], - mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); - end - 3'b 111: begin // C.BNEZ - mem_rdata_q[14:12] <= 3'b001; - { mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8] } <= - $signed({mem_rdata_latched[12], mem_rdata_latched[6:5], mem_rdata_latched[2], - mem_rdata_latched[11:10], mem_rdata_latched[4:3]}); - end - endcase - end - 2'b10: begin // Quadrant 2 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.SLLI - mem_rdata_q[31:25] <= 7'b0000000; - mem_rdata_q[14:12] <= 3'b 001; - end - 3'b010: begin // C.LWSP - mem_rdata_q[31:20] <= {4'b0, mem_rdata_latched[3:2], mem_rdata_latched[12], mem_rdata_latched[6:4], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - 3'b100: begin - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] == 0) begin // C.JR - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= 12'b0; - end - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:25] <= 7'b0000000; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:20] <= 12'b0; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD - mem_rdata_q[14:12] <= 3'b000; - mem_rdata_q[31:25] <= 7'b0000000; - end - end - 3'b110: begin // C.SWSP - {mem_rdata_q[31:25], mem_rdata_q[11:7]} <= {4'b0, mem_rdata_latched[8:7], mem_rdata_latched[12:9], 2'b00}; - mem_rdata_q[14:12] <= 3'b 010; - end - endcase - end - endcase - end - end - - always @(posedge clk) begin - if (resetn && !trap) begin - if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) - `assert(!mem_do_wdata); - - if (mem_do_prefetch || mem_do_rinst) - `assert(!mem_do_rdata); - - if (mem_do_rdata) - `assert(!mem_do_prefetch && !mem_do_rinst); - - if (mem_do_wdata) - `assert(!(mem_do_prefetch || mem_do_rinst || mem_do_rdata)); - - if (mem_state == 2 || mem_state == 3) - `assert(mem_valid || mem_do_prefetch); - end - end - - always @(posedge clk) begin - if (!resetn || trap) begin - if (!resetn) - mem_state <= 0; - if (!resetn || mem_ready) - mem_valid <= 0; - mem_la_secondword <= 0; - prefetched_high_word <= 0; - end else begin - if (mem_la_read || mem_la_write) begin - mem_addr <= mem_la_addr; - mem_wstrb <= mem_la_wstrb & {4{mem_la_write}}; - end - if (mem_la_write) begin - mem_wdata <= mem_la_wdata; - end - case (mem_state) - 0: begin - if (mem_do_prefetch || mem_do_rinst || mem_do_rdata) begin - mem_valid <= !mem_la_use_prefetched_high_word; - mem_instr <= mem_do_prefetch || mem_do_rinst; - mem_wstrb <= 0; - mem_state <= 1; - end - if (mem_do_wdata) begin - mem_valid <= 1; - mem_instr <= 0; - mem_state <= 2; - end - end - 1: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch || mem_do_rinst || mem_do_rdata); - `assert(mem_valid == !mem_la_use_prefetched_high_word); - `assert(mem_instr == (mem_do_prefetch || mem_do_rinst)); - if (mem_xfer) begin - if (COMPRESSED_ISA && mem_la_read) begin - mem_valid <= 1; - mem_la_secondword <= 1; - if (!mem_la_use_prefetched_high_word) - mem_16bit_buffer <= mem_rdata[31:16]; - end else begin - mem_valid <= 0; - mem_la_secondword <= 0; - if (COMPRESSED_ISA && !mem_do_rdata) begin - if (~&mem_rdata[1:0] || mem_la_secondword) begin - mem_16bit_buffer <= mem_rdata[31:16]; - prefetched_high_word <= 1; - end else begin - prefetched_high_word <= 0; - end - end - mem_state <= mem_do_rinst || mem_do_rdata ? 0 : 3; - end - end - end - 2: begin - `assert(mem_wstrb != 0); - `assert(mem_do_wdata); - if (mem_xfer) begin - mem_valid <= 0; - mem_state <= 0; - end - end - 3: begin - `assert(mem_wstrb == 0); - `assert(mem_do_prefetch); - if (mem_do_rinst) begin - mem_state <= 0; - end - end - endcase - end - - if (clear_prefetched_high_word) - prefetched_high_word <= 0; - end - - - // Instruction Decoder - - reg instr_lui, instr_auipc, instr_jal, instr_jalr; - reg instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu; - reg instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw; - reg instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai; - reg instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and; - reg instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, instr_ecall_ebreak; - reg instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer; - wire instr_trap; - - reg [regindex_bits-1:0] decoded_rd, decoded_rs1, decoded_rs2; - reg [31:0] decoded_imm, decoded_imm_uj; - reg decoder_trigger; - reg decoder_trigger_q; - reg decoder_pseudo_trigger; - reg decoder_pseudo_trigger_q; - reg compressed_instr; - - reg is_lui_auipc_jal; - reg is_lb_lh_lw_lbu_lhu; - reg is_slli_srli_srai; - reg is_jalr_addi_slti_sltiu_xori_ori_andi; - reg is_sb_sh_sw; - reg is_sll_srl_sra; - reg is_lui_auipc_jal_jalr_addi_add_sub; - reg is_slti_blt_slt; - reg is_sltiu_bltu_sltu; - reg is_beq_bne_blt_bge_bltu_bgeu; - reg is_lbu_lhu_lw; - reg is_alu_reg_imm; - reg is_alu_reg_reg; - reg is_compare; - - assign instr_trap = (CATCH_ILLINSN || WITH_PCPI) && !{instr_lui, instr_auipc, instr_jal, instr_jalr, - instr_beq, instr_bne, instr_blt, instr_bge, instr_bltu, instr_bgeu, - instr_lb, instr_lh, instr_lw, instr_lbu, instr_lhu, instr_sb, instr_sh, instr_sw, - instr_addi, instr_slti, instr_sltiu, instr_xori, instr_ori, instr_andi, instr_slli, instr_srli, instr_srai, - instr_add, instr_sub, instr_sll, instr_slt, instr_sltu, instr_xor, instr_srl, instr_sra, instr_or, instr_and, - instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh, - instr_getq, instr_setq, instr_retirq, instr_maskirq, instr_waitirq, instr_timer}; - - wire is_rdcycle_rdcycleh_rdinstr_rdinstrh; - assign is_rdcycle_rdcycleh_rdinstr_rdinstrh = |{instr_rdcycle, instr_rdcycleh, instr_rdinstr, instr_rdinstrh}; - - reg [63:0] new_ascii_instr; - `FORMAL_KEEP reg [63:0] dbg_ascii_instr; - `FORMAL_KEEP reg [31:0] dbg_insn_imm; - `FORMAL_KEEP reg [4:0] dbg_insn_rs1; - `FORMAL_KEEP reg [4:0] dbg_insn_rs2; - `FORMAL_KEEP reg [4:0] dbg_insn_rd; - `FORMAL_KEEP reg [31:0] dbg_rs1val; - `FORMAL_KEEP reg [31:0] dbg_rs2val; - `FORMAL_KEEP reg dbg_rs1val_valid; - `FORMAL_KEEP reg dbg_rs2val_valid; - - always @* begin - new_ascii_instr = ""; - - if (instr_lui) new_ascii_instr = "lui"; - if (instr_auipc) new_ascii_instr = "auipc"; - if (instr_jal) new_ascii_instr = "jal"; - if (instr_jalr) new_ascii_instr = "jalr"; - - if (instr_beq) new_ascii_instr = "beq"; - if (instr_bne) new_ascii_instr = "bne"; - if (instr_blt) new_ascii_instr = "blt"; - if (instr_bge) new_ascii_instr = "bge"; - if (instr_bltu) new_ascii_instr = "bltu"; - if (instr_bgeu) new_ascii_instr = "bgeu"; - - if (instr_lb) new_ascii_instr = "lb"; - if (instr_lh) new_ascii_instr = "lh"; - if (instr_lw) new_ascii_instr = "lw"; - if (instr_lbu) new_ascii_instr = "lbu"; - if (instr_lhu) new_ascii_instr = "lhu"; - if (instr_sb) new_ascii_instr = "sb"; - if (instr_sh) new_ascii_instr = "sh"; - if (instr_sw) new_ascii_instr = "sw"; - - if (instr_addi) new_ascii_instr = "addi"; - if (instr_slti) new_ascii_instr = "slti"; - if (instr_sltiu) new_ascii_instr = "sltiu"; - if (instr_xori) new_ascii_instr = "xori"; - if (instr_ori) new_ascii_instr = "ori"; - if (instr_andi) new_ascii_instr = "andi"; - if (instr_slli) new_ascii_instr = "slli"; - if (instr_srli) new_ascii_instr = "srli"; - if (instr_srai) new_ascii_instr = "srai"; - - if (instr_add) new_ascii_instr = "add"; - if (instr_sub) new_ascii_instr = "sub"; - if (instr_sll) new_ascii_instr = "sll"; - if (instr_slt) new_ascii_instr = "slt"; - if (instr_sltu) new_ascii_instr = "sltu"; - if (instr_xor) new_ascii_instr = "xor"; - if (instr_srl) new_ascii_instr = "srl"; - if (instr_sra) new_ascii_instr = "sra"; - if (instr_or) new_ascii_instr = "or"; - if (instr_and) new_ascii_instr = "and"; - - if (instr_rdcycle) new_ascii_instr = "rdcycle"; - if (instr_rdcycleh) new_ascii_instr = "rdcycleh"; - if (instr_rdinstr) new_ascii_instr = "rdinstr"; - if (instr_rdinstrh) new_ascii_instr = "rdinstrh"; - - if (instr_getq) new_ascii_instr = "getq"; - if (instr_setq) new_ascii_instr = "setq"; - if (instr_retirq) new_ascii_instr = "retirq"; - if (instr_maskirq) new_ascii_instr = "maskirq"; - if (instr_waitirq) new_ascii_instr = "waitirq"; - if (instr_timer) new_ascii_instr = "timer"; - end - - reg [63:0] q_ascii_instr; - reg [31:0] q_insn_imm; - reg [31:0] q_insn_opcode; - reg [4:0] q_insn_rs1; - reg [4:0] q_insn_rs2; - reg [4:0] q_insn_rd; - reg dbg_next; - - wire launch_next_insn; - reg dbg_valid_insn; - - reg [63:0] cached_ascii_instr; - reg [31:0] cached_insn_imm; - reg [31:0] cached_insn_opcode; - reg [4:0] cached_insn_rs1; - reg [4:0] cached_insn_rs2; - reg [4:0] cached_insn_rd; - - always @(posedge clk) begin - q_ascii_instr <= dbg_ascii_instr; - q_insn_imm <= dbg_insn_imm; - q_insn_opcode <= dbg_insn_opcode; - q_insn_rs1 <= dbg_insn_rs1; - q_insn_rs2 <= dbg_insn_rs2; - q_insn_rd <= dbg_insn_rd; - dbg_next <= launch_next_insn; - - if (!resetn || trap) - dbg_valid_insn <= 0; - else if (launch_next_insn) - dbg_valid_insn <= 1; - - if (decoder_trigger_q) begin - cached_ascii_instr <= new_ascii_instr; - cached_insn_imm <= decoded_imm; - if (&next_insn_opcode[1:0]) - cached_insn_opcode <= next_insn_opcode; - else - cached_insn_opcode <= {16'b0, next_insn_opcode[15:0]}; - cached_insn_rs1 <= decoded_rs1; - cached_insn_rs2 <= decoded_rs2; - cached_insn_rd <= decoded_rd; - end - - if (launch_next_insn) begin - dbg_insn_addr <= next_pc; - end - end - - always @* begin - dbg_ascii_instr = q_ascii_instr; - dbg_insn_imm = q_insn_imm; - dbg_insn_opcode = q_insn_opcode; - dbg_insn_rs1 = q_insn_rs1; - dbg_insn_rs2 = q_insn_rs2; - dbg_insn_rd = q_insn_rd; - - if (dbg_next) begin - if (decoder_pseudo_trigger_q) begin - dbg_ascii_instr = cached_ascii_instr; - dbg_insn_imm = cached_insn_imm; - dbg_insn_opcode = cached_insn_opcode; - dbg_insn_rs1 = cached_insn_rs1; - dbg_insn_rs2 = cached_insn_rs2; - dbg_insn_rd = cached_insn_rd; - end else begin - dbg_ascii_instr = new_ascii_instr; - if (&next_insn_opcode[1:0]) - dbg_insn_opcode = next_insn_opcode; - else - dbg_insn_opcode = {16'b0, next_insn_opcode[15:0]}; - dbg_insn_imm = decoded_imm; - dbg_insn_rs1 = decoded_rs1; - dbg_insn_rs2 = decoded_rs2; - dbg_insn_rd = decoded_rd; - end - end - end - -`ifdef DEBUGASM - always @(posedge clk) begin - if (dbg_next) begin - $display("debugasm %x %x %s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "*"); - end - end -`endif - -`ifdef DEBUG - always @(posedge clk) begin - if (dbg_next) begin - if (&dbg_insn_opcode[1:0]) - $display("DECODE: 0x%08x 0x%08x %-0s", dbg_insn_addr, dbg_insn_opcode, dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); - else - $display("DECODE: 0x%08x 0x%04x %-0s", dbg_insn_addr, dbg_insn_opcode[15:0], dbg_ascii_instr ? dbg_ascii_instr : "UNKNOWN"); - end - end -`endif - - always @(posedge clk) begin - is_lui_auipc_jal <= |{instr_lui, instr_auipc, instr_jal}; - is_lui_auipc_jal_jalr_addi_add_sub <= |{instr_lui, instr_auipc, instr_jal, instr_jalr, instr_addi, instr_add, instr_sub}; - is_slti_blt_slt <= |{instr_slti, instr_blt, instr_slt}; - is_sltiu_bltu_sltu <= |{instr_sltiu, instr_bltu, instr_sltu}; - is_lbu_lhu_lw <= |{instr_lbu, instr_lhu, instr_lw}; - is_compare <= |{is_beq_bne_blt_bge_bltu_bgeu, instr_slti, instr_slt, instr_sltiu, instr_sltu}; - - if (mem_do_rinst && mem_done) begin - instr_lui <= mem_rdata_latched[6:0] == 7'b0110111; - instr_auipc <= mem_rdata_latched[6:0] == 7'b0010111; - instr_jal <= mem_rdata_latched[6:0] == 7'b1101111; - instr_jalr <= mem_rdata_latched[6:0] == 7'b1100111 && mem_rdata_latched[14:12] == 3'b000; - instr_retirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ; - instr_waitirq <= mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000100 && ENABLE_IRQ; - - is_beq_bne_blt_bge_bltu_bgeu <= mem_rdata_latched[6:0] == 7'b1100011; - is_lb_lh_lw_lbu_lhu <= mem_rdata_latched[6:0] == 7'b0000011; - is_sb_sh_sw <= mem_rdata_latched[6:0] == 7'b0100011; - is_alu_reg_imm <= mem_rdata_latched[6:0] == 7'b0010011; - is_alu_reg_reg <= mem_rdata_latched[6:0] == 7'b0110011; - - { decoded_imm_uj[31:20], decoded_imm_uj[10:1], decoded_imm_uj[11], decoded_imm_uj[19:12], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[31:12], 1'b0}); - - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[19:15]; - decoded_rs2 <= mem_rdata_latched[24:20]; - - if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS) - decoded_rs1[regindex_bits-1] <= 1; // instr_getq - - if (mem_rdata_latched[6:0] == 7'b0001011 && mem_rdata_latched[31:25] == 7'b0000010 && ENABLE_IRQ) - decoded_rs1 <= ENABLE_IRQ_QREGS ? irqregs_offset : 3; // instr_retirq - - compressed_instr <= 0; - if (COMPRESSED_ISA && mem_rdata_latched[1:0] != 2'b11) begin - compressed_instr <= 1; - decoded_rd <= 0; - decoded_rs1 <= 0; - decoded_rs2 <= 0; - - { decoded_imm_uj[31:11], decoded_imm_uj[4], decoded_imm_uj[9:8], decoded_imm_uj[10], decoded_imm_uj[6], - decoded_imm_uj[7], decoded_imm_uj[3:1], decoded_imm_uj[5], decoded_imm_uj[0] } <= $signed({mem_rdata_latched[12:2], 1'b0}); - - case (mem_rdata_latched[1:0]) - 2'b00: begin // Quadrant 0 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.ADDI4SPN - is_alu_reg_imm <= |mem_rdata_latched[12:5]; - decoded_rs1 <= 2; - decoded_rd <= 8 + mem_rdata_latched[4:2]; - end - 3'b010: begin // C.LW - is_lb_lh_lw_lbu_lhu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rd <= 8 + mem_rdata_latched[4:2]; - end - 3'b110: begin // C.SW - is_sb_sh_sw <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 8 + mem_rdata_latched[4:2]; - end - endcase - end - 2'b01: begin // Quadrant 1 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.NOP / C.ADDI - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - 3'b001: begin // C.JAL - instr_jal <= 1; - decoded_rd <= 1; - end - 3'b 010: begin // C.LI - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - end - 3'b 011: begin - if (mem_rdata_latched[12] || mem_rdata_latched[6:2]) begin - if (mem_rdata_latched[11:7] == 2) begin // C.ADDI16SP - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - end else begin // C.LUI - instr_lui <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - end - end - end - 3'b100: begin - if (!mem_rdata_latched[11] && !mem_rdata_latched[12]) begin // C.SRLI, C.SRAI - is_alu_reg_imm <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; - end - if (mem_rdata_latched[11:10] == 2'b10) begin // C.ANDI - is_alu_reg_imm <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - end - if (mem_rdata_latched[12:10] == 3'b011) begin // C.SUB, C.XOR, C.OR, C.AND - is_alu_reg_reg <= 1; - decoded_rd <= 8 + mem_rdata_latched[9:7]; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 8 + mem_rdata_latched[4:2]; - end - end - 3'b101: begin // C.J - instr_jal <= 1; - end - 3'b110: begin // C.BEQZ - is_beq_bne_blt_bge_bltu_bgeu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 0; - end - 3'b111: begin // C.BNEZ - is_beq_bne_blt_bge_bltu_bgeu <= 1; - decoded_rs1 <= 8 + mem_rdata_latched[9:7]; - decoded_rs2 <= 0; - end - endcase - end - 2'b10: begin // Quadrant 2 - case (mem_rdata_latched[15:13]) - 3'b000: begin // C.SLLI - if (!mem_rdata_latched[12]) begin - is_alu_reg_imm <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - decoded_rs2 <= {mem_rdata_latched[12], mem_rdata_latched[6:2]}; - end - end - 3'b010: begin // C.LWSP - if (mem_rdata_latched[11:7]) begin - is_lb_lh_lw_lbu_lhu <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 2; - end - end - 3'b100: begin - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JR - instr_jalr <= 1; - decoded_rd <= 0; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - if (mem_rdata_latched[12] == 0 && mem_rdata_latched[6:2] != 0) begin // C.MV - is_alu_reg_reg <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= 0; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[11:7] != 0 && mem_rdata_latched[6:2] == 0) begin // C.JALR - instr_jalr <= 1; - decoded_rd <= 1; - decoded_rs1 <= mem_rdata_latched[11:7]; - end - if (mem_rdata_latched[12] != 0 && mem_rdata_latched[6:2] != 0) begin // C.ADD - is_alu_reg_reg <= 1; - decoded_rd <= mem_rdata_latched[11:7]; - decoded_rs1 <= mem_rdata_latched[11:7]; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - end - 3'b110: begin // C.SWSP - is_sb_sh_sw <= 1; - decoded_rs1 <= 2; - decoded_rs2 <= mem_rdata_latched[6:2]; - end - endcase - end - endcase - end - end - - if (decoder_trigger && !decoder_pseudo_trigger) begin - pcpi_insn <= WITH_PCPI ? mem_rdata_q : 'bx; - - instr_beq <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b000; - instr_bne <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b001; - instr_blt <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b100; - instr_bge <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b101; - instr_bltu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b110; - instr_bgeu <= is_beq_bne_blt_bge_bltu_bgeu && mem_rdata_q[14:12] == 3'b111; - - instr_lb <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b000; - instr_lh <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b001; - instr_lw <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b010; - instr_lbu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b100; - instr_lhu <= is_lb_lh_lw_lbu_lhu && mem_rdata_q[14:12] == 3'b101; - - instr_sb <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b000; - instr_sh <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b001; - instr_sw <= is_sb_sh_sw && mem_rdata_q[14:12] == 3'b010; - - instr_addi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b000; - instr_slti <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b010; - instr_sltiu <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b011; - instr_xori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b100; - instr_ori <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b110; - instr_andi <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b111; - - instr_slli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; - instr_srli <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; - instr_srai <= is_alu_reg_imm && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; - - instr_add <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0000000; - instr_sub <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b000 && mem_rdata_q[31:25] == 7'b0100000; - instr_sll <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000; - instr_slt <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b010 && mem_rdata_q[31:25] == 7'b0000000; - instr_sltu <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b011 && mem_rdata_q[31:25] == 7'b0000000; - instr_xor <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b100 && mem_rdata_q[31:25] == 7'b0000000; - instr_srl <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000; - instr_sra <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000; - instr_or <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b110 && mem_rdata_q[31:25] == 7'b0000000; - instr_and <= is_alu_reg_reg && mem_rdata_q[14:12] == 3'b111 && mem_rdata_q[31:25] == 7'b0000000; - - instr_rdcycle <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000000000010) || - (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000000100000010)) && ENABLE_COUNTERS; - instr_rdcycleh <= ((mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000000000010) || - (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000000100000010)) && ENABLE_COUNTERS && ENABLE_COUNTERS64; - instr_rdinstr <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11000000001000000010) && ENABLE_COUNTERS; - instr_rdinstrh <= (mem_rdata_q[6:0] == 7'b1110011 && mem_rdata_q[31:12] == 'b11001000001000000010) && ENABLE_COUNTERS && ENABLE_COUNTERS64; - - instr_ecall_ebreak <= ((mem_rdata_q[6:0] == 7'b1110011 && !mem_rdata_q[31:21] && !mem_rdata_q[19:7]) || - (COMPRESSED_ISA && mem_rdata_q[15:0] == 16'h9002)); - - instr_getq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000000 && ENABLE_IRQ && ENABLE_IRQ_QREGS; - instr_setq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000001 && ENABLE_IRQ && ENABLE_IRQ_QREGS; - instr_maskirq <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000011 && ENABLE_IRQ; - instr_timer <= mem_rdata_q[6:0] == 7'b0001011 && mem_rdata_q[31:25] == 7'b0000101 && ENABLE_IRQ && ENABLE_IRQ_TIMER; - - is_slli_srli_srai <= is_alu_reg_imm && |{ - mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 - }; - - is_jalr_addi_slti_sltiu_xori_ori_andi <= instr_jalr || is_alu_reg_imm && |{ - mem_rdata_q[14:12] == 3'b000, - mem_rdata_q[14:12] == 3'b010, - mem_rdata_q[14:12] == 3'b011, - mem_rdata_q[14:12] == 3'b100, - mem_rdata_q[14:12] == 3'b110, - mem_rdata_q[14:12] == 3'b111 - }; - - is_sll_srl_sra <= is_alu_reg_reg && |{ - mem_rdata_q[14:12] == 3'b001 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0000000, - mem_rdata_q[14:12] == 3'b101 && mem_rdata_q[31:25] == 7'b0100000 - }; - - is_lui_auipc_jal_jalr_addi_add_sub <= 0; - is_compare <= 0; - - (* parallel_case *) - case (1'b1) - instr_jal: - decoded_imm <= decoded_imm_uj; - |{instr_lui, instr_auipc}: - decoded_imm <= mem_rdata_q[31:12] << 12; - |{instr_jalr, is_lb_lh_lw_lbu_lhu, is_alu_reg_imm}: - decoded_imm <= $signed(mem_rdata_q[31:20]); - is_beq_bne_blt_bge_bltu_bgeu: - decoded_imm <= $signed({mem_rdata_q[31], mem_rdata_q[7], mem_rdata_q[30:25], mem_rdata_q[11:8], 1'b0}); - is_sb_sh_sw: - decoded_imm <= $signed({mem_rdata_q[31:25], mem_rdata_q[11:7]}); - default: - decoded_imm <= 1'bx; - endcase - end - - if (!resetn) begin - is_beq_bne_blt_bge_bltu_bgeu <= 0; - is_compare <= 0; - - instr_beq <= 0; - instr_bne <= 0; - instr_blt <= 0; - instr_bge <= 0; - instr_bltu <= 0; - instr_bgeu <= 0; - - instr_addi <= 0; - instr_slti <= 0; - instr_sltiu <= 0; - instr_xori <= 0; - instr_ori <= 0; - instr_andi <= 0; - - instr_add <= 0; - instr_sub <= 0; - instr_sll <= 0; - instr_slt <= 0; - instr_sltu <= 0; - instr_xor <= 0; - instr_srl <= 0; - instr_sra <= 0; - instr_or <= 0; - instr_and <= 0; - end - end - - - // Main State Machine - - localparam cpu_state_trap = 8'b10000000; - localparam cpu_state_fetch = 8'b01000000; - localparam cpu_state_ld_rs1 = 8'b00100000; - localparam cpu_state_ld_rs2 = 8'b00010000; - localparam cpu_state_exec = 8'b00001000; - localparam cpu_state_shift = 8'b00000100; - localparam cpu_state_stmem = 8'b00000010; - localparam cpu_state_ldmem = 8'b00000001; - - reg [7:0] cpu_state; - reg [1:0] irq_state; - - `FORMAL_KEEP reg [127:0] dbg_ascii_state; - - always @* begin - dbg_ascii_state = ""; - if (cpu_state == cpu_state_trap) dbg_ascii_state = "trap"; - if (cpu_state == cpu_state_fetch) dbg_ascii_state = "fetch"; - if (cpu_state == cpu_state_ld_rs1) dbg_ascii_state = "ld_rs1"; - if (cpu_state == cpu_state_ld_rs2) dbg_ascii_state = "ld_rs2"; - if (cpu_state == cpu_state_exec) dbg_ascii_state = "exec"; - if (cpu_state == cpu_state_shift) dbg_ascii_state = "shift"; - if (cpu_state == cpu_state_stmem) dbg_ascii_state = "stmem"; - if (cpu_state == cpu_state_ldmem) dbg_ascii_state = "ldmem"; - end - - reg set_mem_do_rinst; - reg set_mem_do_rdata; - reg set_mem_do_wdata; - - reg latched_store; - reg latched_stalu; - reg latched_branch; - reg latched_compr; - reg latched_trace; - reg latched_is_lu; - reg latched_is_lh; - reg latched_is_lb; - reg [regindex_bits-1:0] latched_rd; - - reg [31:0] current_pc; - assign next_pc = latched_store && latched_branch ? reg_out & ~1 : reg_next_pc; - - reg [3:0] pcpi_timeout_counter; - reg pcpi_timeout; - - reg [31:0] next_irq_pending; - reg do_waitirq; - - reg [31:0] alu_out, alu_out_q; - reg alu_out_0, alu_out_0_q; - reg alu_wait, alu_wait_2; - - reg [31:0] alu_add_sub; - reg [31:0] alu_shl, alu_shr; - reg alu_eq, alu_ltu, alu_lts; - - generate if (TWO_CYCLE_ALU) begin - always @(posedge clk) begin - alu_add_sub <= instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; - alu_eq <= reg_op1 == reg_op2; - alu_lts <= $signed(reg_op1) < $signed(reg_op2); - alu_ltu <= reg_op1 < reg_op2; - alu_shl <= reg_op1 << reg_op2[4:0]; - alu_shr <= $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; - end - end else begin - always @* begin - alu_add_sub = instr_sub ? reg_op1 - reg_op2 : reg_op1 + reg_op2; - alu_eq = reg_op1 == reg_op2; - alu_lts = $signed(reg_op1) < $signed(reg_op2); - alu_ltu = reg_op1 < reg_op2; - alu_shl = reg_op1 << reg_op2[4:0]; - alu_shr = $signed({instr_sra || instr_srai ? reg_op1[31] : 1'b0, reg_op1}) >>> reg_op2[4:0]; - end - end endgenerate - - always @* begin - alu_out_0 = 'bx; - (* parallel_case, full_case *) - case (1'b1) - instr_beq: - alu_out_0 = alu_eq; - instr_bne: - alu_out_0 = !alu_eq; - instr_bge: - alu_out_0 = !alu_lts; - instr_bgeu: - alu_out_0 = !alu_ltu; - is_slti_blt_slt && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): - alu_out_0 = alu_lts; - is_sltiu_bltu_sltu && (!TWO_CYCLE_COMPARE || !{instr_beq,instr_bne,instr_bge,instr_bgeu}): - alu_out_0 = alu_ltu; - endcase - - alu_out = 'bx; - (* parallel_case, full_case *) - case (1'b1) - is_lui_auipc_jal_jalr_addi_add_sub: - alu_out = alu_add_sub; - is_compare: - alu_out = alu_out_0; - instr_xori || instr_xor: - alu_out = reg_op1 ^ reg_op2; - instr_ori || instr_or: - alu_out = reg_op1 | reg_op2; - instr_andi || instr_and: - alu_out = reg_op1 & reg_op2; - BARREL_SHIFTER && (instr_sll || instr_slli): - alu_out = alu_shl; - BARREL_SHIFTER && (instr_srl || instr_srli || instr_sra || instr_srai): - alu_out = alu_shr; - endcase - -`ifdef RISCV_FORMAL_BLACKBOX_ALU - alu_out_0 = $anyseq; - alu_out = $anyseq; -`endif - end - - reg clear_prefetched_high_word_q; - always @(posedge clk) clear_prefetched_high_word_q <= clear_prefetched_high_word; - - always @* begin - clear_prefetched_high_word = clear_prefetched_high_word_q; - if (!prefetched_high_word) - clear_prefetched_high_word = 0; - if (latched_branch || irq_state || !resetn) - clear_prefetched_high_word = COMPRESSED_ISA; - end - - reg cpuregs_write; - reg [31:0] cpuregs_wrdata; - reg [31:0] cpuregs_rs1; - reg [31:0] cpuregs_rs2; - reg [regindex_bits-1:0] decoded_rs; - - always @* begin - cpuregs_write = 0; - cpuregs_wrdata = 'bx; - - if (cpu_state == cpu_state_fetch) begin - (* parallel_case *) - case (1'b1) - latched_branch: begin - cpuregs_wrdata = reg_pc + (latched_compr ? 2 : 4); - cpuregs_write = 1; - end - latched_store && !latched_branch: begin - cpuregs_wrdata = latched_stalu ? alu_out_q : reg_out; - cpuregs_write = 1; - end - ENABLE_IRQ && irq_state[0]: begin - cpuregs_wrdata = reg_next_pc | latched_compr; - cpuregs_write = 1; - end - ENABLE_IRQ && irq_state[1]: begin - cpuregs_wrdata = irq_pending & ~irq_mask; - cpuregs_write = 1; - end - endcase - end - end - -`ifndef PICORV32_REGS - always @(posedge clk) begin - if (resetn && cpuregs_write && latched_rd) - cpuregs[latched_rd] <= cpuregs_wrdata; - end - - always @* begin - decoded_rs = 'bx; - if (ENABLE_REGS_DUALPORT) begin -`ifndef RISCV_FORMAL_BLACKBOX_REGS - cpuregs_rs1 = decoded_rs1 ? cpuregs[decoded_rs1] : 0; - cpuregs_rs2 = decoded_rs2 ? cpuregs[decoded_rs2] : 0; -`else - cpuregs_rs1 = decoded_rs1 ? $anyseq : 0; - cpuregs_rs2 = decoded_rs2 ? $anyseq : 0; -`endif - end else begin - decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; -`ifndef RISCV_FORMAL_BLACKBOX_REGS - cpuregs_rs1 = decoded_rs ? cpuregs[decoded_rs] : 0; -`else - cpuregs_rs1 = decoded_rs ? $anyseq : 0; -`endif - cpuregs_rs2 = cpuregs_rs1; - end - end -`else - wire[31:0] cpuregs_rdata1; - wire[31:0] cpuregs_rdata2; - - wire [5:0] cpuregs_waddr = latched_rd; - wire [5:0] cpuregs_raddr1 = ENABLE_REGS_DUALPORT ? decoded_rs1 : decoded_rs; - wire [5:0] cpuregs_raddr2 = ENABLE_REGS_DUALPORT ? decoded_rs2 : 0; - - `PICORV32_REGS cpuregs ( - .clk(clk), - .wen(resetn && cpuregs_write && latched_rd), - .waddr(cpuregs_waddr), - .raddr1(cpuregs_raddr1), - .raddr2(cpuregs_raddr2), - .wdata(cpuregs_wrdata), - .rdata1(cpuregs_rdata1), - .rdata2(cpuregs_rdata2) - ); - - always @* begin - decoded_rs = 'bx; - if (ENABLE_REGS_DUALPORT) begin - cpuregs_rs1 = decoded_rs1 ? cpuregs_rdata1 : 0; - cpuregs_rs2 = decoded_rs2 ? cpuregs_rdata2 : 0; - end else begin - decoded_rs = (cpu_state == cpu_state_ld_rs2) ? decoded_rs2 : decoded_rs1; - cpuregs_rs1 = decoded_rs ? cpuregs_rdata1 : 0; - cpuregs_rs2 = cpuregs_rs1; - end - end -`endif - - assign launch_next_insn = cpu_state == cpu_state_fetch && decoder_trigger && (!ENABLE_IRQ || irq_delay || irq_active || !(irq_pending & ~irq_mask)); - - always @(posedge clk) begin - trap <= 0; - reg_sh <= 'bx; - reg_out <= 'bx; - set_mem_do_rinst = 0; - set_mem_do_rdata = 0; - set_mem_do_wdata = 0; - - alu_out_0_q <= alu_out_0; - alu_out_q <= alu_out; - - alu_wait <= 0; - alu_wait_2 <= 0; - - if (launch_next_insn) begin - dbg_rs1val <= 'bx; - dbg_rs2val <= 'bx; - dbg_rs1val_valid <= 0; - dbg_rs2val_valid <= 0; - end - - if (WITH_PCPI && CATCH_ILLINSN) begin - if (resetn && pcpi_valid && !pcpi_int_wait) begin - if (pcpi_timeout_counter) - pcpi_timeout_counter <= pcpi_timeout_counter - 1; - end else - pcpi_timeout_counter <= ~0; - pcpi_timeout <= !pcpi_timeout_counter; - end - - if (ENABLE_COUNTERS) begin - count_cycle <= resetn ? count_cycle + 1 : 0; - if (!ENABLE_COUNTERS64) count_cycle[63:32] <= 0; - end else begin - count_cycle <= 'bx; - count_instr <= 'bx; - end - - next_irq_pending = ENABLE_IRQ ? irq_pending & LATCHED_IRQ : 'bx; - - if (ENABLE_IRQ && ENABLE_IRQ_TIMER && timer) begin - if (timer - 1 == 0) - next_irq_pending[irq_timer] = 1; - timer <= timer - 1; - end - - if (ENABLE_IRQ) begin - next_irq_pending = next_irq_pending | irq; - end - - decoder_trigger <= mem_do_rinst && mem_done; - decoder_trigger_q <= decoder_trigger; - decoder_pseudo_trigger <= 0; - decoder_pseudo_trigger_q <= decoder_pseudo_trigger; - do_waitirq <= 0; - - trace_valid <= 0; - - if (!ENABLE_TRACE) - trace_data <= 'bx; - - if (!resetn) begin - reg_pc <= PROGADDR_RESET; - reg_next_pc <= PROGADDR_RESET; - if (ENABLE_COUNTERS) - count_instr <= 0; - latched_store <= 0; - latched_stalu <= 0; - latched_branch <= 0; - latched_trace <= 0; - latched_is_lu <= 0; - latched_is_lh <= 0; - latched_is_lb <= 0; - pcpi_valid <= 0; - pcpi_timeout <= 0; - irq_active <= 0; - irq_delay <= 0; - irq_mask <= ~0; - next_irq_pending = 0; - irq_state <= 0; - eoi <= 0; - timer <= 0; - if (~STACKADDR) begin - latched_store <= 1; - latched_rd <= 2; - reg_out <= STACKADDR; - end - cpu_state <= cpu_state_fetch; - end else - (* parallel_case, full_case *) - case (cpu_state) - cpu_state_trap: begin - trap <= 1; - end - - cpu_state_fetch: begin - mem_do_rinst <= !decoder_trigger && !do_waitirq; - mem_wordsize <= 0; - - current_pc = reg_next_pc; - - (* parallel_case *) - case (1'b1) - latched_branch: begin - current_pc = latched_store ? (latched_stalu ? alu_out_q : reg_out) & ~1 : reg_next_pc; - `debug($display("ST_RD: %2d 0x%08x, BRANCH 0x%08x", latched_rd, reg_pc + (latched_compr ? 2 : 4), current_pc);) - end - latched_store && !latched_branch: begin - `debug($display("ST_RD: %2d 0x%08x", latched_rd, latched_stalu ? alu_out_q : reg_out);) - end - ENABLE_IRQ && irq_state[0]: begin - current_pc = PROGADDR_IRQ; - irq_active <= 1; - mem_do_rinst <= 1; - end - ENABLE_IRQ && irq_state[1]: begin - eoi <= irq_pending & ~irq_mask; - next_irq_pending = next_irq_pending & irq_mask; - end - endcase - - if (ENABLE_TRACE && latched_trace) begin - latched_trace <= 0; - trace_valid <= 1; - if (latched_branch) - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_BRANCH | (current_pc & 32'hfffffffe); - else - trace_data <= (irq_active ? TRACE_IRQ : 0) | (latched_stalu ? alu_out_q : reg_out); - end - - reg_pc <= current_pc; - reg_next_pc <= current_pc; - - latched_store <= 0; - latched_stalu <= 0; - latched_branch <= 0; - latched_is_lu <= 0; - latched_is_lh <= 0; - latched_is_lb <= 0; - latched_rd <= decoded_rd; - latched_compr <= compressed_instr; - - if (ENABLE_IRQ && ((decoder_trigger && !irq_active && !irq_delay && |(irq_pending & ~irq_mask)) || irq_state)) begin - irq_state <= - irq_state == 2'b00 ? 2'b01 : - irq_state == 2'b01 ? 2'b10 : 2'b00; - latched_compr <= latched_compr; - if (ENABLE_IRQ_QREGS) - latched_rd <= irqregs_offset | irq_state[0]; - else - latched_rd <= irq_state[0] ? 4 : 3; - end else - if (ENABLE_IRQ && (decoder_trigger || do_waitirq) && instr_waitirq) begin - if (irq_pending) begin - latched_store <= 1; - reg_out <= irq_pending; - reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); - mem_do_rinst <= 1; - end else - do_waitirq <= 1; - end else - if (decoder_trigger) begin - `debug($display("-- %-0t", $time);) - irq_delay <= irq_active; - reg_next_pc <= current_pc + (compressed_instr ? 2 : 4); - if (ENABLE_TRACE) - latched_trace <= 1; - if (ENABLE_COUNTERS) begin - count_instr <= count_instr + 1; - if (!ENABLE_COUNTERS64) count_instr[63:32] <= 0; - end - if (instr_jal) begin - mem_do_rinst <= 1; - reg_next_pc <= current_pc + decoded_imm_uj; - latched_branch <= 1; - end else begin - mem_do_rinst <= 0; - mem_do_prefetch <= !instr_jalr && !instr_retirq; - cpu_state <= cpu_state_ld_rs1; - end - end - end - - cpu_state_ld_rs1: begin - reg_op1 <= 'bx; - reg_op2 <= 'bx; - - (* parallel_case *) - case (1'b1) - (CATCH_ILLINSN || WITH_PCPI) && instr_trap: begin - if (WITH_PCPI) begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - if (ENABLE_REGS_DUALPORT) begin - pcpi_valid <= 1; - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - if (pcpi_int_ready) begin - mem_do_rinst <= 1; - pcpi_valid <= 0; - reg_out <= pcpi_int_rd; - latched_store <= pcpi_int_wr; - cpu_state <= cpu_state_fetch; - end else - if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin - pcpi_valid <= 0; - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end else begin - cpu_state <= cpu_state_ld_rs2; - end - end else begin - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end - ENABLE_COUNTERS && is_rdcycle_rdcycleh_rdinstr_rdinstrh: begin - (* parallel_case, full_case *) - case (1'b1) - instr_rdcycle: - reg_out <= count_cycle[31:0]; - instr_rdcycleh && ENABLE_COUNTERS64: - reg_out <= count_cycle[63:32]; - instr_rdinstr: - reg_out <= count_instr[31:0]; - instr_rdinstrh && ENABLE_COUNTERS64: - reg_out <= count_instr[63:32]; - endcase - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - is_lui_auipc_jal: begin - reg_op1 <= instr_lui ? 0 : reg_pc; - reg_op2 <= decoded_imm; - if (TWO_CYCLE_ALU) - alu_wait <= 1; - else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_getq: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && ENABLE_IRQ_QREGS && instr_setq: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - latched_rd <= latched_rd | irqregs_offset; - latched_store <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && instr_retirq: begin - eoi <= 0; - irq_active <= 0; - latched_branch <= 1; - latched_store <= 1; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_out <= CATCH_MISALIGN ? (cpuregs_rs1 & 32'h fffffffe) : cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && instr_maskirq: begin - latched_store <= 1; - reg_out <= irq_mask; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - irq_mask <= cpuregs_rs1 | MASKED_IRQ; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - ENABLE_IRQ && ENABLE_IRQ_TIMER && instr_timer: begin - latched_store <= 1; - reg_out <= timer; - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - timer <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_fetch; - end - is_lb_lh_lw_lbu_lhu && !instr_trap: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - cpu_state <= cpu_state_ldmem; - mem_do_rinst <= 1; - end - is_slli_srli_srai && !BARREL_SHIFTER: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - reg_sh <= decoded_rs2; - cpu_state <= cpu_state_shift; - end - is_jalr_addi_slti_sltiu_xori_ori_andi, is_slli_srli_srai && BARREL_SHIFTER: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - reg_op2 <= is_slli_srli_srai && BARREL_SHIFTER ? decoded_rs2 : decoded_imm; - if (TWO_CYCLE_ALU) - alu_wait <= 1; - else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - default: begin - `debug($display("LD_RS1: %2d 0x%08x", decoded_rs1, cpuregs_rs1);) - reg_op1 <= cpuregs_rs1; - dbg_rs1val <= cpuregs_rs1; - dbg_rs1val_valid <= 1; - if (ENABLE_REGS_DUALPORT) begin - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - (* parallel_case *) - case (1'b1) - is_sb_sh_sw: begin - cpu_state <= cpu_state_stmem; - mem_do_rinst <= 1; - end - is_sll_srl_sra && !BARREL_SHIFTER: begin - cpu_state <= cpu_state_shift; - end - default: begin - if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin - alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); - alu_wait <= 1; - end else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - endcase - end else - cpu_state <= cpu_state_ld_rs2; - end - endcase - end - - cpu_state_ld_rs2: begin - `debug($display("LD_RS2: %2d 0x%08x", decoded_rs2, cpuregs_rs2);) - reg_sh <= cpuregs_rs2; - reg_op2 <= cpuregs_rs2; - dbg_rs2val <= cpuregs_rs2; - dbg_rs2val_valid <= 1; - - (* parallel_case *) - case (1'b1) - WITH_PCPI && instr_trap: begin - pcpi_valid <= 1; - if (pcpi_int_ready) begin - mem_do_rinst <= 1; - pcpi_valid <= 0; - reg_out <= pcpi_int_rd; - latched_store <= pcpi_int_wr; - cpu_state <= cpu_state_fetch; - end else - if (CATCH_ILLINSN && (pcpi_timeout || instr_ecall_ebreak)) begin - pcpi_valid <= 0; - `debug($display("EBREAK OR UNSUPPORTED INSN AT 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_ebreak] && !irq_active) begin - next_irq_pending[irq_ebreak] = 1; - cpu_state <= cpu_state_fetch; - end else - cpu_state <= cpu_state_trap; - end - end - is_sb_sh_sw: begin - cpu_state <= cpu_state_stmem; - mem_do_rinst <= 1; - end - is_sll_srl_sra && !BARREL_SHIFTER: begin - cpu_state <= cpu_state_shift; - end - default: begin - if (TWO_CYCLE_ALU || (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu)) begin - alu_wait_2 <= TWO_CYCLE_ALU && (TWO_CYCLE_COMPARE && is_beq_bne_blt_bge_bltu_bgeu); - alu_wait <= 1; - end else - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_exec; - end - endcase - end - - cpu_state_exec: begin - reg_out <= reg_pc + decoded_imm; - if ((TWO_CYCLE_ALU || TWO_CYCLE_COMPARE) && (alu_wait || alu_wait_2)) begin - mem_do_rinst <= mem_do_prefetch && !alu_wait_2; - alu_wait <= alu_wait_2; - end else - if (is_beq_bne_blt_bge_bltu_bgeu) begin - latched_rd <= 0; - latched_store <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; - latched_branch <= TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0; - if (mem_done) - cpu_state <= cpu_state_fetch; - if (TWO_CYCLE_COMPARE ? alu_out_0_q : alu_out_0) begin - decoder_trigger <= 0; - set_mem_do_rinst = 1; - end - end else begin - latched_branch <= instr_jalr; - latched_store <= 1; - latched_stalu <= 1; - cpu_state <= cpu_state_fetch; - end - end - - cpu_state_shift: begin - latched_store <= 1; - if (reg_sh == 0) begin - reg_out <= reg_op1; - mem_do_rinst <= mem_do_prefetch; - cpu_state <= cpu_state_fetch; - end else if (TWO_STAGE_SHIFT && reg_sh >= 4) begin - (* parallel_case, full_case *) - case (1'b1) - instr_slli || instr_sll: reg_op1 <= reg_op1 << 4; - instr_srli || instr_srl: reg_op1 <= reg_op1 >> 4; - instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 4; - endcase - reg_sh <= reg_sh - 4; - end else begin - (* parallel_case, full_case *) - case (1'b1) - instr_slli || instr_sll: reg_op1 <= reg_op1 << 1; - instr_srli || instr_srl: reg_op1 <= reg_op1 >> 1; - instr_srai || instr_sra: reg_op1 <= $signed(reg_op1) >>> 1; - endcase - reg_sh <= reg_sh - 1; - end - end - - cpu_state_stmem: begin - if (ENABLE_TRACE) - reg_out <= reg_op2; - if (!mem_do_prefetch || mem_done) begin - if (!mem_do_wdata) begin - (* parallel_case, full_case *) - case (1'b1) - instr_sb: mem_wordsize <= 2; - instr_sh: mem_wordsize <= 1; - instr_sw: mem_wordsize <= 0; - endcase - if (ENABLE_TRACE) begin - trace_valid <= 1; - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); - end - reg_op1 <= reg_op1 + decoded_imm; - set_mem_do_wdata = 1; - end - if (!mem_do_prefetch && mem_done) begin - cpu_state <= cpu_state_fetch; - decoder_trigger <= 1; - decoder_pseudo_trigger <= 1; - end - end - end - - cpu_state_ldmem: begin - latched_store <= 1; - if (!mem_do_prefetch || mem_done) begin - if (!mem_do_rdata) begin - (* parallel_case, full_case *) - case (1'b1) - instr_lb || instr_lbu: mem_wordsize <= 2; - instr_lh || instr_lhu: mem_wordsize <= 1; - instr_lw: mem_wordsize <= 0; - endcase - latched_is_lu <= is_lbu_lhu_lw; - latched_is_lh <= instr_lh; - latched_is_lb <= instr_lb; - if (ENABLE_TRACE) begin - trace_valid <= 1; - trace_data <= (irq_active ? TRACE_IRQ : 0) | TRACE_ADDR | ((reg_op1 + decoded_imm) & 32'hffffffff); - end - reg_op1 <= reg_op1 + decoded_imm; - set_mem_do_rdata = 1; - end - if (!mem_do_prefetch && mem_done) begin - (* parallel_case, full_case *) - case (1'b1) - latched_is_lu: reg_out <= mem_rdata_word; - latched_is_lh: reg_out <= $signed(mem_rdata_word[15:0]); - latched_is_lb: reg_out <= $signed(mem_rdata_word[7:0]); - endcase - decoder_trigger <= 1; - decoder_pseudo_trigger <= 1; - cpu_state <= cpu_state_fetch; - end - end - end - endcase - - if (CATCH_MISALIGN && resetn && (mem_do_rdata || mem_do_wdata)) begin - if (mem_wordsize == 0 && reg_op1[1:0] != 0) begin - `debug($display("MISALIGNED WORD: 0x%08x", reg_op1);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - if (mem_wordsize == 1 && reg_op1[0] != 0) begin - `debug($display("MISALIGNED HALFWORD: 0x%08x", reg_op1);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - end - if (CATCH_MISALIGN && resetn && mem_do_rinst && (COMPRESSED_ISA ? reg_pc[0] : |reg_pc[1:0])) begin - `debug($display("MISALIGNED INSTRUCTION: 0x%08x", reg_pc);) - if (ENABLE_IRQ && !irq_mask[irq_buserror] && !irq_active) begin - next_irq_pending[irq_buserror] = 1; - end else - cpu_state <= cpu_state_trap; - end - if (!CATCH_ILLINSN && decoder_trigger_q && !decoder_pseudo_trigger_q && instr_ecall_ebreak) begin - cpu_state <= cpu_state_trap; - end - - if (!resetn || mem_done) begin - mem_do_prefetch <= 0; - mem_do_rinst <= 0; - mem_do_rdata <= 0; - mem_do_wdata <= 0; - end - - if (set_mem_do_rinst) - mem_do_rinst <= 1; - if (set_mem_do_rdata) - mem_do_rdata <= 1; - if (set_mem_do_wdata) - mem_do_wdata <= 1; - - irq_pending <= next_irq_pending & ~MASKED_IRQ; - - if (!CATCH_MISALIGN) begin - if (COMPRESSED_ISA) begin - reg_pc[0] <= 0; - reg_next_pc[0] <= 0; - end else begin - reg_pc[1:0] <= 0; - reg_next_pc[1:0] <= 0; - end - end - current_pc = 'bx; - end - -`ifdef RISCV_FORMAL - reg dbg_irq_call; - reg dbg_irq_enter; - reg [31:0] dbg_irq_ret; - always @(posedge clk) begin - rvfi_valid <= resetn && (launch_next_insn || trap) && dbg_valid_insn; - rvfi_order <= resetn ? rvfi_order + rvfi_valid : 0; - - rvfi_insn <= dbg_insn_opcode; - rvfi_rs1_addr <= dbg_rs1val_valid ? dbg_insn_rs1 : 0; - rvfi_rs2_addr <= dbg_rs2val_valid ? dbg_insn_rs2 : 0; - rvfi_pc_rdata <= dbg_insn_addr; - rvfi_rs1_rdata <= dbg_rs1val_valid ? dbg_rs1val : 0; - rvfi_rs2_rdata <= dbg_rs2val_valid ? dbg_rs2val : 0; - rvfi_trap <= trap; - rvfi_halt <= trap; - rvfi_intr <= dbg_irq_enter; - - if (!resetn) begin - dbg_irq_call <= 0; - dbg_irq_enter <= 0; - end else - if (rvfi_valid) begin - dbg_irq_call <= 0; - dbg_irq_enter <= dbg_irq_call; - end else - if (irq_state == 1) begin - dbg_irq_call <= 1; - dbg_irq_ret <= next_pc; - end - - if (!resetn) begin - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end else - if (cpuregs_write && !irq_state) begin - rvfi_rd_addr <= latched_rd; - rvfi_rd_wdata <= latched_rd ? cpuregs_wrdata : 0; - end else - if (rvfi_valid) begin - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end - - casez (dbg_insn_opcode) - 32'b 0000000_?????_000??_???_?????_0001011: begin // getq - rvfi_rs1_addr <= 0; - rvfi_rs1_rdata <= 0; - end - 32'b 0000001_?????_?????_???_000??_0001011: begin // setq - rvfi_rd_addr <= 0; - rvfi_rd_wdata <= 0; - end - 32'b 0000010_?????_00000_???_00000_0001011: begin // retirq - rvfi_rs1_addr <= 0; - rvfi_rs1_rdata <= 0; - end - endcase - - if (!dbg_irq_call) begin - if (dbg_mem_instr) begin - rvfi_mem_addr <= 0; - rvfi_mem_rmask <= 0; - rvfi_mem_wmask <= 0; - rvfi_mem_rdata <= 0; - rvfi_mem_wdata <= 0; - end else - if (dbg_mem_valid && dbg_mem_ready) begin - rvfi_mem_addr <= dbg_mem_addr; - rvfi_mem_rmask <= dbg_mem_wstrb ? 0 : ~0; - rvfi_mem_wmask <= dbg_mem_wstrb; - rvfi_mem_rdata <= dbg_mem_rdata; - rvfi_mem_wdata <= dbg_mem_wdata; - end - end - end - - always @* begin - rvfi_pc_wdata = dbg_irq_call ? dbg_irq_ret : dbg_insn_addr; - end -`endif - - // Formal Verification -`ifdef FORMAL - reg [3:0] last_mem_nowait; - always @(posedge clk) - last_mem_nowait <= {last_mem_nowait, mem_ready || !mem_valid}; - - // stall the memory interface for max 4 cycles - restrict property (|last_mem_nowait || mem_ready || !mem_valid); - - // resetn low in first cycle, after that resetn high - restrict property (resetn != $initstate); - - // this just makes it much easier to read traces. uncomment as needed. - // assume property (mem_valid || !mem_ready); - - reg ok; - always @* begin - if (resetn) begin - // instruction fetches are read-only - if (mem_valid && mem_instr) - assert (mem_wstrb == 0); - - // cpu_state must be valid - ok = 0; - if (cpu_state == cpu_state_trap) ok = 1; - if (cpu_state == cpu_state_fetch) ok = 1; - if (cpu_state == cpu_state_ld_rs1) ok = 1; - if (cpu_state == cpu_state_ld_rs2) ok = !ENABLE_REGS_DUALPORT; - if (cpu_state == cpu_state_exec) ok = 1; - if (cpu_state == cpu_state_shift) ok = 1; - if (cpu_state == cpu_state_stmem) ok = 1; - if (cpu_state == cpu_state_ldmem) ok = 1; - assert (ok); - end - end - - reg last_mem_la_read = 0; - reg last_mem_la_write = 0; - reg [31:0] last_mem_la_addr; - reg [31:0] last_mem_la_wdata; - reg [3:0] last_mem_la_wstrb = 0; - - always @(posedge clk) begin - last_mem_la_read <= mem_la_read; - last_mem_la_write <= mem_la_write; - last_mem_la_addr <= mem_la_addr; - last_mem_la_wdata <= mem_la_wdata; - last_mem_la_wstrb <= mem_la_wstrb; - - if (last_mem_la_read) begin - assert(mem_valid); - assert(mem_addr == last_mem_la_addr); - assert(mem_wstrb == 0); - end - if (last_mem_la_write) begin - assert(mem_valid); - assert(mem_addr == last_mem_la_addr); - assert(mem_wdata == last_mem_la_wdata); - assert(mem_wstrb == last_mem_la_wstrb); - end - if (mem_la_read || mem_la_write) begin - assert(!mem_valid || mem_ready); - end - end -`endif -endmodule - -// This is a simple example implementation of PICORV32_REGS. -// Use the PICORV32_REGS mechanism if you want to use custom -// memory resources to implement the processor register file. -// Note that your implementation must match the requirements of -// the PicoRV32 configuration. (e.g. QREGS, etc) -module picorv32_regs ( - input clk, wen, - input [5:0] waddr, - input [5:0] raddr1, - input [5:0] raddr2, - input [31:0] wdata, - output [31:0] rdata1, - output [31:0] rdata2 -); - reg [31:0] regs [0:30]; - - always @(posedge clk) - if (wen) regs[~waddr[4:0]] <= wdata; - - assign rdata1 = regs[~raddr1[4:0]]; - assign rdata2 = regs[~raddr2[4:0]]; -endmodule - - -/*************************************************************** - * picorv32_pcpi_mul - ***************************************************************/ - -module picorv32_pcpi_mul #( - parameter STEPS_AT_ONCE = 1, - parameter CARRY_CHAIN = 4 -) ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output reg pcpi_wr, - output reg [31:0] pcpi_rd, - output reg pcpi_wait, - output reg pcpi_ready -); - reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; - wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; - wire instr_rs2_signed = |{instr_mulh}; - - reg pcpi_wait_q; - wire mul_start = pcpi_wait && !pcpi_wait_q; - - always @(posedge clk) begin - instr_mul <= 0; - instr_mulh <= 0; - instr_mulhsu <= 0; - instr_mulhu <= 0; - - if (resetn && pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin - case (pcpi_insn[14:12]) - 3'b000: instr_mul <= 1; - 3'b001: instr_mulh <= 1; - 3'b010: instr_mulhsu <= 1; - 3'b011: instr_mulhu <= 1; - endcase - end - - pcpi_wait <= instr_any_mul; - pcpi_wait_q <= pcpi_wait; - end - - reg [63:0] rs1, rs2, rd, rdx; - reg [63:0] next_rs1, next_rs2, this_rs2; - reg [63:0] next_rd, next_rdx, next_rdt; - reg [6:0] mul_counter; - reg mul_waiting; - reg mul_finish; - integer i, j; - - // carry save accumulator - always @* begin - next_rd = rd; - next_rdx = rdx; - next_rs1 = rs1; - next_rs2 = rs2; - - for (i = 0; i < STEPS_AT_ONCE; i=i+1) begin - this_rs2 = next_rs1[0] ? next_rs2 : 0; - if (CARRY_CHAIN == 0) begin - next_rdt = next_rd ^ next_rdx ^ this_rs2; - next_rdx = ((next_rd & next_rdx) | (next_rd & this_rs2) | (next_rdx & this_rs2)) << 1; - next_rd = next_rdt; - end else begin - next_rdt = 0; - for (j = 0; j < 64; j = j + CARRY_CHAIN) - {next_rdt[j+CARRY_CHAIN-1], next_rd[j +: CARRY_CHAIN]} = - next_rd[j +: CARRY_CHAIN] + next_rdx[j +: CARRY_CHAIN] + this_rs2[j +: CARRY_CHAIN]; - next_rdx = next_rdt << 1; - end - next_rs1 = next_rs1 >> 1; - next_rs2 = next_rs2 << 1; - end - end - - always @(posedge clk) begin - mul_finish <= 0; - if (!resetn) begin - mul_waiting <= 1; - end else - if (mul_waiting) begin - if (instr_rs1_signed) - rs1 <= $signed(pcpi_rs1); - else - rs1 <= $unsigned(pcpi_rs1); - - if (instr_rs2_signed) - rs2 <= $signed(pcpi_rs2); - else - rs2 <= $unsigned(pcpi_rs2); - - rd <= 0; - rdx <= 0; - mul_counter <= (instr_any_mulh ? 63 - STEPS_AT_ONCE : 31 - STEPS_AT_ONCE); - mul_waiting <= !mul_start; - end else begin - rd <= next_rd; - rdx <= next_rdx; - rs1 <= next_rs1; - rs2 <= next_rs2; - - mul_counter <= mul_counter - STEPS_AT_ONCE; - if (mul_counter[6]) begin - mul_finish <= 1; - mul_waiting <= 1; - end - end - end - - always @(posedge clk) begin - pcpi_wr <= 0; - pcpi_ready <= 0; - if (mul_finish && resetn) begin - pcpi_wr <= 1; - pcpi_ready <= 1; - pcpi_rd <= instr_any_mulh ? rd >> 32 : rd; - end - end -endmodule - -module picorv32_pcpi_fast_mul #( - parameter EXTRA_MUL_FFS = 0, - parameter EXTRA_INSN_FFS = 0, - parameter MUL_CLKGATE = 0 -) ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output pcpi_wr, - output [31:0] pcpi_rd, - output pcpi_wait, - output pcpi_ready -); - reg instr_mul, instr_mulh, instr_mulhsu, instr_mulhu; - wire instr_any_mul = |{instr_mul, instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_any_mulh = |{instr_mulh, instr_mulhsu, instr_mulhu}; - wire instr_rs1_signed = |{instr_mulh, instr_mulhsu}; - wire instr_rs2_signed = |{instr_mulh}; - - reg shift_out; - reg [3:0] active; - reg [32:0] rs1, rs2, rs1_q, rs2_q; - reg [63:0] rd, rd_q; - - wire pcpi_insn_valid = pcpi_valid && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001; - reg pcpi_insn_valid_q; - - always @* begin - instr_mul = 0; - instr_mulh = 0; - instr_mulhsu = 0; - instr_mulhu = 0; - - if (resetn && (EXTRA_INSN_FFS ? pcpi_insn_valid_q : pcpi_insn_valid)) begin - case (pcpi_insn[14:12]) - 3'b000: instr_mul = 1; - 3'b001: instr_mulh = 1; - 3'b010: instr_mulhsu = 1; - 3'b011: instr_mulhu = 1; - endcase - end - end - - always @(posedge clk) begin - pcpi_insn_valid_q <= pcpi_insn_valid; - if (!MUL_CLKGATE || active[0]) begin - rs1_q <= rs1; - rs2_q <= rs2; - end - if (!MUL_CLKGATE || active[1]) begin - rd <= $signed(EXTRA_MUL_FFS ? rs1_q : rs1) * $signed(EXTRA_MUL_FFS ? rs2_q : rs2); - end - if (!MUL_CLKGATE || active[2]) begin - rd_q <= rd; - end - end - - always @(posedge clk) begin - if (instr_any_mul && !(EXTRA_MUL_FFS ? active[3:0] : active[1:0])) begin - if (instr_rs1_signed) - rs1 <= $signed(pcpi_rs1); - else - rs1 <= $unsigned(pcpi_rs1); - - if (instr_rs2_signed) - rs2 <= $signed(pcpi_rs2); - else - rs2 <= $unsigned(pcpi_rs2); - active[0] <= 1; - end else begin - active[0] <= 0; - end - - active[3:1] <= active; - shift_out <= instr_any_mulh; - - if (!resetn) - active <= 0; - end - - assign pcpi_wr = active[EXTRA_MUL_FFS ? 3 : 1]; - assign pcpi_wait = 0; - assign pcpi_ready = active[EXTRA_MUL_FFS ? 3 : 1]; -`ifdef RISCV_FORMAL_ALTOPS - assign pcpi_rd = - instr_mul ? (pcpi_rs1 + pcpi_rs2) ^ 32'h5876063e : - instr_mulh ? (pcpi_rs1 + pcpi_rs2) ^ 32'hf6583fb7 : - instr_mulhsu ? (pcpi_rs1 - pcpi_rs2) ^ 32'hecfbe137 : - instr_mulhu ? (pcpi_rs1 + pcpi_rs2) ^ 32'h949ce5e8 : 1'bx; -`else - assign pcpi_rd = shift_out ? (EXTRA_MUL_FFS ? rd_q : rd) >> 32 : (EXTRA_MUL_FFS ? rd_q : rd); -`endif -endmodule - - -/*************************************************************** - * picorv32_pcpi_div - ***************************************************************/ - -module picorv32_pcpi_div ( - input clk, resetn, - - input pcpi_valid, - input [31:0] pcpi_insn, - input [31:0] pcpi_rs1, - input [31:0] pcpi_rs2, - output reg pcpi_wr, - output reg [31:0] pcpi_rd, - output reg pcpi_wait, - output reg pcpi_ready -); - reg instr_div, instr_divu, instr_rem, instr_remu; - wire instr_any_div_rem = |{instr_div, instr_divu, instr_rem, instr_remu}; - - reg pcpi_wait_q; - wire start = pcpi_wait && !pcpi_wait_q; - - always @(posedge clk) begin - instr_div <= 0; - instr_divu <= 0; - instr_rem <= 0; - instr_remu <= 0; - - if (resetn && pcpi_valid && !pcpi_ready && pcpi_insn[6:0] == 7'b0110011 && pcpi_insn[31:25] == 7'b0000001) begin - case (pcpi_insn[14:12]) - 3'b100: instr_div <= 1; - 3'b101: instr_divu <= 1; - 3'b110: instr_rem <= 1; - 3'b111: instr_remu <= 1; - endcase - end - - pcpi_wait <= instr_any_div_rem && resetn; - pcpi_wait_q <= pcpi_wait && resetn; - end - - reg [31:0] dividend; - reg [62:0] divisor; - reg [31:0] quotient; - reg [31:0] quotient_msk; - reg running; - reg outsign; - - always @(posedge clk) begin - pcpi_ready <= 0; - pcpi_wr <= 0; - pcpi_rd <= 'bx; - - if (!resetn) begin - running <= 0; - end else - if (start) begin - running <= 1; - dividend <= (instr_div || instr_rem) && pcpi_rs1[31] ? -pcpi_rs1 : pcpi_rs1; - divisor <= ((instr_div || instr_rem) && pcpi_rs2[31] ? -pcpi_rs2 : pcpi_rs2) << 31; - outsign <= (instr_div && (pcpi_rs1[31] != pcpi_rs2[31]) && |pcpi_rs2) || (instr_rem && pcpi_rs1[31]); - quotient <= 0; - quotient_msk <= 1 << 31; - end else - if (!quotient_msk && running) begin - running <= 0; - pcpi_ready <= 1; - pcpi_wr <= 1; -`ifdef RISCV_FORMAL_ALTOPS - case (1) - instr_div: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h7f8529ec; - instr_divu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h10e8fd70; - instr_rem: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h8da68fa5; - instr_remu: pcpi_rd <= (pcpi_rs1 - pcpi_rs2) ^ 32'h3138d0e1; - endcase -`else - if (instr_div || instr_divu) - pcpi_rd <= outsign ? -quotient : quotient; - else - pcpi_rd <= outsign ? -dividend : dividend; -`endif - end else begin - if (divisor <= dividend) begin - dividend <= dividend - divisor; - quotient <= quotient | quotient_msk; - end - divisor <= divisor >> 1; -`ifdef RISCV_FORMAL_ALTOPS - quotient_msk <= quotient_msk >> 5; -`else - quotient_msk <= quotient_msk >> 1; -`endif - end - end -endmodule - - -/*************************************************************** - * picorv32_axi - ***************************************************************/ - -module picorv32_axi #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - input clk, resetn, - output trap, - - // AXI4-lite master memory interface - - output mem_axi_awvalid, - input mem_axi_awready, - output [31:0] mem_axi_awaddr, - output [ 2:0] mem_axi_awprot, - - output mem_axi_wvalid, - input mem_axi_wready, - output [31:0] mem_axi_wdata, - output [ 3:0] mem_axi_wstrb, - - input mem_axi_bvalid, - output mem_axi_bready, - - output mem_axi_arvalid, - input mem_axi_arready, - output [31:0] mem_axi_araddr, - output [ 2:0] mem_axi_arprot, - - input mem_axi_rvalid, - output mem_axi_rready, - input [31:0] mem_axi_rdata, - - // Pico Co-Processor Interface (PCPI) - output pcpi_valid, - output [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ interface - input [31:0] irq, - output [31:0] eoi, - -`ifdef RISCV_FORMAL - output rvfi_valid, - output [63:0] rvfi_order, - output [31:0] rvfi_insn, - output rvfi_trap, - output rvfi_halt, - output rvfi_intr, - output [ 4:0] rvfi_rs1_addr, - output [ 4:0] rvfi_rs2_addr, - output [31:0] rvfi_rs1_rdata, - output [31:0] rvfi_rs2_rdata, - output [ 4:0] rvfi_rd_addr, - output [31:0] rvfi_rd_wdata, - output [31:0] rvfi_pc_rdata, - output [31:0] rvfi_pc_wdata, - output [31:0] rvfi_mem_addr, - output [ 3:0] rvfi_mem_rmask, - output [ 3:0] rvfi_mem_wmask, - output [31:0] rvfi_mem_rdata, - output [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output trace_valid, - output [35:0] trace_data -); - wire mem_valid; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [ 3:0] mem_wstrb; - wire mem_instr; - wire mem_ready; - wire [31:0] mem_rdata; - - picorv32_axi_adapter axi_adapter ( - .clk (clk ), - .resetn (resetn ), - .mem_axi_awvalid(mem_axi_awvalid), - .mem_axi_awready(mem_axi_awready), - .mem_axi_awaddr (mem_axi_awaddr ), - .mem_axi_awprot (mem_axi_awprot ), - .mem_axi_wvalid (mem_axi_wvalid ), - .mem_axi_wready (mem_axi_wready ), - .mem_axi_wdata (mem_axi_wdata ), - .mem_axi_wstrb (mem_axi_wstrb ), - .mem_axi_bvalid (mem_axi_bvalid ), - .mem_axi_bready (mem_axi_bready ), - .mem_axi_arvalid(mem_axi_arvalid), - .mem_axi_arready(mem_axi_arready), - .mem_axi_araddr (mem_axi_araddr ), - .mem_axi_arprot (mem_axi_arprot ), - .mem_axi_rvalid (mem_axi_rvalid ), - .mem_axi_rready (mem_axi_rready ), - .mem_axi_rdata (mem_axi_rdata ), - .mem_valid (mem_valid ), - .mem_instr (mem_instr ), - .mem_ready (mem_ready ), - .mem_addr (mem_addr ), - .mem_wdata (mem_wdata ), - .mem_wstrb (mem_wstrb ), - .mem_rdata (mem_rdata ) - ); - - picorv32 #( - .ENABLE_COUNTERS (ENABLE_COUNTERS ), - .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), - .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), - .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), - .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), - .BARREL_SHIFTER (BARREL_SHIFTER ), - .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), - .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), - .COMPRESSED_ISA (COMPRESSED_ISA ), - .CATCH_MISALIGN (CATCH_MISALIGN ), - .CATCH_ILLINSN (CATCH_ILLINSN ), - .ENABLE_PCPI (ENABLE_PCPI ), - .ENABLE_MUL (ENABLE_MUL ), - .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), - .ENABLE_DIV (ENABLE_DIV ), - .ENABLE_IRQ (ENABLE_IRQ ), - .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), - .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), - .ENABLE_TRACE (ENABLE_TRACE ), - .REGS_INIT_ZERO (REGS_INIT_ZERO ), - .MASKED_IRQ (MASKED_IRQ ), - .LATCHED_IRQ (LATCHED_IRQ ), - .PROGADDR_RESET (PROGADDR_RESET ), - .PROGADDR_IRQ (PROGADDR_IRQ ), - .STACKADDR (STACKADDR ) - ) picorv32_core ( - .clk (clk ), - .resetn (resetn), - .trap (trap ), - - .mem_valid(mem_valid), - .mem_addr (mem_addr ), - .mem_wdata(mem_wdata), - .mem_wstrb(mem_wstrb), - .mem_instr(mem_instr), - .mem_ready(mem_ready), - .mem_rdata(mem_rdata), - - .pcpi_valid(pcpi_valid), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_wr ), - .pcpi_rd (pcpi_rd ), - .pcpi_wait (pcpi_wait ), - .pcpi_ready(pcpi_ready), - - .irq(irq), - .eoi(eoi), - -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata(rvfi_rs1_rdata), - .rvfi_rs2_rdata(rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask(rvfi_mem_rmask), - .rvfi_mem_wmask(rvfi_mem_wmask), - .rvfi_mem_rdata(rvfi_mem_rdata), - .rvfi_mem_wdata(rvfi_mem_wdata), -`endif - - .trace_valid(trace_valid), - .trace_data (trace_data) - ); -endmodule - - -/*************************************************************** - * picorv32_axi_adapter - ***************************************************************/ - -module picorv32_axi_adapter ( - input clk, resetn, - - // AXI4-lite master memory interface - - output mem_axi_awvalid, - input mem_axi_awready, - output [31:0] mem_axi_awaddr, - output [ 2:0] mem_axi_awprot, - - output mem_axi_wvalid, - input mem_axi_wready, - output [31:0] mem_axi_wdata, - output [ 3:0] mem_axi_wstrb, - - input mem_axi_bvalid, - output mem_axi_bready, - - output mem_axi_arvalid, - input mem_axi_arready, - output [31:0] mem_axi_araddr, - output [ 2:0] mem_axi_arprot, - - input mem_axi_rvalid, - output mem_axi_rready, - input [31:0] mem_axi_rdata, - - // Native PicoRV32 memory interface - - input mem_valid, - input mem_instr, - output mem_ready, - input [31:0] mem_addr, - input [31:0] mem_wdata, - input [ 3:0] mem_wstrb, - output [31:0] mem_rdata -); - reg ack_awvalid; - reg ack_arvalid; - reg ack_wvalid; - reg xfer_done; - - assign mem_axi_awvalid = mem_valid && |mem_wstrb && !ack_awvalid; - assign mem_axi_awaddr = mem_addr; - assign mem_axi_awprot = 0; - - assign mem_axi_arvalid = mem_valid && !mem_wstrb && !ack_arvalid; - assign mem_axi_araddr = mem_addr; - assign mem_axi_arprot = mem_instr ? 3'b100 : 3'b000; - - assign mem_axi_wvalid = mem_valid && |mem_wstrb && !ack_wvalid; - assign mem_axi_wdata = mem_wdata; - assign mem_axi_wstrb = mem_wstrb; - - assign mem_ready = mem_axi_bvalid || mem_axi_rvalid; - assign mem_axi_bready = mem_valid && |mem_wstrb; - assign mem_axi_rready = mem_valid && !mem_wstrb; - assign mem_rdata = mem_axi_rdata; - - always @(posedge clk) begin - if (!resetn) begin - ack_awvalid <= 0; - end else begin - xfer_done <= mem_valid && mem_ready; - if (mem_axi_awready && mem_axi_awvalid) - ack_awvalid <= 1; - if (mem_axi_arready && mem_axi_arvalid) - ack_arvalid <= 1; - if (mem_axi_wready && mem_axi_wvalid) - ack_wvalid <= 1; - if (xfer_done || !mem_valid) begin - ack_awvalid <= 0; - ack_arvalid <= 0; - ack_wvalid <= 0; - end - end - end -endmodule - - -/*************************************************************** - * picorv32_wb - ***************************************************************/ - -module picorv32_wb #( - parameter [ 0:0] ENABLE_COUNTERS = 1, - parameter [ 0:0] ENABLE_COUNTERS64 = 1, - parameter [ 0:0] ENABLE_REGS_16_31 = 1, - parameter [ 0:0] ENABLE_REGS_DUALPORT = 1, - parameter [ 0:0] TWO_STAGE_SHIFT = 1, - parameter [ 0:0] BARREL_SHIFTER = 0, - parameter [ 0:0] TWO_CYCLE_COMPARE = 0, - parameter [ 0:0] TWO_CYCLE_ALU = 0, - parameter [ 0:0] COMPRESSED_ISA = 0, - parameter [ 0:0] CATCH_MISALIGN = 1, - parameter [ 0:0] CATCH_ILLINSN = 1, - parameter [ 0:0] ENABLE_PCPI = 0, - parameter [ 0:0] ENABLE_MUL = 0, - parameter [ 0:0] ENABLE_FAST_MUL = 0, - parameter [ 0:0] ENABLE_DIV = 0, - parameter [ 0:0] ENABLE_IRQ = 0, - parameter [ 0:0] ENABLE_IRQ_QREGS = 1, - parameter [ 0:0] ENABLE_IRQ_TIMER = 1, - parameter [ 0:0] ENABLE_TRACE = 0, - parameter [ 0:0] REGS_INIT_ZERO = 0, - parameter [31:0] MASKED_IRQ = 32'h 0000_0000, - parameter [31:0] LATCHED_IRQ = 32'h ffff_ffff, - parameter [31:0] PROGADDR_RESET = 32'h 0000_0000, - parameter [31:0] PROGADDR_IRQ = 32'h 0000_0010, - parameter [31:0] STACKADDR = 32'h ffff_ffff -) ( - output trap, - - // Wishbone interfaces - input wb_rst_i, - input wb_clk_i, - - output reg [31:0] wbm_adr_o, - output reg [31:0] wbm_dat_o, - input [31:0] wbm_dat_i, - output reg wbm_we_o, - output reg [3:0] wbm_sel_o, - output reg wbm_stb_o, - input wbm_ack_i, - output reg wbm_cyc_o, - - // Pico Co-Processor Interface (PCPI) - output pcpi_valid, - output [31:0] pcpi_insn, - output [31:0] pcpi_rs1, - output [31:0] pcpi_rs2, - input pcpi_wr, - input [31:0] pcpi_rd, - input pcpi_wait, - input pcpi_ready, - - // IRQ interface - input [31:0] irq, - output [31:0] eoi, - -`ifdef RISCV_FORMAL - output rvfi_valid, - output [63:0] rvfi_order, - output [31:0] rvfi_insn, - output rvfi_trap, - output rvfi_halt, - output rvfi_intr, - output [ 4:0] rvfi_rs1_addr, - output [ 4:0] rvfi_rs2_addr, - output [31:0] rvfi_rs1_rdata, - output [31:0] rvfi_rs2_rdata, - output [ 4:0] rvfi_rd_addr, - output [31:0] rvfi_rd_wdata, - output [31:0] rvfi_pc_rdata, - output [31:0] rvfi_pc_wdata, - output [31:0] rvfi_mem_addr, - output [ 3:0] rvfi_mem_rmask, - output [ 3:0] rvfi_mem_wmask, - output [31:0] rvfi_mem_rdata, - output [31:0] rvfi_mem_wdata, -`endif - - // Trace Interface - output trace_valid, - output [35:0] trace_data, - - output mem_instr -); - wire mem_valid; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [ 3:0] mem_wstrb; - reg mem_ready; - reg [31:0] mem_rdata; - - wire clk; - wire resetn; - - assign clk = wb_clk_i; - assign resetn = ~wb_rst_i; - - picorv32 #( - .ENABLE_COUNTERS (ENABLE_COUNTERS ), - .ENABLE_COUNTERS64 (ENABLE_COUNTERS64 ), - .ENABLE_REGS_16_31 (ENABLE_REGS_16_31 ), - .ENABLE_REGS_DUALPORT(ENABLE_REGS_DUALPORT), - .TWO_STAGE_SHIFT (TWO_STAGE_SHIFT ), - .BARREL_SHIFTER (BARREL_SHIFTER ), - .TWO_CYCLE_COMPARE (TWO_CYCLE_COMPARE ), - .TWO_CYCLE_ALU (TWO_CYCLE_ALU ), - .COMPRESSED_ISA (COMPRESSED_ISA ), - .CATCH_MISALIGN (CATCH_MISALIGN ), - .CATCH_ILLINSN (CATCH_ILLINSN ), - .ENABLE_PCPI (ENABLE_PCPI ), - .ENABLE_MUL (ENABLE_MUL ), - .ENABLE_FAST_MUL (ENABLE_FAST_MUL ), - .ENABLE_DIV (ENABLE_DIV ), - .ENABLE_IRQ (ENABLE_IRQ ), - .ENABLE_IRQ_QREGS (ENABLE_IRQ_QREGS ), - .ENABLE_IRQ_TIMER (ENABLE_IRQ_TIMER ), - .ENABLE_TRACE (ENABLE_TRACE ), - .REGS_INIT_ZERO (REGS_INIT_ZERO ), - .MASKED_IRQ (MASKED_IRQ ), - .LATCHED_IRQ (LATCHED_IRQ ), - .PROGADDR_RESET (PROGADDR_RESET ), - .PROGADDR_IRQ (PROGADDR_IRQ ), - .STACKADDR (STACKADDR ) - ) picorv32_core ( - .clk (clk ), - .resetn (resetn), - .trap (trap ), - - .mem_valid(mem_valid), - .mem_addr (mem_addr ), - .mem_wdata(mem_wdata), - .mem_wstrb(mem_wstrb), - .mem_instr(mem_instr), - .mem_ready(mem_ready), - .mem_rdata(mem_rdata), - - .pcpi_valid(pcpi_valid), - .pcpi_insn (pcpi_insn ), - .pcpi_rs1 (pcpi_rs1 ), - .pcpi_rs2 (pcpi_rs2 ), - .pcpi_wr (pcpi_wr ), - .pcpi_rd (pcpi_rd ), - .pcpi_wait (pcpi_wait ), - .pcpi_ready(pcpi_ready), - - .irq(irq), - .eoi(eoi), - -`ifdef RISCV_FORMAL - .rvfi_valid (rvfi_valid ), - .rvfi_order (rvfi_order ), - .rvfi_insn (rvfi_insn ), - .rvfi_trap (rvfi_trap ), - .rvfi_halt (rvfi_halt ), - .rvfi_intr (rvfi_intr ), - .rvfi_rs1_addr (rvfi_rs1_addr ), - .rvfi_rs2_addr (rvfi_rs2_addr ), - .rvfi_rs1_rdata(rvfi_rs1_rdata), - .rvfi_rs2_rdata(rvfi_rs2_rdata), - .rvfi_rd_addr (rvfi_rd_addr ), - .rvfi_rd_wdata (rvfi_rd_wdata ), - .rvfi_pc_rdata (rvfi_pc_rdata ), - .rvfi_pc_wdata (rvfi_pc_wdata ), - .rvfi_mem_addr (rvfi_mem_addr ), - .rvfi_mem_rmask(rvfi_mem_rmask), - .rvfi_mem_wmask(rvfi_mem_wmask), - .rvfi_mem_rdata(rvfi_mem_rdata), - .rvfi_mem_wdata(rvfi_mem_wdata), -`endif - - .trace_valid(trace_valid), - .trace_data (trace_data) - ); - - localparam IDLE = 2'b00; - localparam WBSTART = 2'b01; - localparam WBEND = 2'b10; - - reg [1:0] state; - - wire we; - assign we = (mem_wstrb[0] | mem_wstrb[1] | mem_wstrb[2] | mem_wstrb[3]); - - always @(posedge wb_clk_i) begin - if (wb_rst_i) begin - wbm_adr_o <= 0; - wbm_dat_o <= 0; - wbm_we_o <= 0; - wbm_sel_o <= 0; - wbm_stb_o <= 0; - wbm_cyc_o <= 0; - state <= IDLE; - end else begin - case (state) - IDLE: begin - if (mem_valid) begin - wbm_adr_o <= mem_addr; - wbm_dat_o <= mem_wdata; - wbm_we_o <= we; - wbm_sel_o <= mem_wstrb; - - wbm_stb_o <= 1'b1; - wbm_cyc_o <= 1'b1; - state <= WBSTART; - end else begin - mem_ready <= 1'b0; - - wbm_stb_o <= 1'b0; - wbm_cyc_o <= 1'b0; - wbm_we_o <= 1'b0; - end - end - WBSTART:begin - if (wbm_ack_i) begin - mem_rdata <= wbm_dat_i; - mem_ready <= 1'b1; - - state <= WBEND; - - wbm_stb_o <= 1'b0; - wbm_cyc_o <= 1'b0; - wbm_we_o <= 1'b0; - end - end - WBEND: begin - mem_ready <= 1'b0; - - state <= IDLE; - end - default: - state <= IDLE; - endcase - end - end -endmodule diff --git a/xc7/benchmark/picosoc.v b/xc7/benchmark/picosoc.v deleted file mode 100644 index 6298a8ef..00000000 --- a/xc7/benchmark/picosoc.v +++ /dev/null @@ -1,241 +0,0 @@ -/* - * PicoSoC - A simple example SoC using PicoRV32 - * - * Copyright (C) 2017 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 PICORV32_REGS -`ifdef PICORV32_V -`error "picosoc.v must be read before picorv32.v!" -`endif - -`define PICORV32_REGS picosoc_regs -`endif - -module picosoc ( - input clk, - input resetn, - - output iomem_valid, - input iomem_ready, - output [ 3:0] iomem_wstrb, - output [31:0] iomem_addr, - output [31:0] iomem_wdata, - input [31:0] iomem_rdata, - - input irq_5, - input irq_6, - input irq_7, - - output ser_tx, - input ser_rx, - - output flash_csb, - output flash_clk, - - output flash_io0_oe, - output flash_io1_oe, - output flash_io2_oe, - output flash_io3_oe, - - output flash_io0_do, - output flash_io1_do, - output flash_io2_do, - output flash_io3_do, - - input flash_io0_di, - input flash_io1_di, - input flash_io2_di, - input flash_io3_di -); - parameter integer MEM_WORDS = 256; - parameter [31:0] STACKADDR = (4*MEM_WORDS); // end of memory - parameter [31:0] PROGADDR_RESET = 32'h 0010_0000; // 1 MB into flash - - reg [31:0] irq; - wire irq_stall = 0; - wire irq_uart = 0; - - always @* begin - irq = 0; - irq[3] = irq_stall; - irq[4] = irq_uart; - irq[5] = irq_5; - irq[6] = irq_6; - irq[7] = irq_7; - end - - wire mem_valid; - wire mem_instr; - wire mem_ready; - wire [31:0] mem_addr; - wire [31:0] mem_wdata; - wire [3:0] mem_wstrb; - wire [31:0] mem_rdata; - - wire spimem_ready; - wire [31:0] spimem_rdata; - - reg ram_ready; - wire [31:0] ram_rdata; - - assign iomem_valid = mem_valid && (mem_addr[31:24] > 8'h 01); - assign iomem_wstrb = mem_wstrb; - assign iomem_addr = mem_addr; - assign iomem_wdata = mem_wdata; - - wire spimemio_cfgreg_sel = mem_valid && (mem_addr == 32'h 0200_0000); - wire [31:0] spimemio_cfgreg_do; - - wire simpleuart_reg_div_sel = mem_valid && (mem_addr == 32'h 0200_0004); - wire [31:0] simpleuart_reg_div_do; - - wire simpleuart_reg_dat_sel = mem_valid && (mem_addr == 32'h 0200_0008); - wire [31:0] simpleuart_reg_dat_do; - wire simpleuart_reg_dat_wait; - - assign mem_ready = (iomem_valid && iomem_ready) || spimem_ready || ram_ready || spimemio_cfgreg_sel || - simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait); - - assign mem_rdata = (iomem_valid && iomem_ready) ? iomem_rdata : spimem_ready ? spimem_rdata : ram_ready ? ram_rdata : - spimemio_cfgreg_sel ? spimemio_cfgreg_do : simpleuart_reg_div_sel ? simpleuart_reg_div_do : - simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 32'h 0000_0000; - - picorv32 #( - .STACKADDR(STACKADDR), - .PROGADDR_RESET(PROGADDR_RESET), - .PROGADDR_IRQ(32'h 0000_0000), - .BARREL_SHIFTER(1), - .COMPRESSED_ISA(1), - .ENABLE_MUL(1), - .ENABLE_DIV(1), - .ENABLE_IRQ(1), - .ENABLE_IRQ_QREGS(0) - ) cpu ( - .clk (clk ), - .resetn (resetn ), - .mem_valid (mem_valid ), - .mem_instr (mem_instr ), - .mem_ready (mem_ready ), - .mem_addr (mem_addr ), - .mem_wdata (mem_wdata ), - .mem_wstrb (mem_wstrb ), - .mem_rdata (mem_rdata ), - .irq (irq ) - ); - - spimemio spimemio ( - .clk (clk), - .resetn (resetn), - .valid (mem_valid && mem_addr >= 4*MEM_WORDS && mem_addr < 32'h 0200_0000), - .ready (spimem_ready), - .addr (mem_addr[23:0]), - .rdata (spimem_rdata), - - .flash_csb (flash_csb ), - .flash_clk (flash_clk ), - - .flash_io0_oe (flash_io0_oe), - .flash_io1_oe (flash_io1_oe), - .flash_io2_oe (flash_io2_oe), - .flash_io3_oe (flash_io3_oe), - - .flash_io0_do (flash_io0_do), - .flash_io1_do (flash_io1_do), - .flash_io2_do (flash_io2_do), - .flash_io3_do (flash_io3_do), - - .flash_io0_di (flash_io0_di), - .flash_io1_di (flash_io1_di), - .flash_io2_di (flash_io2_di), - .flash_io3_di (flash_io3_di), - - .cfgreg_we(spimemio_cfgreg_sel ? mem_wstrb : 4'b 0000), - .cfgreg_di(mem_wdata), - .cfgreg_do(spimemio_cfgreg_do) - ); - - simpleuart simpleuart ( - .clk (clk ), - .resetn (resetn ), - - .ser_tx (ser_tx ), - .ser_rx (ser_rx ), - - .reg_div_we (simpleuart_reg_div_sel ? mem_wstrb : 4'b 0000), - .reg_div_di (mem_wdata), - .reg_div_do (simpleuart_reg_div_do), - - .reg_dat_we (simpleuart_reg_dat_sel ? mem_wstrb[0] : 1'b 0), - .reg_dat_re (simpleuart_reg_dat_sel && !mem_wstrb), - .reg_dat_di (mem_wdata), - .reg_dat_do (simpleuart_reg_dat_do), - .reg_dat_wait(simpleuart_reg_dat_wait) - ); - - always @(posedge clk) - ram_ready <= mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS; - - picosoc_mem #(.WORDS(MEM_WORDS)) memory ( - .clk(clk), - .wen((mem_valid && !mem_ready && mem_addr < 4*MEM_WORDS) ? mem_wstrb : 4'b0), - .addr(mem_addr[23:2]), - .wdata(mem_wdata), - .rdata(ram_rdata) - ); -endmodule - -// Implementation note: -// Replace the following two modules with wrappers for your SRAM cells. - -module picosoc_regs ( - input clk, wen, - input [5:0] waddr, - input [5:0] raddr1, - input [5:0] raddr2, - input [31:0] wdata, - output [31:0] rdata1, - output [31:0] rdata2 -); - reg [31:0] regs [0:31]; - - always @(posedge clk) - if (wen) regs[waddr[4:0]] <= wdata; - - assign rdata1 = regs[raddr1[4:0]]; - assign rdata2 = regs[raddr2[4:0]]; -endmodule - -module picosoc_mem #( - parameter integer WORDS = 256 -) ( - input clk, - input [3:0] wen, - input [21:0] addr, - input [31:0] wdata, - output reg [31:0] rdata -); - reg [31:0] mem [0:WORDS-1]; - - always @(posedge clk) begin - rdata <= mem[addr]; - if (wen[0]) mem[addr][ 7: 0] <= wdata[ 7: 0]; - if (wen[1]) mem[addr][15: 8] <= wdata[15: 8]; - if (wen[2]) mem[addr][23:16] <= wdata[23:16]; - if (wen[3]) mem[addr][31:24] <= wdata[31:24]; - end -endmodule - diff --git a/xc7/benchmark/report.ipynb b/xc7/benchmark/report.ipynb deleted file mode 100644 index b4e03283..00000000 --- a/xc7/benchmark/report.ipynb +++ /dev/null @@ -1,91 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import numpy as np\n", - "import matplotlib.pyplot as plt\n", - "import subprocess, re\n", - "\n", - "gitrev = subprocess.getoutput(\"git rev-parse --short HEAD\")\n", - "\n", - "data_a = np.zeros((10, 2))\n", - "data_n = np.zeros((10, 2))\n", - "\n", - "for i in range(10):\n", - " try:\n", - " with open(\"report_a%d.txt\" % i, \"r\") as f:\n", - " for line in f:\n", - " if line.startswith(\"Total path delay:\"):\n", - " data_a[i, 0] = float(line.split()[3])\n", - " except:\n", - " data_a[i, 0] = 1.0\n", - " \n", - " try:\n", - " with open(\"report_n%d.txt\" % i, \"r\") as f:\n", - " for line in f:\n", - " if line.startswith(\"Total path delay:\"):\n", - " data_n[i, 0] = float(line.split()[3])\n", - " except:\n", - " data_n[i, 0] = 1.0\n", - " \n", - " with open(\"hx8kdemo_a%d.log\" % i, \"r\") as f:\n", - " for line in f:\n", - " match = re.match(r\"real\\s+(\\d+)m(\\d+)\", line)\n", - " if match:\n", - " data_a[i, 1] = float(match.group(1)) + float(match.group(2))/60\n", - " \n", - " with open(\"hx8kdemo_n%d.log\" % i, \"r\") as f:\n", - " for line in f:\n", - " match = re.match(r\"real\\s+(\\d+)m(\\d+)\", line)\n", - " if match:\n", - " data_n[i, 1] = float(match.group(1)) + float(match.group(2))/60\n", - "\n", - "plt.figure(figsize=(9,3))\n", - "plt.title(\"nextpnr -- ice40/benchmark/ -- %s\" % gitrev)\n", - "plt.bar(np.arange(10), data_a[:, 0], color='blue')\n", - "plt.bar(15+np.arange(10), data_n[:, 0], color='red')\n", - "plt.ylabel('Longest path (ns)')\n", - "plt.xticks([5, 20], [\"arachne-pnr\", \"nextpnr\"])\n", - "plt.xlim(-2, 27)\n", - "plt.show()\n", - "\n", - "plt.figure(figsize=(9,3))\n", - "plt.title(\"nextpnr -- ice40/benchmark/ -- %s\" % gitrev)\n", - "plt.bar(np.arange(10), data_a[:, 1], color='blue')\n", - "plt.bar(15+np.arange(10), data_n[:, 1], color='red')\n", - "plt.ylabel('Runtime (minutes)')\n", - "plt.xticks([5, 20], [\"arachne-pnr\", \"nextpnr\"])\n", - "plt.xlim(-2, 27)\n", - "plt.show()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.5.2" - } - }, - "nbformat": 4, - "nbformat_minor": 1 -} diff --git a/xc7/benchmark/simpleuart.v b/xc7/benchmark/simpleuart.v deleted file mode 100644 index 50808cb3..00000000 --- a/xc7/benchmark/simpleuart.v +++ /dev/null @@ -1,137 +0,0 @@ -/* - * PicoSoC - A simple example SoC using PicoRV32 - * - * Copyright (C) 2017 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. - * - */ - -module simpleuart ( - input clk, - input resetn, - - output ser_tx, - input ser_rx, - - input [3:0] reg_div_we, - input [31:0] reg_div_di, - output [31:0] reg_div_do, - - input reg_dat_we, - input reg_dat_re, - input [31:0] reg_dat_di, - output [31:0] reg_dat_do, - output reg_dat_wait -); - reg [31:0] cfg_divider; - - reg [3:0] recv_state; - reg [31:0] recv_divcnt; - reg [7:0] recv_pattern; - reg [7:0] recv_buf_data; - reg recv_buf_valid; - - reg [9:0] send_pattern; - reg [3:0] send_bitcnt; - reg [31:0] send_divcnt; - reg send_dummy; - - assign reg_div_do = cfg_divider; - - assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); - assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; - - always @(posedge clk) begin - if (!resetn) begin - cfg_divider <= 1; - end else begin - if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; - if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; - if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; - if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; - end - end - - always @(posedge clk) begin - if (!resetn) begin - recv_state <= 0; - recv_divcnt <= 0; - recv_pattern <= 0; - recv_buf_data <= 0; - recv_buf_valid <= 0; - end else begin - recv_divcnt <= recv_divcnt + 1; - if (reg_dat_re) - recv_buf_valid <= 0; - case (recv_state) - 0: begin - if (!ser_rx) - recv_state <= 1; - recv_divcnt <= 0; - end - 1: begin - if (2*recv_divcnt > cfg_divider) begin - recv_state <= 2; - recv_divcnt <= 0; - end - end - 10: begin - if (recv_divcnt > cfg_divider) begin - recv_buf_data <= recv_pattern; - recv_buf_valid <= 1; - recv_state <= 0; - end - end - default: begin - if (recv_divcnt > cfg_divider) begin - recv_pattern <= {ser_rx, recv_pattern[7:1]}; - recv_state <= recv_state + 1; - recv_divcnt <= 0; - end - end - endcase - end - end - - assign ser_tx = send_pattern[0]; - - always @(posedge clk) begin - if (reg_div_we) - send_dummy <= 1; - send_divcnt <= send_divcnt + 1; - if (!resetn) begin - send_pattern <= ~0; - send_bitcnt <= 0; - send_divcnt <= 0; - send_dummy <= 1; - end else begin - if (send_dummy && !send_bitcnt) begin - send_pattern <= ~0; - send_bitcnt <= 15; - send_divcnt <= 0; - send_dummy <= 0; - end else - if (reg_dat_we && !send_bitcnt) begin - send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; - send_bitcnt <= 10; - send_divcnt <= 0; - end else - if (send_divcnt > cfg_divider && send_bitcnt) begin - send_pattern <= {1'b1, send_pattern[9:1]}; - send_bitcnt <= send_bitcnt - 1; - send_divcnt <= 0; - end - end - end -endmodule diff --git a/xc7/benchmark/spimemio.v b/xc7/benchmark/spimemio.v deleted file mode 100644 index 0bbf5326..00000000 --- a/xc7/benchmark/spimemio.v +++ /dev/null @@ -1,579 +0,0 @@ -/* - * PicoSoC - A simple example SoC using PicoRV32 - * - * Copyright (C) 2017 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. - * - */ - -module spimemio ( - input clk, resetn, - - input valid, - output ready, - input [23:0] addr, - output reg [31:0] rdata, - - output flash_csb, - output flash_clk, - - output flash_io0_oe, - output flash_io1_oe, - output flash_io2_oe, - output flash_io3_oe, - - output flash_io0_do, - output flash_io1_do, - output flash_io2_do, - output flash_io3_do, - - input flash_io0_di, - input flash_io1_di, - input flash_io2_di, - input flash_io3_di, - - input [3:0] cfgreg_we, - input [31:0] cfgreg_di, - output [31:0] cfgreg_do -); - reg xfer_resetn; - reg din_valid; - wire din_ready; - reg [7:0] din_data; - reg [3:0] din_tag; - reg din_cont; - reg din_qspi; - reg din_ddr; - reg din_rd; - - wire dout_valid; - wire [7:0] dout_data; - wire [3:0] dout_tag; - - reg [23:0] buffer; - - reg [23:0] rd_addr; - reg rd_valid; - reg rd_wait; - reg rd_inc; - - assign ready = valid && (addr == rd_addr) && rd_valid; - wire jump = valid && !ready && (addr != rd_addr+4) && rd_valid; - - reg softreset; - - reg config_en; // cfgreg[31] - reg config_ddr; // cfgreg[22] - reg config_qspi; // cfgreg[21] - reg config_cont; // cfgreg[20] - reg [3:0] config_dummy; // cfgreg[19:16] - reg [3:0] config_oe; // cfgreg[11:8] - reg config_csb; // cfgreg[5] - reg config_clk; // cfgref[4] - reg [3:0] config_do; // cfgreg[3:0] - - assign cfgreg_do[31] = config_en; - assign cfgreg_do[30:23] = 0; - assign cfgreg_do[22] = config_ddr; - assign cfgreg_do[21] = config_qspi; - assign cfgreg_do[20] = config_cont; - assign cfgreg_do[19:16] = config_dummy; - assign cfgreg_do[15:12] = 0; - assign cfgreg_do[11:8] = {flash_io3_oe, flash_io2_oe, flash_io1_oe, flash_io0_oe}; - assign cfgreg_do[7:6] = 0; - assign cfgreg_do[5] = flash_csb; - assign cfgreg_do[4] = flash_clk; - assign cfgreg_do[3:0] = {flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; - - always @(posedge clk) begin - softreset <= !config_en || cfgreg_we; - if (!resetn) begin - softreset <= 1; - config_en <= 1; - config_csb <= 0; - config_clk <= 0; - config_oe <= 0; - config_do <= 0; - config_ddr <= 0; - config_qspi <= 0; - config_cont <= 0; - config_dummy <= 8; - end else begin - if (cfgreg_we[0]) begin - config_csb <= cfgreg_di[5]; - config_clk <= cfgreg_di[4]; - config_do <= cfgreg_di[3:0]; - end - if (cfgreg_we[1]) begin - config_oe <= cfgreg_di[11:8]; - end - if (cfgreg_we[2]) begin - config_ddr <= cfgreg_di[22]; - config_qspi <= cfgreg_di[21]; - config_cont <= cfgreg_di[20]; - config_dummy <= cfgreg_di[19:16]; - end - if (cfgreg_we[3]) begin - config_en <= cfgreg_di[31]; - end - end - end - - wire xfer_csb; - wire xfer_clk; - - wire xfer_io0_oe; - wire xfer_io1_oe; - wire xfer_io2_oe; - wire xfer_io3_oe; - - wire xfer_io0_do; - wire xfer_io1_do; - wire xfer_io2_do; - wire xfer_io3_do; - - reg xfer_io0_90; - reg xfer_io1_90; - reg xfer_io2_90; - reg xfer_io3_90; - - always @(negedge clk) begin - xfer_io0_90 <= xfer_io0_do; - xfer_io1_90 <= xfer_io1_do; - xfer_io2_90 <= xfer_io2_do; - xfer_io3_90 <= xfer_io3_do; - end - - assign flash_csb = config_en ? xfer_csb : config_csb; - assign flash_clk = config_en ? xfer_clk : config_clk; - - assign flash_io0_oe = config_en ? xfer_io0_oe : config_oe[0]; - assign flash_io1_oe = config_en ? xfer_io1_oe : config_oe[1]; - assign flash_io2_oe = config_en ? xfer_io2_oe : config_oe[2]; - assign flash_io3_oe = config_en ? xfer_io3_oe : config_oe[3]; - - assign flash_io0_do = config_en ? (config_ddr ? xfer_io0_90 : xfer_io0_do) : config_do[0]; - assign flash_io1_do = config_en ? (config_ddr ? xfer_io1_90 : xfer_io1_do) : config_do[1]; - assign flash_io2_do = config_en ? (config_ddr ? xfer_io2_90 : xfer_io2_do) : config_do[2]; - assign flash_io3_do = config_en ? (config_ddr ? xfer_io3_90 : xfer_io3_do) : config_do[3]; - - wire xfer_dspi = din_ddr && !din_qspi; - wire xfer_ddr = din_ddr && din_qspi; - - spimemio_xfer xfer ( - .clk (clk ), - .resetn (xfer_resetn ), - .din_valid (din_valid ), - .din_ready (din_ready ), - .din_data (din_data ), - .din_tag (din_tag ), - .din_cont (din_cont ), - .din_dspi (xfer_dspi ), - .din_qspi (din_qspi ), - .din_ddr (xfer_ddr ), - .din_rd (din_rd ), - .dout_valid (dout_valid ), - .dout_data (dout_data ), - .dout_tag (dout_tag ), - .flash_csb (xfer_csb ), - .flash_clk (xfer_clk ), - .flash_io0_oe (xfer_io0_oe ), - .flash_io1_oe (xfer_io1_oe ), - .flash_io2_oe (xfer_io2_oe ), - .flash_io3_oe (xfer_io3_oe ), - .flash_io0_do (xfer_io0_do ), - .flash_io1_do (xfer_io1_do ), - .flash_io2_do (xfer_io2_do ), - .flash_io3_do (xfer_io3_do ), - .flash_io0_di (flash_io0_di), - .flash_io1_di (flash_io1_di), - .flash_io2_di (flash_io2_di), - .flash_io3_di (flash_io3_di) - ); - - reg [3:0] state; - - always @(posedge clk) begin - xfer_resetn <= 1; - din_valid <= 0; - - if (!resetn || softreset) begin - state <= 0; - xfer_resetn <= 0; - rd_valid <= 0; - din_tag <= 0; - din_cont <= 0; - din_qspi <= 0; - din_ddr <= 0; - din_rd <= 0; - end else begin - if (dout_valid && dout_tag == 1) buffer[ 7: 0] <= dout_data; - if (dout_valid && dout_tag == 2) buffer[15: 8] <= dout_data; - if (dout_valid && dout_tag == 3) buffer[23:16] <= dout_data; - if (dout_valid && dout_tag == 4) begin - rdata <= {dout_data, buffer}; - rd_addr <= rd_inc ? rd_addr + 4 : addr; - rd_valid <= 1; - rd_wait <= rd_inc; - rd_inc <= 1; - end - - if (valid) - rd_wait <= 0; - - case (state) - 0: begin - din_valid <= 1; - din_data <= 8'h ff; - din_tag <= 0; - if (din_ready) begin - din_valid <= 0; - state <= 1; - end - end - 1: begin - if (dout_valid) begin - xfer_resetn <= 0; - state <= 2; - end - end - 2: begin - din_valid <= 1; - din_data <= 8'h ab; - din_tag <= 0; - if (din_ready) begin - din_valid <= 0; - state <= 3; - end - end - 3: begin - if (dout_valid) begin - xfer_resetn <= 0; - state <= 4; - end - end - 4: begin - rd_inc <= 0; - din_valid <= 1; - din_tag <= 0; - case ({config_ddr, config_qspi}) - 2'b11: din_data <= 8'h ED; - 2'b01: din_data <= 8'h EB; - 2'b10: din_data <= 8'h BB; - 2'b00: din_data <= 8'h 03; - endcase - if (din_ready) begin - din_valid <= 0; - state <= 5; - end - end - 5: begin - if (valid && !ready) begin - din_valid <= 1; - din_tag <= 0; - din_data <= addr[23:16]; - din_qspi <= config_qspi; - din_ddr <= config_ddr; - if (din_ready) begin - din_valid <= 0; - state <= 6; - end - end - end - 6: begin - din_valid <= 1; - din_tag <= 0; - din_data <= addr[15:8]; - if (din_ready) begin - din_valid <= 0; - state <= 7; - end - end - 7: begin - din_valid <= 1; - din_tag <= 0; - din_data <= addr[7:0]; - if (din_ready) begin - din_valid <= 0; - din_data <= 0; - state <= config_qspi || config_ddr ? 8 : 9; - end - end - 8: begin - din_valid <= 1; - din_tag <= 0; - din_data <= config_cont ? 8'h A5 : 8'h FF; - if (din_ready) begin - din_rd <= 1; - din_data <= config_dummy; - din_valid <= 0; - state <= 9; - end - end - 9: begin - din_valid <= 1; - din_tag <= 1; - if (din_ready) begin - din_valid <= 0; - state <= 10; - end - end - 10: begin - din_valid <= 1; - din_data <= 8'h 00; - din_tag <= 2; - if (din_ready) begin - din_valid <= 0; - state <= 11; - end - end - 11: begin - din_valid <= 1; - din_tag <= 3; - if (din_ready) begin - din_valid <= 0; - state <= 12; - end - end - 12: begin - if (!rd_wait || valid) begin - din_valid <= 1; - din_tag <= 4; - if (din_ready) begin - din_valid <= 0; - state <= 9; - end - end - end - endcase - - if (jump) begin - rd_inc <= 0; - rd_valid <= 0; - xfer_resetn <= 0; - if (config_cont) begin - state <= 5; - end else begin - state <= 4; - din_qspi <= 0; - din_ddr <= 0; - end - din_rd <= 0; - end - end - end -endmodule - -module spimemio_xfer ( - input clk, resetn, - - input din_valid, - output din_ready, - input [7:0] din_data, - input [3:0] din_tag, - input din_cont, - input din_dspi, - input din_qspi, - input din_ddr, - input din_rd, - - output dout_valid, - output [7:0] dout_data, - output [3:0] dout_tag, - - output reg flash_csb, - output reg flash_clk, - - output reg flash_io0_oe, - output reg flash_io1_oe, - output reg flash_io2_oe, - output reg flash_io3_oe, - - output reg flash_io0_do, - output reg flash_io1_do, - output reg flash_io2_do, - output reg flash_io3_do, - - input flash_io0_di, - input flash_io1_di, - input flash_io2_di, - input flash_io3_di -); - reg [7:0] obuffer; - reg [7:0] ibuffer; - - reg [3:0] count; - reg [3:0] dummy_count; - - reg xfer_cont; - reg xfer_dspi; - reg xfer_qspi; - reg xfer_ddr; - reg xfer_ddr_q; - reg xfer_rd; - reg [3:0] xfer_tag; - reg [3:0] xfer_tag_q; - - reg [7:0] next_obuffer; - reg [7:0] next_ibuffer; - reg [3:0] next_count; - - reg fetch; - reg next_fetch; - reg last_fetch; - - always @(posedge clk) begin - xfer_ddr_q <= xfer_ddr; - xfer_tag_q <= xfer_tag; - end - - assign din_ready = din_valid && resetn && next_fetch; - - assign dout_valid = (xfer_ddr_q ? fetch && !last_fetch : next_fetch && !fetch) && resetn; - assign dout_data = ibuffer; - assign dout_tag = xfer_tag_q; - - always @* begin - flash_io0_oe = 0; - flash_io1_oe = 0; - flash_io2_oe = 0; - flash_io3_oe = 0; - - flash_io0_do = 0; - flash_io1_do = 0; - flash_io2_do = 0; - flash_io3_do = 0; - - next_obuffer = obuffer; - next_ibuffer = ibuffer; - next_count = count; - next_fetch = 0; - - if (dummy_count == 0) begin - casez ({xfer_ddr, xfer_qspi, xfer_dspi}) - 3'b 000: begin - flash_io0_oe = 1; - flash_io0_do = obuffer[7]; - - if (flash_clk) begin - next_obuffer = {obuffer[6:0], 1'b 0}; - next_count = count - |count; - end else begin - next_ibuffer = {ibuffer[6:0], flash_io1_di}; - end - - next_fetch = (next_count == 0); - end - 3'b 01?: begin - flash_io0_oe = !xfer_rd; - flash_io1_oe = !xfer_rd; - flash_io2_oe = !xfer_rd; - flash_io3_oe = !xfer_rd; - - flash_io0_do = obuffer[4]; - flash_io1_do = obuffer[5]; - flash_io2_do = obuffer[6]; - flash_io3_do = obuffer[7]; - - if (flash_clk) begin - next_obuffer = {obuffer[3:0], 4'b 0000}; - next_count = count - {|count, 2'b00}; - end else begin - next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; - end - - next_fetch = (next_count == 0); - end - 3'b 11?: begin - flash_io0_oe = !xfer_rd; - flash_io1_oe = !xfer_rd; - flash_io2_oe = !xfer_rd; - flash_io3_oe = !xfer_rd; - - flash_io0_do = obuffer[4]; - flash_io1_do = obuffer[5]; - flash_io2_do = obuffer[6]; - flash_io3_do = obuffer[7]; - - next_obuffer = {obuffer[3:0], 4'b 0000}; - next_ibuffer = {ibuffer[3:0], flash_io3_di, flash_io2_di, flash_io1_di, flash_io0_di}; - next_count = count - {|count, 2'b00}; - - next_fetch = (next_count == 0); - end - 3'b ??1: begin - flash_io0_oe = !xfer_rd; - flash_io1_oe = !xfer_rd; - - flash_io0_do = obuffer[6]; - flash_io1_do = obuffer[7]; - - if (flash_clk) begin - next_obuffer = {obuffer[5:0], 2'b 00}; - next_count = count - {|count, 1'b0}; - end else begin - next_ibuffer = {ibuffer[5:0], flash_io1_di, flash_io0_di}; - end - - next_fetch = (next_count == 0); - end - endcase - end - end - - always @(posedge clk) begin - if (!resetn) begin - fetch <= 1; - last_fetch <= 1; - flash_csb <= 1; - flash_clk <= 0; - count <= 0; - dummy_count <= 0; - xfer_tag <= 0; - xfer_cont <= 0; - xfer_dspi <= 0; - xfer_qspi <= 0; - xfer_ddr <= 0; - xfer_rd <= 0; - end else begin - fetch <= next_fetch; - last_fetch <= xfer_ddr ? fetch : 1; - if (dummy_count) begin - flash_clk <= !flash_clk && !flash_csb; - dummy_count <= dummy_count - flash_clk; - end else - if (count) begin - flash_clk <= !flash_clk && !flash_csb; - obuffer <= next_obuffer; - ibuffer <= next_ibuffer; - count <= next_count; - end - if (din_valid && din_ready) begin - flash_csb <= 0; - flash_clk <= 0; - - count <= 8; - dummy_count <= din_rd ? din_data : 0; - obuffer <= din_data; - - xfer_tag <= din_tag; - xfer_cont <= din_cont; - xfer_dspi <= din_dspi; - xfer_qspi <= din_qspi; - xfer_ddr <= din_ddr; - xfer_rd <= din_rd; - end - end - end -endmodule diff --git a/xc7/carry_tests/.gitignore b/xc7/carry_tests/.gitignore deleted file mode 100644 index 427dd825..00000000 --- a/xc7/carry_tests/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -*.vcd -*_out.v -*.out - diff --git a/xc7/carry_tests/counter.v b/xc7/carry_tests/counter.v deleted file mode 100644 index 1379a330..00000000 --- a/xc7/carry_tests/counter.v +++ /dev/null @@ -1,9 +0,0 @@ -module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); - - reg [15:0] ctr = 0; - - always @(posedge clk) - ctr <= ctr + 1'b1; - - assign {outa, outb, outc, outd} = ctr[15:12]; -endmodule diff --git a/xc7/carry_tests/counter_tb.v b/xc7/carry_tests/counter_tb.v deleted file mode 100644 index ede133a7..00000000 --- a/xc7/carry_tests/counter_tb.v +++ /dev/null @@ -1,23 +0,0 @@ -module counter_tb; - reg clk; - always #5 clk = (clk === 1'b0); - - wire outa, outb, outc, outd; - - chip uut ( - .clk(clk), - .cen(1'b1), - .rst(1'b0), - .outa(outa), - .outb(outb), - .outc(outc), - .outd(outd) - ); - - initial begin - $dumpfile("counter_tb.vcd"); - $dumpvars(0, counter_tb); - repeat (100000) @(posedge clk); - $finish; - end -endmodule diff --git a/xc7/carry_tests/test.pcf b/xc7/carry_tests/test.pcf deleted file mode 100644 index 8cd488bf..00000000 --- a/xc7/carry_tests/test.pcf +++ /dev/null @@ -1,10 +0,0 @@ -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/xc7/carry_tests/test.sh b/xc7/carry_tests/test.sh deleted file mode 100755 index 0ba63365..00000000 --- a/xc7/carry_tests/test.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -ex -NAME=${1%.v} -yosys -p "synth_ice40 -top top; write_json ${NAME}.json" $1 -../../nextpnr-ice40 --json ${NAME}.json --pcf test.pcf --asc ${NAME}.asc --verbose -icebox_vlog -p test.pcf -L ${NAME}.asc > ${NAME}_out.v -iverilog -o ${NAME}_sim.out ${NAME}_tb.v ${NAME}_out.v -vvp ${NAME}_sim.out - diff --git a/xc7/icebreaker.pcf b/xc7/icebreaker.pcf deleted file mode 100644 index bc4a2974..00000000 --- a/xc7/icebreaker.pcf +++ /dev/null @@ -1,14 +0,0 @@ -set_io led1 27 -set_io led2 25 -set_io led3 21 -set_io led4 23 -set_io led5 26 -set_io ledr 11 -set_io ledg 37 - -set_io clki 35 -set_io btn1 20 -set_io btn2 19 -set_io btn3 18 -set_io btn_n 10 - diff --git a/xc7/icebreaker.v b/xc7/icebreaker.v deleted file mode 100644 index 1c8c0863..00000000 --- a/xc7/icebreaker.v +++ /dev/null @@ -1,31 +0,0 @@ -module icebreaker ( - input clki, - input btn1, - input btn2, - input btn3, - input btn_n, - - output led1, - output led2, - output led3, - output led4, - output led5, - output ledr, - output ledg, -); - wire clk; - SB_GB clk_gb(.USER_SIGNAL_TO_GLOBAL_BUFFER(clki), .GLOBAL_BUFFER_OUTPUT(clk)); - localparam BITS = 5; - localparam LOG2DELAY = 22; - - reg [BITS+LOG2DELAY-1:0] counter = 0; - reg [BITS-1:0] outcnt; - - always @(posedge clk) begin - counter <= counter + 1; - outcnt <= counter >> LOG2DELAY; - end - assign {led1, led2, led3, led4, led5} = outcnt ^ (outcnt >> 1); - - assign {ledr, ledg} = ~(!btn_n + btn1 + btn2 + btn3); -endmodule diff --git a/xc7/icebreaker.ys b/xc7/icebreaker.ys deleted file mode 100644 index 878914aa..00000000 --- a/xc7/icebreaker.ys +++ /dev/null @@ -1,3 +0,0 @@ -read_verilog icebreaker.v -synth_ice40 -nocarry -top icebreaker -write_json icebreaker.json diff --git a/xc7/pack_tests/.gitignore b/xc7/pack_tests/.gitignore deleted file mode 100644 index 749cb303..00000000 --- a/xc7/pack_tests/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.vcd -*_out.v diff --git a/xc7/pack_tests/ffmodes.v b/xc7/pack_tests/ffmodes.v deleted file mode 100644 index c09ced74..00000000 --- a/xc7/pack_tests/ffmodes.v +++ /dev/null @@ -1,43 +0,0 @@ -module top(input clk, cen, rst, ina, inb, output reg outa, outb, outc, outd); - -reg temp0 = 1'b0, temp1 = 1'b0; -initial outa = 1'b0; -initial outb = 1'b0; -initial outc = 1'b0; -initial outd = 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 posedge 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/xc7/pack_tests/locals.v b/xc7/pack_tests/locals.v deleted file mode 100644 index a1c5ea9f..00000000 --- a/xc7/pack_tests/locals.v +++ /dev/null @@ -1,27 +0,0 @@ -module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); - -reg [31:0] temp = 0; - -integer i; - -always @(posedge clk) -begin - if (cen) begin - if (rst) begin - temp <= 0; - end else begin - temp[0] <= ina; - temp[1] <= inb; - for (i = 2; i < 32; i++) begin - temp[i] <= temp[(i + 3) % 32] ^ temp[(i + 30) % 32] ^ temp[(i + 4) % 16] ^ temp[(i + 2) % 32]; - end - end - end -end - -assign outa = temp[3]; -assign outb = temp[5]; -assign outc = temp[9]; -assign outd = temp[15]; - -endmodule diff --git a/xc7/pack_tests/place_constr.v b/xc7/pack_tests/place_constr.v deleted file mode 100644 index f915a203..00000000 --- a/xc7/pack_tests/place_constr.v +++ /dev/null @@ -1,54 +0,0 @@ -module top(input clk, cen, rst, ina, inb, output outa, outb, outc, outd); - -wire temp0, temp1; - -(* BEL="1_1_lc0" *) -SB_LUT4 #( - .LUT_INIT(2'b01) -) lut0 ( - .I3(), - .I2(), - .I1(), - .I0(ina), - .O(temp0) -); - - -(* BEL="1_3_lc0" *) -SB_LUT4 #( - .LUT_INIT(2'b01) -) lut1 ( - .I3(), - .I2(), - .I1(), - .I0(inb), - .O(temp1) -); - -(* BEL="1_1_lc0" *) -SB_DFF ff0 ( - .C(clk), - .D(temp1), - .Q(outa) -); - - -(* BEL="1_1_lc7" *) -SB_DFF ff1 ( - .C(clk), - .D(inb), - .Q(outb) -); - - -(* BEL="1_6_lc7" *) -SB_DFF ff2 ( - .C(clk), - .D(temp1), - .Q(outc) -); - - -assign outd = 1'b0; - -endmodule diff --git a/xc7/pack_tests/test.pcf b/xc7/pack_tests/test.pcf deleted file mode 100644 index 8cd488bf..00000000 --- a/xc7/pack_tests/test.pcf +++ /dev/null @@ -1,10 +0,0 @@ -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/xc7/pack_tests/test.sh b/xc7/pack_tests/test.sh deleted file mode 100755 index b36c01dc..00000000 --- a/xc7/pack_tests/test.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash -set -ex -NAME=${1%.v} -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;\ - rename chip 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 60 -seq 50 -prove trigger 0 -prove-skip 1 -show-inputs -show-outputs miter" ${NAME}_out.v diff --git a/xc7/resource/chipdb.rc b/xc7/resource/chipdb.rc deleted file mode 100644 index a6f2dbe8..00000000 --- a/xc7/resource/chipdb.rc +++ /dev/null @@ -1,6 +0,0 @@ -#include "resource.h" - -IDR_CHIPDB_384 BINARYFILE "..\chipdbs\chipdb-384.bin" -IDR_CHIPDB_1K BINARYFILE "..\chipdbs\chipdb-1k.bin" -IDR_CHIPDB_5K BINARYFILE "..\chipdbs\chipdb-5k.bin" -IDR_CHIPDB_8K BINARYFILE "..\chipdbs\chipdb-8k.bin" diff --git a/xc7/resource/embed.cc b/xc7/resource/embed.cc deleted file mode 100644 index 74f2eee9..00000000 --- a/xc7/resource/embed.cc +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include -#include "nextpnr.h" -#include "resource.h" - -NEXTPNR_NAMESPACE_BEGIN - -const char *chipdb_blob_384; -const char *chipdb_blob_1k; -const char *chipdb_blob_5k; -const char *chipdb_blob_8k; - -const char *LoadFileInResource(int name, int type, DWORD &size) -{ - HMODULE handle = ::GetModuleHandle(NULL); - HRSRC rc = ::FindResource(handle, MAKEINTRESOURCE(name), MAKEINTRESOURCE(type)); - HGLOBAL rcData = ::LoadResource(handle, rc); - size = ::SizeofResource(handle, rc); - return static_cast(::LockResource(rcData)); -} -void load_chipdb() -{ - DWORD size = 0; - chipdb_blob_384 = LoadFileInResource(IDR_CHIPDB_384, BINARYFILE, size); - chipdb_blob_1k = LoadFileInResource(IDR_CHIPDB_1K, BINARYFILE, size); - chipdb_blob_5k = LoadFileInResource(IDR_CHIPDB_5K, BINARYFILE, size); - chipdb_blob_8k = LoadFileInResource(IDR_CHIPDB_8K, BINARYFILE, size); -} - -NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/xc7/resource/resource.h b/xc7/resource/resource.h deleted file mode 100644 index 46997ae5..00000000 --- a/xc7/resource/resource.h +++ /dev/null @@ -1,5 +0,0 @@ -#define BINARYFILE 256 -#define IDR_CHIPDB_384 101 -#define IDR_CHIPDB_1K 102 -#define IDR_CHIPDB_5K 103 -#define IDR_CHIPDB_8K 104 From e15aa8d3f4036dd82d5e2bffb9f17323f347be7d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:26:47 -0800 Subject: [PATCH 168/174] Add blinky_sim.sh --- xc7/blinky_sim.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100755 xc7/blinky_sim.sh diff --git a/xc7/blinky_sim.sh b/xc7/blinky_sim.sh new file mode 100755 index 00000000..e353a407 --- /dev/null +++ b/xc7/blinky_sim.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -ex +yosys blinky_sim.ys +../nextpnr-xc7 --json blinky.json --pcf blinky.pcf --xdl blinky.xdl --freq 125 +xdl -xdl2ncd blinky.xdl +trce blinky.ncd -v 10 +netgen -sim -ofmt vhdl blinky.ncd -w blinky_pnr.vhd +ghdl -c -fexplicit --no-vital-checks --ieee=synopsys -Pxilinx-ise blinky_tb.vhd blinky_pnr.vhd -r testbench From 84d038360d357a7c3830fbb483718f81286523e7 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:27:50 -0800 Subject: [PATCH 169/174] Add implicit wire --- xc7/blinky.v | 1 + 1 file changed, 1 insertion(+) diff --git a/xc7/blinky.v b/xc7/blinky.v index 10ec23a3..692c7ab9 100644 --- a/xc7/blinky.v +++ b/xc7/blinky.v @@ -5,6 +5,7 @@ module blinky ( output led2, output led3 ); + wire clk; BUFGCTRL clk_gb ( .I0(clki), .CE0(1'b1), From 04757865feec0467f83371daafddb5bb5999270d Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:28:12 -0800 Subject: [PATCH 170/174] Remove PLL from picorv32, allow errors in pnr --- xc7/picorv32.pcf | 6 +++--- xc7/picorv32.sh | 4 +++- xc7/picorv32_top.v | 16 +++++++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/xc7/picorv32.pcf b/xc7/picorv32.pcf index 0f023697..bc8e084a 100644 --- a/xc7/picorv32.pcf +++ b/xc7/picorv32.pcf @@ -1,3 +1,3 @@ -NET "pll.clkin1" PERIOD = 8 nS ; -#PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; -#PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; +NET "clki" PERIOD = 8 nS ; +PIN "clki_pin" = BEL "clki.PAD" PINNAME PAD; +PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/picorv32.sh b/xc7/picorv32.sh index 99860236..ec2aee80 100755 --- a/xc7/picorv32.sh +++ b/xc7/picorv32.sh @@ -3,7 +3,9 @@ set -ex rm -f picorv32.v wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v yosys picorv32.ys -../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl --pcf picorv32.pcf --freq 150 +set +e +../nextpnr-xc7 --json picorv32.json --xdl picorv32.xdl --pcf picorv32.pcf --freq 125 +set -e xdl -xdl2ncd picorv32.xdl #bitgen -w blinky.ncd -g UnconstrainedPins:Allow trce picorv32.ncd -v 10 diff --git a/xc7/picorv32_top.v b/xc7/picorv32_top.v index 34149622..3735aa1b 100644 --- a/xc7/picorv32_top.v +++ b/xc7/picorv32_top.v @@ -1,5 +1,5 @@ module top ( - input clk, resetn, + input clki, resetn, output trap, output mem_valid, @@ -12,7 +12,17 @@ module top ( input [31:0] mem_rdata ); - clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); + wire clk; + BUFGCTRL clk_gb ( + .I0(clki), + .CE0(1'b1), + .CE1(1'b0), + .S0(1'b1), + .S1(1'b0), + .IGNORE0(1'b0), + .IGNORE1(1'b0), + .O(clk) + ); picorv32 #( .ENABLE_COUNTERS(0), @@ -20,7 +30,7 @@ module top ( .CATCH_MISALIGN(0), .CATCH_ILLINSN(0) ) cpu ( - .clk (gclk ), + .clk (clk ), .resetn (resetn ), .trap (trap ), .mem_valid(mem_valid), From cb6ea8ba84fa1e7895f62b891e2e9e82f66647f1 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:28:33 -0800 Subject: [PATCH 171/174] Remove PLL from attosoc, allow errors in pnr --- xc7/attosoc.pcf | 7 +++---- xc7/attosoc.sh | 13 ++++++++----- xc7/attosoc.ys | 1 - xc7/attosoc_tb.vhd | 2 +- xc7/attosoc_top.v | 19 ++++++++++++++----- 5 files changed, 26 insertions(+), 16 deletions(-) diff --git a/xc7/attosoc.pcf b/xc7/attosoc.pcf index 3ef75a17..fd14331c 100644 --- a/xc7/attosoc.pcf +++ b/xc7/attosoc.pcf @@ -2,8 +2,7 @@ COMP "led[0]" LOCATE = SITE "M14" LEVEL 1; COMP "led[1]" LOCATE = SITE "M15" LEVEL 1; COMP "led[2]" LOCATE = SITE "G14" LEVEL 1; COMP "led[3]" LOCATE = SITE "D18" LEVEL 1; -COMP "clk" LOCATE = SITE "K17" LEVEL 1; -COMP "pll.mmcm_adv_inst" LOCATE = SITE "MMCME2_ADV_X1Y2" LEVEL 1; +COMP "clki" LOCATE = SITE "K17" LEVEL 1; NET "pll.clkin1" PERIOD = 8 nS ; -#PIN "clk_pin" = BEL "clk.PAD" PINNAME PAD; -#PIN "clk_pin" CLOCK_DEDICATED_ROUTE = FALSE; +PIN "clki_pin" = BEL "clki.PAD" PINNAME PAD; +PIN "clki_pin" CLOCK_DEDICATED_ROUTE = FALSE; diff --git a/xc7/attosoc.sh b/xc7/attosoc.sh index e7f1c95a..119ed6b9 100755 --- a/xc7/attosoc.sh +++ b/xc7/attosoc.sh @@ -1,11 +1,14 @@ #!/bin/bash -#set -ex -#rm -f picorv32.v -#wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +set -ex +rm -f picorv32.v attosoc.v +wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +wget https://raw.githubusercontent.com/SymbiFlow/prjtrellis/master/examples/picorv32_versa5g/attosoc.v yosys attosoc.ys -../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 150 |& tee attosoc.log +set +e +../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 125 +set -e xdl -xdl2ncd attosoc.xdl -bitgen -w attosoc.ncd -g UnconstrainedPins:Allow +#bitgen -w attosoc.ncd -g UnconstrainedPins:Allow trce attosoc.ncd -v 10 netgen -sim -ofmt vhdl attosoc.ncd -w attosoc_pnr.vhd diff --git a/xc7/attosoc.ys b/xc7/attosoc.ys index 105728c9..7ec25173 100644 --- a/xc7/attosoc.ys +++ b/xc7/attosoc.ys @@ -1,7 +1,6 @@ read_verilog attosoc_top.v read_verilog attosoc.v read_verilog picorv32.v -read_verilog 125MHz_to_60MHz.v #synth_xilinx -top picorv32 diff --git a/xc7/attosoc_tb.vhd b/xc7/attosoc_tb.vhd index fe697c3f..68996189 100644 --- a/xc7/attosoc_tb.vhd +++ b/xc7/attosoc_tb.vhd @@ -14,7 +14,7 @@ begin wait for 4 ns; end process; - uut: entity work.name port map(clk_PAD_PAD => clk, led_0_OUTBUF_OUT => led(0), led_1_OUTBUF_OUT => led(1), led_2_OUTBUF_OUT => led(2), led_3_OUTBUF_OUT => led(3)); + uut: entity work.name port map(clki_PAD_PAD => clk, led_0_OUTBUF_OUT => led(0), led_1_OUTBUF_OUT => led(1), led_2_OUTBUF_OUT => led(2), led_3_OUTBUF_OUT => led(3)); process begin diff --git a/xc7/attosoc_top.v b/xc7/attosoc_top.v index b794abda..bbf75a05 100644 --- a/xc7/attosoc_top.v +++ b/xc7/attosoc_top.v @@ -1,15 +1,24 @@ module top ( - input clk, + input clki, output [3:0] led ); (* keep *) wire led_unused; - wire gclk; - clk_wiz_v3_6 pll(.CLK_IN1(clk), .CLK_OUT1(gclk)); - //assign gclk = clk; - attosoc soc(.clk(gclk), .led({led_unused, led})); + wire clk; + BUFGCTRL clk_gb ( + .I0(clki), + .CE0(1'b1), + .CE1(1'b0), + .S0(1'b1), + .S1(1'b0), + .IGNORE0(1'b0), + .IGNORE1(1'b0), + .O(clk) + ); + + attosoc soc(.clk(clk), .led({led_unused, led})); endmodule From 592022c180f682f8b817b44331ab2388977dcc27 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:29:35 -0800 Subject: [PATCH 172/174] Add *.nlf and *.sdf to .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2510da04..bf22d038 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,5 @@ xilinx_device_details.xml *_fpga_editor.* *.twr *.twx +*.nlf +*.sdf From 4c9f62e1e01484d047abb34334e36adb0edfb0f0 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:47:16 -0800 Subject: [PATCH 173/174] Add attosoc_sim.sh and fimrware_fast.hex --- xc7/attosoc.sh | 6 ++---- xc7/attosoc_sim.sh | 16 ++++++++++++++++ xc7/firmware_fast.hex | 6 ++++++ xc7/{firmware.hex => firmware_slow.hex} | 0 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100755 xc7/attosoc_sim.sh create mode 100644 xc7/firmware_fast.hex rename xc7/{firmware.hex => firmware_slow.hex} (100%) diff --git a/xc7/attosoc.sh b/xc7/attosoc.sh index 119ed6b9..cb04bda4 100755 --- a/xc7/attosoc.sh +++ b/xc7/attosoc.sh @@ -3,13 +3,11 @@ set -ex rm -f picorv32.v attosoc.v wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v wget https://raw.githubusercontent.com/SymbiFlow/prjtrellis/master/examples/picorv32_versa5g/attosoc.v +ln -sf firmware_slow.hex firmware.hex yosys attosoc.ys set +e ../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 125 set -e xdl -xdl2ncd attosoc.xdl -#bitgen -w attosoc.ncd -g UnconstrainedPins:Allow +bitgen -w attosoc.ncd -g UnconstrainedPins:Allow trce attosoc.ncd -v 10 - -netgen -sim -ofmt vhdl attosoc.ncd -w attosoc_pnr.vhd -ghdl -c -fexplicit --no-vital-checks --ieee=synopsys -Pxilinx-ise attosoc_tb.vhd attosoc_pnr.vhd -r testbench diff --git a/xc7/attosoc_sim.sh b/xc7/attosoc_sim.sh new file mode 100755 index 00000000..61d668af --- /dev/null +++ b/xc7/attosoc_sim.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -ex +rm -f picorv32.v attosoc.v +wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v +wget https://raw.githubusercontent.com/SymbiFlow/prjtrellis/master/examples/picorv32_versa5g/attosoc.v +ln -sf firmware_fast.hex firmware.hex +yosys attosoc.ys +set +e +../nextpnr-xc7 --json attosoc.json --xdl attosoc.xdl --pcf attosoc.pcf --freq 125 +set -e +xdl -xdl2ncd attosoc.xdl +#bitgen -w attosoc.ncd -g UnconstrainedPins:Allow +trce attosoc.ncd -v 10 + +netgen -sim -ofmt vhdl attosoc.ncd -w attosoc_pnr.vhd +ghdl -c -fexplicit --no-vital-checks --ieee=synopsys -Pxilinx-ise attosoc_tb.vhd attosoc_pnr.vhd -r testbench diff --git a/xc7/firmware_fast.hex b/xc7/firmware_fast.hex new file mode 100644 index 00000000..bf6fe43c --- /dev/null +++ b/xc7/firmware_fast.hex @@ -0,0 +1,6 @@ +@00000000 +13 04 20 00 B7 04 00 02 13 04 14 00 13 74 F4 0F +13 09 20 00 63 5E 89 00 13 05 04 00 93 05 09 00 +EF 00 80 01 63 08 05 00 13 09 19 00 6F F0 9F FE +23 A0 84 00 6F F0 5F FD 93 02 10 00 33 05 B5 40 +E3 5E 55 FE 67 80 00 00 diff --git a/xc7/firmware.hex b/xc7/firmware_slow.hex similarity index 100% rename from xc7/firmware.hex rename to xc7/firmware_slow.hex From ba646ac8c47ab74c5509855e45be611b039ad083 Mon Sep 17 00:00:00 2001 From: Eddie Hung Date: Thu, 27 Dec 2018 23:49:16 -0800 Subject: [PATCH 174/174] Update README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 5b79d1fb..5733a40d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ nextpnr -- a portable FPGA place and route tool =============================================== +*** +### NB: This nextpnr-xc7 branch is *unofficial*, *very* proof-of-concept, *very* experimental, *very* unoptimised, and is provided with *no support whatsoever*. Use at your own risk! +#### It leverages a [torc](https://github.com/torc-isi/torc) fork with minimal changes (those necessary to support building on later versions of gcc) to target XDL-compatible devices. +### Note that torc is licensed under GPLv3 which differs from nextpnr's ISC license, thus please respect the limitations imposed by both licenses. +Currently, only LUT1-6, IOB, BUFGCTRL, MMCME2_ADV are supported for xc7z020 and xc7vx680t (but trivial to add others). +The following example shell scripts are available: +* blinky.sh -- generates blinky.bit that flashes (with a delay) the 4 LEDs on a ZYBO Z7 +* blinky_sim.sh -- post place-and-route simulation, without any delays (requires [GHDL](https://github.com/ghdl/ghdl)) +* picorv32.sh -- just places-and-routes picorv32.ncd (no testbench) +* attosoc.sh -- generates attosoc.bit of a self-stimulating picorv32 device that displays (with a delay) prime numbers to the LEDs -- when testing on hardware, consider using a PLL (MMCM) to meet timing +* attosoc_sim.sh -- post place-and-route simulation of a self-stimulating picorv32 device, without any delays (requires [GHDL](https://github.com/ghdl/ghdl)) +*** + nextpnr aims to be a vendor neutral, timing driven, FOSS FPGA place and route tool.