Rip out ice40 stuff, put xc7z020 in
This commit is contained in:
parent
a0d72a6f8e
commit
6425032ec4
126
xc7/arch.cc
126
xc7/arch.cc
@ -41,105 +41,42 @@ void IdString::initialize_arch(const BaseCtx *ctx)
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static const ChipInfoPOD *get_chip_info(const RelPtr<ChipInfoPOD> *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<const RelPtr<ChipInfoPOD> *>(chipdb_blob_1k));
|
||||
if (args.type == ArchArgs::XC7Z020) {
|
||||
//chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(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<const RelPtr<ChipInfoPOD> *>(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<const RelPtr<ChipInfoPOD> *>(chipdb_blob_1k));
|
||||
} 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::LP8K || args.type == ArchArgs::HX8K) {
|
||||
fast_part = args.type == ArchArgs::HX8K;
|
||||
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(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<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) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
11
xc7/arch.h
11
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
|
||||
|
999
xc7/bitstream.cc
999
xc7/bitstream.cc
@ -1,999 +0,0 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
* Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com>
|
||||
*
|
||||
* 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 <cctype>
|
||||
#include <vector>
|
||||
#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<int8_t, int8_t, int8_t> 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<std::vector<int8_t>> &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<std::vector<int8_t>> &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<std::vector<int8_t>> &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<std::vector<std::vector<std::vector<int8_t>>>> 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<std::pair<std::string, int>> ¶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<bool> 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<int, int> &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<int> 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<int8_t>(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<bool> 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<Loc> sb_io_used_by_pll;
|
||||
std::unordered_set<Loc> 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<bool> lc(20, false);
|
||||
|
||||
// Discover permutation
|
||||
std::unordered_map<int, int> input_perm;
|
||||
std::set<int> 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<std::pair<std::string, int>> 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<std::pair<std::string, int>> 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<std::pair<std::string, int>> 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<int> 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<bool> 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<int, int, int> 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<NetInfo> created_net = std::unique_ptr<NetInfo>(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<int8_t>(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<bool> 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<CellInfo> 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<CellInfo> 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<CellInfo> 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<CellInfo> 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<CellInfo> 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<CellInfo> 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<CellInfo> 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
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
*
|
||||
* 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 <iostream>
|
||||
#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
|
128
xc7/delay.cc
128
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
|
||||
|
@ -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 $<TARGET_OBJECTS:ice40_chipdb> ${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 $<TARGET_OBJECTS:ice40_chipdb>)
|
||||
endforeach (target)
|
||||
endforeach (dev)
|
||||
endif()
|
125
xc7/main.cc
125
xc7/main.cc
@ -21,7 +21,6 @@
|
||||
#ifdef MAIN_EXECUTABLE
|
||||
|
||||
#include <fstream>
|
||||
#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<Context> 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<std::string>(), "set device package");
|
||||
specific.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
||||
specific.add_options()("asc", po::value<std::string>(), "asc bitstream file to write");
|
||||
specific.add_options()("read", po::value<std::string>(), "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<std::string>(), "set device package");
|
||||
// specific.add_options()("pcf", po::value<std::string>(), "PCF constraints file to ingest");
|
||||
specific.add_options()("xdl", po::value<std::string>(), "XDL file to write");
|
||||
// specific.add_options()("read", po::value<std::string>(), "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::string>();
|
||||
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::string>();
|
||||
// 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::string>();
|
||||
std::ofstream f(filename);
|
||||
write_asc(ctx, f);
|
||||
}
|
||||
// if (vm.count("tmfuzz"))
|
||||
// ice40DelayFuzzerMain(ctx);
|
||||
}
|
||||
|
||||
void Ice40CommandHandler::setupArchContext(Context *ctx)
|
||||
std::unique_ptr<Context> Xc7CommandHandler::createContext()
|
||||
{
|
||||
if (vm.count("tmfuzz"))
|
||||
ice40DelayFuzzerMain(ctx);
|
||||
|
||||
if (vm.count("read")) {
|
||||
std::string filename = vm["read"].as<std::string>();
|
||||
std::ifstream f(filename);
|
||||
if (!read_asc(ctx, f))
|
||||
log_error("Loading ASC failed.\n");
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> 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<std::string>();
|
||||
// if (vm.count("package"))
|
||||
// chipArgs.package = vm["package"].as<std::string>();
|
||||
|
||||
return std::unique_ptr<Context>(new Context(chipArgs));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
Ice40CommandHandler handler(argc, argv);
|
||||
Xc7CommandHandler handler(argc, argv);
|
||||
return handler.exec();
|
||||
}
|
||||
|
||||
|
@ -38,23 +38,8 @@ std::unique_ptr<Context> ProjectHandler::createContext(pt::ptree &root)
|
||||
{
|
||||
ArchArgs chipArgs;
|
||||
std::string arch_type = root.get<std::string>("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<std::string>("project.arch.package");
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user