diff options
Diffstat (limited to 'ice40/arch.cc')
-rw-r--r-- | ice40/arch.cc | 215 |
1 files changed, 197 insertions, 18 deletions
diff --git a/ice40/arch.cc b/ice40/arch.cc index ada78020..d536ad35 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -19,15 +19,17 @@ */ #include <algorithm> +#include <boost/iostreams/device/mapped_file.hpp> #include <cmath> #include "cells.h" #include "gfx.h" #include "log.h" #include "nextpnr.h" #include "placer1.h" +#include "placer_heap.h" #include "router1.h" +#include "timing_opt.h" #include "util.h" - NEXTPNR_NAMESPACE_BEGIN // ----------------------------------------------------------------------- @@ -47,9 +49,39 @@ static const ChipInfoPOD *get_chip_info(const RelPtr<ChipInfoPOD> *ptr) { return void load_chipdb(); #endif +#if defined(EXTERNAL_CHIPDB_ROOT) +const char *chipdb_blob_384 = nullptr; +const char *chipdb_blob_1k = nullptr; +const char *chipdb_blob_5k = nullptr; +const char *chipdb_blob_u4k = nullptr; +const char *chipdb_blob_8k = nullptr; + +boost::iostreams::mapped_file_source blob_files[5]; + +const char *mmap_file(int index, const char *filename) +{ + try { + blob_files[index].open(filename); + if (!blob_files[index].is_open()) + log_error("Unable to read chipdb %s\n", filename); + return (const char *)blob_files[index].data(); + } catch (...) { + log_error("Unable to read chipdb %s\n", filename); + } +} + +void load_chipdb() +{ + chipdb_blob_384 = mmap_file(0, EXTERNAL_CHIPDB_ROOT "/ice40/chipdb-384.bin"); + chipdb_blob_1k = mmap_file(1, EXTERNAL_CHIPDB_ROOT "/ice40/chipdb-1k.bin"); + chipdb_blob_5k = mmap_file(2, EXTERNAL_CHIPDB_ROOT "/ice40/chipdb-5k.bin"); + chipdb_blob_u4k = mmap_file(3, EXTERNAL_CHIPDB_ROOT "/ice40/chipdb-u4k.bin"); + chipdb_blob_8k = mmap_file(4, EXTERNAL_CHIPDB_ROOT "/ice40/chipdb-8k.bin"); +} +#endif Arch::Arch(ArchArgs args) : args(args) { -#if defined(_MSC_VER) +#if defined(_MSC_VER) || defined(EXTERNAL_CHIPDB_ROOT) load_chipdb(); #endif @@ -70,6 +102,9 @@ Arch::Arch(ArchArgs args) : args(args) } else if (args.type == ArchArgs::UP5K) { fast_part = false; chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_5k)); + } else if (args.type == ArchArgs::U4K) { + fast_part = false; + chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_u4k)); } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { fast_part = args.type == ArchArgs::HX8K; chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_8k)); @@ -114,6 +149,8 @@ std::string Arch::getChipName() const return "Lattice HX1K"; } else if (args.type == ArchArgs::UP5K) { return "Lattice UP5K"; + } else if (args.type == ArchArgs::U4K) { + return "Lattice U4K"; } else if (args.type == ArchArgs::LP8K) { return "Lattice LP8K"; } else if (args.type == ArchArgs::HX8K) { @@ -136,6 +173,8 @@ IdString Arch::archArgsToId(ArchArgs args) const return id("hx1k"); if (args.type == ArchArgs::UP5K) return id("up5k"); + if (args.type == ArchArgs::U4K) + return id("u4k"); if (args.type == ArchArgs::LP8K) return id("lp8k"); if (args.type == ArchArgs::HX8K) @@ -593,26 +632,30 @@ std::vector<GroupId> 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) { - if (driver.cell->constr_abs_z && driver.cell->constr_z < 7) + if (driver.port == id_COUT) { + NPNR_ASSERT(sink.port == id_CIN || sink.port == id_I3); + NPNR_ASSERT(driver.cell->constr_abs_z); + bool cin = sink.port == id_CIN; + bool same_y = driver.cell->constr_z < 7; + if (cin && same_y) budget = 0; else { - NPNR_ASSERT(driver.cell->constr_z == 7); switch (args.type) { #ifndef ICE40_HX1K_ONLY case ArchArgs::HX8K: #endif case ArchArgs::HX1K: - budget = 190; + budget = cin ? 190 : (same_y ? 260 : 560); break; #ifndef ICE40_HX1K_ONLY case ArchArgs::LP384: case ArchArgs::LP1K: case ArchArgs::LP8K: - budget = 290; + budget = cin ? 290 : (same_y ? 380 : 670); break; case ArchArgs::UP5K: - budget = 560; + case ArchArgs::U4K: + budget = cin ? 560 : (same_y ? 660 : 1220); break; #endif default: @@ -626,7 +669,28 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay // ----------------------------------------------------------------------- -bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); } +bool Arch::place() +{ + std::string placer = str_or_default(settings, id("placer"), defaultPlacer); + if (placer == "heap") { + PlacerHeapCfg cfg(getCtx()); + cfg.ioBufTypes.insert(id_SB_IO); + if (!placer_heap(getCtx(), cfg)) + return false; + } else if (placer == "sa") { + if (!placer1(getCtx(), Placer1Cfg(getCtx()))) + return false; + } else { + log_error("iCE40 architecture does not support placer '%s'\n", placer.c_str()); + } + if (bool_or_default(settings, id("opt_timing"), false)) { + TimingOptCfg tocfg(getCtx()); + tocfg.cellTypes.insert(id_ICESTORM_LC); + return timing_opt(getCtx(), tocfg); + } else { + return true; + } +} bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); } @@ -855,6 +919,17 @@ std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { + if (cell->type == id_ICESTORM_LC && cell->lcInfo.dffEnable) { + if (toPort == id_O) + return false; + } else if (cell->type == id_ICESTORM_RAM || cell->type == id_ICESTORM_SPRAM) { + return false; + } + return getCellDelayInternal(cell, fromPort, toPort, delay); +} + +bool Arch::getCellDelayInternal(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) { @@ -923,13 +998,37 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in return TMG_REGISTER_INPUT; } } else if (cell->type == id_SB_IO) { - if (port == id_D_IN_0 || port == id_D_IN_1) + if (port == id_INPUT_CLK || port == id_OUTPUT_CLK) + return TMG_CLOCK_INPUT; + if (port == id_CLOCK_ENABLE) { + clockInfoCount = 2; + return TMG_REGISTER_INPUT; + } + if ((port == id_D_IN_0 && !(cell->ioInfo.pintype & 0x1)) || port == id_D_IN_1) { + clockInfoCount = 1; + return TMG_REGISTER_OUTPUT; + } else if (port == id_D_IN_0) { return TMG_STARTPOINT; - if (port == id_D_OUT_0 || port == id_D_OUT_1 || port == id_OUTPUT_ENABLE) - return TMG_ENDPOINT; + } + if (port == id_D_OUT_0 || port == id_D_OUT_1) { + if ((cell->ioInfo.pintype & 0xC) == 0x8) { + return TMG_ENDPOINT; + } else { + clockInfoCount = 1; + return TMG_REGISTER_INPUT; + } + } + if (port == id_OUTPUT_ENABLE) { + if ((cell->ioInfo.pintype & 0x18) == 0x18) { + return TMG_REGISTER_INPUT; + } else { + return TMG_ENDPOINT; + } + } + return TMG_IGNORE; } else if (cell->type == id_ICESTORM_PLL) { - if (port == id_PLLOUT_A || port == id_PLLOUT_B) + if (port == id_PLLOUT_A || port == id_PLLOUT_B || port == id_PLLOUT_A_GLOBAL || port == id_PLLOUT_B_GLOBAL) return TMG_GEN_CLOCK; return TMG_IGNORE; } else if (cell->type == id_ICESTORM_LFOSC) { @@ -942,7 +1041,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in return TMG_IGNORE; } else if (cell->type == id_SB_GB) { if (port == id_GLOBAL_BUFFER_OUTPUT) - return TMG_COMB_OUTPUT; + return cell->gbInfo.forPadIn ? TMG_GEN_CLOCK : TMG_COMB_OUTPUT; return TMG_COMB_INPUT; } else if (cell->type == id_SB_WARMBOOT) { return TMG_ENDPOINT; @@ -954,6 +1053,16 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in if (port == id_CLK || port == id_CLOCK) return TMG_CLOCK_INPUT; return TMG_IGNORE; + } else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) { + if (port == this->id("SBCLKI")) + return TMG_CLOCK_INPUT; + + clockInfoCount = 1; + + if (cell->ports.at(port).type == PORT_OUT) + return TMG_REGISTER_OUTPUT; + else + return TMG_REGISTER_INPUT; } log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this), cell->name.c_str(this)); } @@ -965,10 +1074,23 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port info.clock_port = id_CLK; info.edge = cell->lcInfo.negClk ? FALLING_EDGE : RISING_EDGE; if (port == id_O) { - bool has_clktoq = getCellDelay(cell, id_CLK, id_O, info.clockToQ); + bool has_clktoq = getCellDelayInternal(cell, id_CLK, id_O, info.clockToQ); NPNR_ASSERT(has_clktoq); } else { - info.setup.delay = 100; + if (port == id_I0 || port == id_I1 || port == id_I2 || port == id_I3) { + DelayInfo dlut; + bool has_ld = getCellDelayInternal(cell, port, id_O, dlut); + NPNR_ASSERT(has_ld); + if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP8K || args.type == ArchArgs::LP384) { + info.setup.delay = 30 + dlut.delay; + } else if (args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K) { // XXX verify u4k + info.setup.delay = dlut.delay - 50; + } else { + info.setup.delay = 20 + dlut.delay; + } + } else { + info.setup.delay = 100; + } info.hold.delay = 0; } } else if (cell->type == id_ICESTORM_RAM) { @@ -980,23 +1102,69 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port info.edge = bool_or_default(cell->params, id("NEG_CLK_W")) ? FALLING_EDGE : RISING_EDGE; } if (cell->ports.at(port).type == PORT_OUT) { - bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ); + bool has_clktoq = getCellDelayInternal(cell, info.clock_port, port, info.clockToQ); NPNR_ASSERT(has_clktoq); } else { info.setup.delay = 100; info.hold.delay = 0; } + } else if (cell->type == id_SB_IO) { + delay_t io_setup = 80, io_clktoq = 140; + if (args.type == ArchArgs::LP1K || args.type == ArchArgs::LP8K || args.type == ArchArgs::LP384) { + io_setup = 115; + io_clktoq = 210; + } else if (args.type == ArchArgs::UP5K || args.type == ArchArgs::U4K) { + io_setup = 205; + io_clktoq = 1005; + } + if (port == id_CLOCK_ENABLE) { + info.clock_port = (index == 1) ? id_OUTPUT_CLK : id_INPUT_CLK; + info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; + info.setup.delay = io_setup; + info.hold.delay = 0; + } else if (port == id_D_OUT_0 || port == id_OUTPUT_ENABLE) { + info.clock_port = id_OUTPUT_CLK; + info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; + info.setup.delay = io_setup; + info.hold.delay = 0; + } else if (port == id_D_OUT_1) { + info.clock_port = id_OUTPUT_CLK; + info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE; + info.setup.delay = io_setup; + info.hold.delay = 0; + } else if (port == id_D_IN_0) { + info.clock_port = id_INPUT_CLK; + info.edge = cell->ioInfo.negtrig ? FALLING_EDGE : RISING_EDGE; + info.clockToQ.delay = io_clktoq; + } else if (port == id_D_IN_1) { + info.clock_port = id_INPUT_CLK; + info.edge = cell->ioInfo.negtrig ? RISING_EDGE : FALLING_EDGE; + info.clockToQ.delay = io_clktoq; + } else { + NPNR_ASSERT_FALSE("no clock data for IO cell port"); + } } else if (cell->type == id_ICESTORM_DSP || cell->type == id_ICESTORM_SPRAM) { info.clock_port = cell->type == id_ICESTORM_SPRAM ? id_CLOCK : id_CLK; info.edge = RISING_EDGE; if (cell->ports.at(port).type == PORT_OUT) { - bool has_clktoq = getCellDelay(cell, info.clock_port, port, info.clockToQ); + bool has_clktoq = getCellDelayInternal(cell, info.clock_port, port, info.clockToQ); if (!has_clktoq) info.clockToQ.delay = 100; } else { info.setup.delay = 100; info.hold.delay = 0; } + } else if (cell->type == id_SB_I2C || cell->type == id_SB_SPI) { + info.clock_port = this->id("SBCLKI"); + info.edge = RISING_EDGE; + if (cell->ports.at(port).type == PORT_OUT) { + /* Dummy number */ + info.clockToQ.delay = 1500; + } else { + /* Dummy number */ + info.setup.delay = 1500; + info.hold.delay = 0; + } } else { NPNR_ASSERT_FALSE("unhandled cell type in getPortClockingInfo"); } @@ -1053,9 +1221,20 @@ void Arch::assignCellInfo(CellInfo *cell) } else if (cell->type == id_SB_IO) { cell->ioInfo.lvds = str_or_default(cell->params, id_IO_STANDARD, "SB_LVCMOS") == "SB_LVDS_INPUT"; cell->ioInfo.global = bool_or_default(cell->attrs, this->id("GLOBAL")); + cell->ioInfo.pintype = int_or_default(cell->params, this->id("PIN_TYPE")); + cell->ioInfo.negtrig = bool_or_default(cell->params, this->id("NEG_TRIGGER")); + } else if (cell->type == id_SB_GB) { cell->gbInfo.forPadIn = bool_or_default(cell->attrs, this->id("FOR_PAD_IN")); } } +const std::string Arch::defaultPlacer = "sa"; + +const std::vector<std::string> Arch::availablePlacers = {"sa", +#ifdef WITH_HEAP + "heap" +#endif +}; + NEXTPNR_NAMESPACE_END |