Adding NanoXplore NG-Ultra support (#1397)
* ng-ultra: new architecture * Implementation as in D2 deliverable * Support for nxdesignsuite-24.0.0.0-20240429T102300 * Save memory by directly outputing json * Add support for bidirectional IOs * cleanup * Create BFRs properly * Add IOM insertion * Cleanup * Block certain pips depending of DDFR mode * Add LUT bypass to improve routability * Add bypass for CSC mode of GCK * Fix IOM case * Initial memory support * Better RF/XRF handling * fix * RF placement and legalization * Disconnect non available ports for NX_RAM * cleanup * Add RFB/RAM context support for latest release * Remove ports that must not be used * Proper port used only on RFB * Add structure for clock sinks * Use cell type where applicable * Add clock sinks for other cell types * Validation check fixes * Commented too restrictive placement * Added more crossbar wire type * Hande IO termination input * Fail early due to NX tools limitation for now * Validations and fixes for RAM I/Os * Fix for latest version of tools * Use ctx->idf where applicable * warn if RAM ports are not actually used * Fix IOM packing * Fix CY packing * Change how constants are handled on CY * Post placement optimization for CY * Address comments for PR * pack and export GCK, WFG and PLL * Cover more global routing cases * Constraing to location if provided * Place at LOC * Pack and export DSP * wip * wip * notes * wip * wip * Validate DSPs * DSP cascading * Check mandatory parameters for DSP * existing gck * wip * export all the rest for bitstream * CDC packing * add more sinks * place FIFO * map rest of FIFO ports * enable pll by default * cleanup * Initial XLUT support * Fix statistics * Properly duplicate GCKs * RRSTO and WRSTO are not used on XFIFO * Fix for latest version of JSON format * Implement GCK limitations * cleanup * cleanup * Add more signals and use lowskew name * cleanup code a bit * Fix wfb * detect cascaded GCKs * Handle DFR * Route dfr clock properly * Cleanup * Cleanup bitstream code * Review issues addressed * Move helper routines * Expose private members for unit tests * cleanup * remove scale factor * make all location helper arrays static * Addressed review comments * Support post-routing CSC and SCC * Support NX_BFF * Place CSS and SCC only on allowed locations * Support latest Impulse * ng_ultra: Expand bounding box further for left-edge IO Signed-off-by: gatecat <gatecat@ds0.me> * Export all IO parameters in bitstream * Handle new CSV order or parameters and additional validation * Add some more undocumented values for CSV * Support for old and new CSV formats * Initial DDFR support * Display warning message once per file * Address review issues * Fix crash on memory access * Make boundbox fit NG-Ultra internal design * Update attributes after dff rewrite * Implement basic NG-Ultra LUT-DFF unit tests * Always use first seen xbar input Signed-off-by: gatecat <gatecat@ds0.me> * Simplified crossbar pip detection * Change order to prevent issues with some unconnected constants * Pack LUT and multiple DFF in stripe * Place DFF chains * Improve large DFF chains * Rename to pack_dff_chains * Better use XLUTs when possible * pack output DFF together with XLUT * option to disable XLUT optimiziations * Make more optimizations optional * fix to use pre-increment * GCK for lowskew signals * Bugfix for nets that are not part of lowskew network * Fix bitstream export for PLL cell * Remove separate route lowskew * Allow WFG mode 2 * Merge inverter into GCK * Add CSC per TILE when needed * Improve reusage of existing cell for CSC * Take preferred CSC * Cleanup * When in place CSC size not important * Cleanup * Reset and Load restriction * make csc optimisation optional * Proper count for IO resources * Detect when there is no next cell for DSP chain * Do not incorporate loops in XLUT * Check if output exists * Update copyright for delivery * Make building NG-Ultra chip database optional, follow filename convention * Ported drawing code to new API * Update expandBoundingBox for NG-Ultra * Copyright and license update * Add README information * cleanup and constids * Using ctx->idf where applicable * remove if_using_basecluster * refactor extra data usage * refactor to use create_cell_ptr only * optimized getCSC * optimize critical path a bit * clangformat * disable clangformat where applicable --------- Signed-off-by: gatecat <gatecat@ds0.me> Co-authored-by: Lofty <dan.ravensloft@gmail.com> Co-authored-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
5eaa1b3f1f
commit
5a807110de
@ -334,6 +334,7 @@ foreach (family ${ARCH})
|
|||||||
|
|
||||||
if (BUILD_TESTS)
|
if (BUILD_TESTS)
|
||||||
set(family_targets ${family_targets} ${PROGRAM_PREFIX}nextpnr-${family}-test)
|
set(family_targets ${family_targets} ${PROGRAM_PREFIX}nextpnr-${family}-test)
|
||||||
|
set(family_test_targets ${PROGRAM_PREFIX}nextpnr-${family}-test)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Include the family-specific CMakeFile
|
# Include the family-specific CMakeFile
|
||||||
|
13
README.md
13
README.md
@ -9,6 +9,7 @@ Currently nextpnr supports:
|
|||||||
* Lattice ECP5 devices supported by [Project Trellis](https://github.com/YosysHQ/prjtrellis)
|
* Lattice ECP5 devices supported by [Project Trellis](https://github.com/YosysHQ/prjtrellis)
|
||||||
* Lattice Nexus devices supported by [Project Oxide](https://github.com/gatecat/prjoxide)
|
* Lattice Nexus devices supported by [Project Oxide](https://github.com/gatecat/prjoxide)
|
||||||
* Gowin LittleBee devices supported by [Project Apicula](https://github.com/YosysHQ/apicula)
|
* Gowin LittleBee devices supported by [Project Apicula](https://github.com/YosysHQ/apicula)
|
||||||
|
* NanoXplore NG-Ultra devices supported by [Project Beyond](https://github.com/yosyshq-GmbH/prjbeyond-db)
|
||||||
* *(experimental)* Cyclone V devices supported by [Mistral](https://github.com/Ravenslofty/mistral)
|
* *(experimental)* Cyclone V devices supported by [Mistral](https://github.com/Ravenslofty/mistral)
|
||||||
* *(experimental)* Lattice MachXO2 devices supported by [Project Trellis](https://github.com/YosysHQ/prjtrellis)
|
* *(experimental)* Lattice MachXO2 devices supported by [Project Trellis](https://github.com/YosysHQ/prjtrellis)
|
||||||
* *(experimental)* a "generic" back-end for user-defined architectures
|
* *(experimental)* a "generic" back-end for user-defined architectures
|
||||||
@ -146,6 +147,18 @@ sudo make install
|
|||||||
|
|
||||||
- Examples of the Gowin flow for a range of boards can be found in the [Project Apicula Examples](https://github.com/YosysHQ/apicula/tree/master/examples).
|
- Examples of the Gowin flow for a range of boards can be found in the [Project Apicula Examples](https://github.com/YosysHQ/apicula/tree/master/examples).
|
||||||
|
|
||||||
|
#### ng-ultra
|
||||||
|
|
||||||
|
For NanoXplore NG-Ultra support, clone [Project Beyond DB](https://github.com/yosyshq-GmbH/prjbeyond-db) repo
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake . -DARCH="himbaechel" -DHIMBAECHEL_PRJBEYOND_DB=/path/to/prjbeyond-db -DHIMBAECHEL_NGULTRA_DEVICES=ng-ultra
|
||||||
|
make -j$(nproc)
|
||||||
|
sudo make install
|
||||||
|
```
|
||||||
|
|
||||||
|
*Please note that binary bitstream creation requires Impulse tool from NanoXplore.*
|
||||||
|
|
||||||
### GUI
|
### GUI
|
||||||
|
|
||||||
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5 and OpenGL are available:
|
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5 and OpenGL are available:
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
set(HIMBAECHEL_UARCHES "example;gowin;xilinx")
|
set(HIMBAECHEL_UARCHES "example;gowin;xilinx;ng-ultra")
|
||||||
foreach(uarch ${HIMBAECHEL_UARCHES})
|
foreach(uarch ${HIMBAECHEL_UARCHES})
|
||||||
add_subdirectory(${family}/uarch/${uarch})
|
add_subdirectory(${family}/uarch/${uarch})
|
||||||
aux_source_directory(${family}/uarch/${uarch} HM_UARCH_FILES)
|
aux_source_directory(${family}/uarch/${uarch} HM_UARCH_FILES)
|
||||||
foreach(target ${family_targets})
|
foreach(target ${family_targets})
|
||||||
target_sources(${target} PRIVATE ${HM_UARCH_FILES})
|
target_sources(${target} PRIVATE ${HM_UARCH_FILES})
|
||||||
endforeach()
|
endforeach()
|
||||||
|
if (BUILD_TESTS)
|
||||||
|
foreach(target ${family_test_targets})
|
||||||
|
aux_source_directory(${family}/uarch/${uarch}/tests/ HM_UARCH_TEST_FILES)
|
||||||
|
target_sources(${target} PRIVATE ${HM_UARCH_TEST_FILES})
|
||||||
|
endforeach()
|
||||||
|
endif()
|
||||||
endforeach(uarch)
|
endforeach(uarch)
|
||||||
|
38
himbaechel/uarch/ng-ultra/CMakeLists.txt
Normal file
38
himbaechel/uarch/ng-ultra/CMakeLists.txt
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
message(STATUS "Configuring Himbaechel-NG-ULTRA uarch")
|
||||||
|
cmake_minimum_required(VERSION 3.5)
|
||||||
|
project(himbaechel-ng-ultra-chipdb NONE)
|
||||||
|
|
||||||
|
set(ALL_HIMBAECHEL_NGULTRA_DEVICES ng-ultra)
|
||||||
|
set(HIMBAECHEL_NGULTRA_DEVICES "" CACHE STRING
|
||||||
|
"Include support for these NG-Ultra devices (available: ${ALL_HIMBAECHEL_NGULTRA_DEVICES})")
|
||||||
|
message(STATUS "Enabled Himbaechel-NG-Ultra devices: ${HIMBAECHEL_NGULTRA_DEVICES}")
|
||||||
|
set(HIMBAECHEL_PRJBEYOND_DB "" CACHE STRING
|
||||||
|
"Path to a Project Beyond database")
|
||||||
|
|
||||||
|
set(chipdb_binaries)
|
||||||
|
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/share/himbaechel/ng-ultra)
|
||||||
|
foreach(device ${HIMBAECHEL_NGULTRA_DEVICES})
|
||||||
|
if("${HIMBAECHEL_PRJBEYOND_DB}" STREQUAL "")
|
||||||
|
message(SEND_ERROR "HIMBAECHEL_PRJBEYOND_DB must be set to a prjbeyond database checkout")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(device_bba ${CMAKE_BINARY_DIR}/share/himbaechel/ng-ultra/chipdb-${device}.bba)
|
||||||
|
set(device_bin ${CMAKE_BINARY_DIR}/share/himbaechel/ng-ultra/chipdb-${device}.bin)
|
||||||
|
string(TOUPPER ${device} upcase_device)
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${device_bin}
|
||||||
|
COMMAND ${Python3_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/gen/arch_gen.py --db ${HIMBAECHEL_PRJBEYOND_DB} --device ${upcase_device} --bba ${device_bba}
|
||||||
|
COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${device_bba} ${device_bin}.new
|
||||||
|
# atomically update
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E rename ${device_bin}.new ${device_bin}
|
||||||
|
DEPENDS
|
||||||
|
bbasm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/gen/arch_gen.py
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/constids.inc
|
||||||
|
VERBATIM)
|
||||||
|
list(APPEND chipdb_binaries ${device_bin})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
add_custom_target(chipdb-himbaechel-ng-ultra ALL DEPENDS ${chipdb_binaries})
|
||||||
|
install(DIRECTORY ${CMAKE_BINARY_DIR}/share/himbaechel/ng-ultra/ DESTINATION share/nextpnr/himbaechel/ng-ultra
|
||||||
|
PATTERN "*.bba" EXCLUDE)
|
705
himbaechel/uarch/ng-ultra/bitstream.cc
Normal file
705
himbaechel/uarch/ng-ultra/bitstream.cc
Normal file
@ -0,0 +1,705 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "extra_data.h"
|
||||||
|
#include "himbaechel_api.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "ng_ultra.h"
|
||||||
|
|
||||||
|
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"
|
||||||
|
#include "himbaechel_constids.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct BitstreamJsonBackend
|
||||||
|
{
|
||||||
|
Context *ctx;
|
||||||
|
NgUltraImpl *uarch;
|
||||||
|
std::ostream &out;
|
||||||
|
bool first_instance;
|
||||||
|
|
||||||
|
BitstreamJsonBackend(Context *ctx, NgUltraImpl *uarch, std::ostream &out) : ctx(ctx), uarch(uarch), out(out) {};
|
||||||
|
|
||||||
|
std::string get_string(std::string str)
|
||||||
|
{
|
||||||
|
std::string newstr = "\"";
|
||||||
|
for (char c : str) {
|
||||||
|
if (c == '\\')
|
||||||
|
newstr += c;
|
||||||
|
newstr += c;
|
||||||
|
}
|
||||||
|
return newstr + "\"";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string update_name(std::string tile, std::string name)
|
||||||
|
{
|
||||||
|
if (boost::starts_with(tile, "FENCE[")) {
|
||||||
|
char last = tile[tile.size() - 2];
|
||||||
|
switch (last) {
|
||||||
|
case 'T':
|
||||||
|
case 'B':
|
||||||
|
case 'U':
|
||||||
|
case 'L':
|
||||||
|
std::string loc = tile.substr(tile.find("[") + 1, tile.find("x") - tile.find("["));
|
||||||
|
boost::replace_all(name, "1x", loc);
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (boost::starts_with(tile, "TILE[") && boost::algorithm::contains(name, ".FE")) {
|
||||||
|
std::string last = name.substr(name.rfind('.') + 1);
|
||||||
|
if (last[0] == 'D') {
|
||||||
|
boost::replace_all(name, ".D", ".");
|
||||||
|
boost::replace_all(name, ".FE", ".DFF");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (last == "L" || last == "R") {
|
||||||
|
boost::replace_all(name, ".FE", ".DFF");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (last == "CK") {
|
||||||
|
boost::replace_all(name, ".FE", ".DFF");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (last[0] == 'L') {
|
||||||
|
boost::replace_all(name, ".L", ".");
|
||||||
|
boost::replace_all(name, ".FE", ".LUT");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
if (last[0] == 'P') {
|
||||||
|
boost::replace_all(name, ".PI", ".I");
|
||||||
|
boost::replace_all(name, ".FE", ".LUT");
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_net(std::set<std::string> &nets, std::string src_tile, std::string src_name, std::string dst_tile,
|
||||||
|
std::string dst_name, IdString src_type, IdString dst_type)
|
||||||
|
{
|
||||||
|
if (src_type.in(ctx->id("LUT_PERMUTATION_WIRE"), ctx->id("MUX_WIRE"), ctx->id("INTERCONNECT_INPUT")))
|
||||||
|
return;
|
||||||
|
if (boost::starts_with(src_type.c_str(ctx), "CROSSBAR_") && boost::ends_with(src_type.c_str(ctx), "INPUT_WIRE"))
|
||||||
|
return;
|
||||||
|
if (dst_type == ctx->id("MUX_WIRE"))
|
||||||
|
dst_name = dst_name.substr(0, dst_name.rfind('.'));
|
||||||
|
src_name = update_name(src_tile, src_name);
|
||||||
|
dst_name = update_name(dst_tile, dst_name);
|
||||||
|
|
||||||
|
nets.emplace(stringf("%s:%s->%s:%s", src_tile.c_str(), src_name.c_str(), dst_tile.c_str(), dst_name.c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string cleanup_name(std::string name)
|
||||||
|
{
|
||||||
|
std::replace(name.begin(), name.end(), '$', '_');
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_nets()
|
||||||
|
{
|
||||||
|
out << "\t\"nets\": {\n";
|
||||||
|
bool first_net = true;
|
||||||
|
for (auto &net : ctx->nets) {
|
||||||
|
NetInfo *ni = net.second.get();
|
||||||
|
if (ni->wires.empty())
|
||||||
|
continue;
|
||||||
|
out << (first_net ? "" : ",\n");
|
||||||
|
first_net = false;
|
||||||
|
out << stringf("\t\t%s: [\n", get_string(cleanup_name(ni->name.c_str(ctx))).c_str());
|
||||||
|
std::set<std::string> nets;
|
||||||
|
for (auto &w : ni->wires) {
|
||||||
|
if (w.second.pip != PipId()) {
|
||||||
|
PipId pip = w.second.pip;
|
||||||
|
auto &pd = chip_pip_info(ctx->chip_info, pip);
|
||||||
|
const auto &extra_data = *uarch->pip_extra_data(pip);
|
||||||
|
WireId swire = ctx->getPipSrcWire(pip);
|
||||||
|
IdString src = ctx->getWireName(swire)[1];
|
||||||
|
IdString src_type = ctx->getWireType(swire);
|
||||||
|
|
||||||
|
IdString src_orig = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name);
|
||||||
|
IdString src_orig_type =
|
||||||
|
IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].wire_type);
|
||||||
|
|
||||||
|
WireId dwire = ctx->getPipDstWire(pip);
|
||||||
|
IdString dst = ctx->getWireName(dwire)[1];
|
||||||
|
IdString dst_type = ctx->getWireType(dwire);
|
||||||
|
|
||||||
|
std::string s_tile_name = uarch->tile_name(swire.tile);
|
||||||
|
std::string tile_name = uarch->tile_name(pip.tile);
|
||||||
|
|
||||||
|
if (src_orig != src)
|
||||||
|
add_net(nets, s_tile_name, src.c_str(ctx), tile_name, src_orig.c_str(ctx), src_type,
|
||||||
|
src_orig_type);
|
||||||
|
if (!extra_data.name ||
|
||||||
|
(extra_data.type != PipExtra::PIP_EXTRA_BYPASS &&
|
||||||
|
extra_data.type != PipExtra::PIP_EXTRA_VIRTUAL && extra_data.type != PipExtra::PIP_EXTRA_MUX))
|
||||||
|
add_net(nets, tile_name, src_orig.c_str(ctx), tile_name, dst.c_str(ctx), src_orig_type,
|
||||||
|
dst_type);
|
||||||
|
} else if (ni->wires.size() == 1) {
|
||||||
|
IdString src = ctx->getWireName(w.first)[1];
|
||||||
|
IdString src_type = ctx->getWireType(w.first);
|
||||||
|
std::string s_tile_name = uarch->tile_name(w.first.tile);
|
||||||
|
for (auto &u : ni->users) {
|
||||||
|
std::string tile_name = uarch->tile_name(u.cell->bel.tile);
|
||||||
|
IdString bel_name = ctx->getBelName(u.cell->bel)[1];
|
||||||
|
add_net(nets, s_tile_name, src.c_str(ctx), tile_name,
|
||||||
|
stringf("%s.%s", bel_name.c_str(ctx), u.port.c_str(ctx)), src_type, src_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool first = true;
|
||||||
|
for (auto &str : nets) {
|
||||||
|
out << (first ? "" : ",\n");
|
||||||
|
out << stringf("\t\t\t%s", get_string(str).c_str());
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
out << "\n\t\t]";
|
||||||
|
}
|
||||||
|
out << "\n\t},\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KeyType>
|
||||||
|
std::string str_or_n_value(const dict<KeyType, Property> &ct, const KeyType &key, std::string def = "N")
|
||||||
|
{
|
||||||
|
auto found = ct.find(key);
|
||||||
|
if (found == ct.end())
|
||||||
|
return def;
|
||||||
|
else {
|
||||||
|
if (!found->second.is_string)
|
||||||
|
log_error("Expecting string value but got integer %d.\n", int(found->second.intval));
|
||||||
|
if (found->second.as_string().empty())
|
||||||
|
return def;
|
||||||
|
return found->second.as_string();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename KeyType>
|
||||||
|
std::string str_or_n_value_lower(const dict<KeyType, Property> &ct, const KeyType &key, std::string def = "N")
|
||||||
|
{
|
||||||
|
auto found = ct.find(key);
|
||||||
|
if (found == ct.end())
|
||||||
|
return def;
|
||||||
|
else {
|
||||||
|
if (!found->second.is_string)
|
||||||
|
log_error("Expecting string value but got integer %d.\n", int(found->second.intval));
|
||||||
|
if (found->second.as_string().empty())
|
||||||
|
return def;
|
||||||
|
std::string tmp = found->second.as_string();
|
||||||
|
boost::algorithm::to_lower(tmp);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename KeyType>
|
||||||
|
std::string extract_bits_or_default(const dict<KeyType, Property> &ct, const KeyType &key, int bits, int def = 0)
|
||||||
|
{
|
||||||
|
Property extr = get_or_default(ct, key, Property()).extract(0, bits);
|
||||||
|
std::string str = extr.str;
|
||||||
|
std::reverse(str.begin(), str.end());
|
||||||
|
return str;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<std::string> config;
|
||||||
|
|
||||||
|
void open_instance(CellInfo *cell, std::string rename = "")
|
||||||
|
{
|
||||||
|
out << stringf("%s", first_instance ? "" : ",\n");
|
||||||
|
first_instance = false;
|
||||||
|
out << stringf("\t\t%s: {\n",
|
||||||
|
get_string(cleanup_name(rename.empty() ? cell->name.c_str(ctx) : rename.c_str())).c_str());
|
||||||
|
std::string tile_name = uarch->tile_name(cell->bel.tile);
|
||||||
|
IdString idx = ctx->getBelName(cell->bel)[1];
|
||||||
|
std::string belname = idx.c_str(ctx);
|
||||||
|
config.clear();
|
||||||
|
out << stringf("\t\t\t\"location\": %s,\n", get_string(tile_name + ":" + belname).c_str());
|
||||||
|
out << stringf("\t\t\t\"type\": %s", get_string(cell->type.c_str(ctx)).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void open_instance_fe(CellInfo *cell, std::string type, std::string replace, std::string postfix = "")
|
||||||
|
{
|
||||||
|
out << stringf("%s", first_instance ? "" : ",\n");
|
||||||
|
first_instance = false;
|
||||||
|
out << stringf("\t\t%s: {\n", get_string(cleanup_name(cell->name.c_str(ctx)) + postfix).c_str());
|
||||||
|
std::string tile_name = uarch->tile_name(cell->bel.tile);
|
||||||
|
IdString idx = ctx->getBelName(cell->bel)[1];
|
||||||
|
std::string belname = idx.c_str(ctx);
|
||||||
|
boost::replace_all(belname, ".FE", replace);
|
||||||
|
config.clear();
|
||||||
|
out << stringf("\t\t\t\"location\": %s,\n", get_string(tile_name + ":" + belname).c_str());
|
||||||
|
out << stringf("\t\t\t\"type\": %s", get_string(type).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_config(std::string name, int val)
|
||||||
|
{
|
||||||
|
config.push_back(stringf("\t\t\t\t%s:%d", get_string(name).c_str(), val));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_config(std::string name, bool val)
|
||||||
|
{
|
||||||
|
config.push_back(stringf("\t\t\t\t%s:%s", get_string(name).c_str(), val ? "true" : "false"));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void add_config(std::string name, std::string val)
|
||||||
|
{
|
||||||
|
config.push_back(stringf("\t\t\t\t%s:%s", get_string(name).c_str(), get_string(val).c_str()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void close_instance()
|
||||||
|
{
|
||||||
|
bool first = true;
|
||||||
|
if (!config.empty())
|
||||||
|
out << ",\n\t\t\t\"config\": {\n";
|
||||||
|
for (auto &str : config) {
|
||||||
|
out << (first ? "" : ",\n");
|
||||||
|
out << str.c_str();
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
if (!config.empty())
|
||||||
|
out << "\n\t\t\t}";
|
||||||
|
out << "\n\t\t}";
|
||||||
|
config.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_iop(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell, str_or_default(cell->params, id_iobname, ""));
|
||||||
|
add_config("location", str_or_default(cell->params, id_location, ""));
|
||||||
|
add_config("differential", str_or_n_value_lower(cell->params, id_differential, "false"));
|
||||||
|
add_config("slewRate", str_or_default(cell->params, id_slewRate, "Medium"));
|
||||||
|
add_config("turbo", str_or_n_value_lower(cell->params, id_turbo, "false"));
|
||||||
|
add_config("weakTermination", str_or_n_value(cell->params, id_weakTermination, "PullUp"));
|
||||||
|
add_config("inputDelayLine", str_or_default(cell->params, id_inputDelayLine, "0"));
|
||||||
|
add_config("outputDelayLine", str_or_default(cell->params, id_outputDelayLine, "0"));
|
||||||
|
add_config("inputSignalSlope", str_or_default(cell->params, id_inputSignalSlope, "0"));
|
||||||
|
add_config("outputCapacity", str_or_default(cell->params, id_outputCapacity, "0"));
|
||||||
|
add_config("standard", str_or_default(cell->params, id_standard, "LVCMOS"));
|
||||||
|
add_config("drive", str_or_default(cell->params, id_drive, "2mA"));
|
||||||
|
add_config("inputDelayOn", str_or_n_value_lower(cell->params, id_inputDelayOn, "false"));
|
||||||
|
add_config("outputDelayOn", str_or_n_value_lower(cell->params, id_outputDelayOn, "false"));
|
||||||
|
add_config("dynDrive", str_or_n_value_lower(cell->params, id_dynDrive, "false"));
|
||||||
|
add_config("dynInput", str_or_n_value_lower(cell->params, id_dynInput, "false"));
|
||||||
|
add_config("dynTerm", str_or_n_value_lower(cell->params, id_dynTerm, "false"));
|
||||||
|
if (cell->type.in(id_OTP, id_ITP, id_IOTP)) {
|
||||||
|
add_config("termination", str_or_n_value(cell->params, id_termination, "0"));
|
||||||
|
add_config("terminationReference", str_or_n_value(cell->params, id_terminationReference, "VT"));
|
||||||
|
}
|
||||||
|
close_instance();
|
||||||
|
std::string tile_name = uarch->tile_name(cell->bel.tile);
|
||||||
|
std::string bank = tile_name.substr(0, tile_name.rfind(':'));
|
||||||
|
if (uarch->bank_voltage.count(bank) == 0) {
|
||||||
|
if (bank == "IOB0" || bank == "IOB1" || bank == "IOB6" || bank == "IOB7")
|
||||||
|
uarch->bank_voltage[bank] = "3.3V";
|
||||||
|
else
|
||||||
|
uarch->bank_voltage[bank] = "1.8V";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_ddfr(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("dff_load", bool_or_default(cell->params, id_dff_load, false));
|
||||||
|
add_config("dff_sync", bool_or_default(cell->params, id_dff_sync, false));
|
||||||
|
add_config("dff_type", bool_or_default(cell->params, id_dff_type, false));
|
||||||
|
add_config("iobname", str_or_default(cell->params, id_iobname, ""));
|
||||||
|
add_config("path", int_or_default(cell->params, id_path, 0));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_dfr(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("data_inv", bool_or_default(cell->params, id_data_inv, false));
|
||||||
|
add_config("dff_edge", bool_or_default(cell->params, id_dff_edge, false));
|
||||||
|
add_config("dff_init", bool_or_default(cell->params, id_dff_init, false));
|
||||||
|
add_config("dff_load", bool_or_default(cell->params, id_dff_load, false));
|
||||||
|
add_config("dff_sync", bool_or_default(cell->params, id_dff_sync, false));
|
||||||
|
add_config("dff_type", bool_or_default(cell->params, id_dff_type, false));
|
||||||
|
add_config("mode", int_or_default(cell->params, id_mode, 3));
|
||||||
|
add_config("iobname", str_or_default(cell->params, id_iobname, ""));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_bfr(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("mode", int_or_default(cell->params, id_mode, 2));
|
||||||
|
add_config("iobname", str_or_default(cell->params, id_iobname, ""));
|
||||||
|
if (cell->params.count(id_data_inv)) {
|
||||||
|
add_config("data_inv", bool_or_default(cell->params, id_data_inv, false));
|
||||||
|
}
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_cy(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("add_carry", int_or_default(cell->params, id_add_carry, 0));
|
||||||
|
add_config("shifter", bool_or_default(cell->params, id_shifter, false));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_fe(CellInfo *cell)
|
||||||
|
{
|
||||||
|
if (bool_or_default(cell->params, id_lut_used)) {
|
||||||
|
open_instance_fe(cell, "LUT", ".LUT");
|
||||||
|
add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
if (bool_or_default(cell->params, id_dff_used)) {
|
||||||
|
std::string subtype = str_or_default(cell->params, id_type, "DFF");
|
||||||
|
open_instance_fe(cell, subtype, ".DFF", "_D");
|
||||||
|
if (subtype == "DFF") {
|
||||||
|
add_config("dff_ctxt", std::to_string(int_or_default(cell->params, id_dff_ctxt, 0)));
|
||||||
|
add_config("dff_edge", bool_or_default(cell->params, id_dff_edge, false));
|
||||||
|
add_config("dff_init", bool_or_default(cell->params, id_dff_init, false));
|
||||||
|
add_config("dff_load", bool_or_default(cell->params, id_dff_load, false));
|
||||||
|
add_config("dff_sync", bool_or_default(cell->params, id_dff_sync, false));
|
||||||
|
add_config("dff_type", bool_or_default(cell->params, id_dff_type, false));
|
||||||
|
}
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_xlut(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("lut_table", extract_bits_or_default(cell->params, id_lut_table, 16));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_iom(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("pads_path", str_or_default(cell->params, id_pads_path, ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_gck(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("inv_in", bool_or_default(cell->params, id_inv_in, false));
|
||||||
|
add_config("inv_out", bool_or_default(cell->params, id_inv_out, false));
|
||||||
|
add_config("std_mode", str_or_default(cell->params, id_std_mode, "BYPASS"));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_wfb(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("delay_on", bool_or_default(cell->params, id_delay_on, false));
|
||||||
|
add_config("delay", int_or_default(cell->params, id_delay, 0));
|
||||||
|
add_config("wfg_edge", bool_or_default(cell->params, id_wfg_edge, false));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_wfg(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("mode", int_or_default(cell->params, id_mode, 0));
|
||||||
|
add_config("delay_on", bool_or_default(cell->params, id_delay_on, false));
|
||||||
|
add_config("delay", int_or_default(cell->params, id_delay, 0));
|
||||||
|
add_config("wfg_edge", bool_or_default(cell->params, id_wfg_edge, false));
|
||||||
|
add_config("pattern", extract_bits_or_default(cell->params, id_pattern, 16));
|
||||||
|
add_config("pattern_end", int_or_default(cell->params, id_pattern_end, 0));
|
||||||
|
add_config("div_ratio", int_or_default(cell->params, id_div_ratio, 0));
|
||||||
|
add_config("div_phase", bool_or_default(cell->params, id_div_phase, false));
|
||||||
|
add_config("reset_on_pll_lock_n", bool_or_default(cell->params, id_reset_on_pll_lock_n, false));
|
||||||
|
add_config("reset_on_pll_locka_n", bool_or_default(cell->params, id_reset_on_pll_locka_n, false));
|
||||||
|
add_config("reset_on_cal_lock_n", bool_or_default(cell->params, id_reset_on_cal_lock_n, false));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_pll(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("clk_outdiv1", extract_bits_or_default(cell->params, id_clk_outdiv1, 3));
|
||||||
|
add_config("clk_outdiv2", extract_bits_or_default(cell->params, id_clk_outdiv2, 3));
|
||||||
|
add_config("clk_outdiv3", extract_bits_or_default(cell->params, id_clk_outdiv3, 3));
|
||||||
|
add_config("clk_outdiv4", extract_bits_or_default(cell->params, id_clk_outdiv4, 3));
|
||||||
|
add_config("clk_outdivd1", extract_bits_or_default(cell->params, id_clk_outdivd1, 4));
|
||||||
|
add_config("clk_outdivd2", extract_bits_or_default(cell->params, id_clk_outdivd2, 4));
|
||||||
|
add_config("clk_outdivd3", extract_bits_or_default(cell->params, id_clk_outdivd3, 4));
|
||||||
|
add_config("clk_outdivd4", extract_bits_or_default(cell->params, id_clk_outdivd4, 4));
|
||||||
|
add_config("clk_outdivd5", extract_bits_or_default(cell->params, id_clk_outdivd5, 4));
|
||||||
|
add_config("use_cal", bool_or_default(cell->params, id_use_cal, false));
|
||||||
|
add_config("clk_cal_sel", extract_bits_or_default(cell->params, id_clk_cal_sel, 2));
|
||||||
|
add_config("pll_odf", extract_bits_or_default(cell->params, id_pll_odf, 2));
|
||||||
|
add_config("pll_lpf_res", extract_bits_or_default(cell->params, id_pll_lpf_res, 4));
|
||||||
|
add_config("pll_lpf_cap", extract_bits_or_default(cell->params, id_pll_lpf_cap, 4));
|
||||||
|
add_config("cal_div", extract_bits_or_default(cell->params, id_cal_div, 4));
|
||||||
|
add_config("cal_delay", extract_bits_or_default(cell->params, id_cal_delay, 6));
|
||||||
|
add_config("use_pll", bool_or_default(cell->params, id_use_pll, true));
|
||||||
|
add_config("ref_intdiv", extract_bits_or_default(cell->params, id_ref_intdiv, 5));
|
||||||
|
add_config("ref_osc_on", bool_or_default(cell->params, id_ref_osc_on, false));
|
||||||
|
add_config("pll_cpump", extract_bits_or_default(cell->params, id_pll_cpump, 4));
|
||||||
|
add_config("pll_lock", extract_bits_or_default(cell->params, id_pll_lock, 4));
|
||||||
|
add_config("ext_fbk_on", bool_or_default(cell->params, id_ext_fbk_on, false));
|
||||||
|
add_config("fbk_intdiv", extract_bits_or_default(cell->params, id_fbk_intdiv, 7));
|
||||||
|
add_config("fbk_delay_on", bool_or_default(cell->params, id_fbk_delay_on, false));
|
||||||
|
add_config("fbk_delay", extract_bits_or_default(cell->params, id_fbk_delay, 6));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_rfb(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
std::string context = str_or_default(cell->params, id_mem_ctxt, "");
|
||||||
|
if (!context.empty())
|
||||||
|
add_config("mem_ctxt", context);
|
||||||
|
add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_ram(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("mcka_edge", bool_or_default(cell->params, id_mcka_edge, false));
|
||||||
|
add_config("mckb_edge", bool_or_default(cell->params, id_mckb_edge, false));
|
||||||
|
add_config("pcka_edge", bool_or_default(cell->params, id_pcka_edge, false));
|
||||||
|
add_config("pckb_edge", bool_or_default(cell->params, id_pckb_edge, false));
|
||||||
|
add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 4));
|
||||||
|
add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 16));
|
||||||
|
std::string context = str_or_default(cell->params, id_mem_ctxt, "");
|
||||||
|
if (!context.empty())
|
||||||
|
add_config("mem_ctxt", context);
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_dsp(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("raw_config0", extract_bits_or_default(cell->params, id_raw_config0, 27));
|
||||||
|
add_config("raw_config1", extract_bits_or_default(cell->params, id_raw_config1, 24));
|
||||||
|
add_config("raw_config2", extract_bits_or_default(cell->params, id_raw_config2, 14));
|
||||||
|
add_config("raw_config3", extract_bits_or_default(cell->params, id_raw_config3, 3));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_cdc(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
if (cell->type.in(id_DDE, id_TDE, id_CDC, id_XCDC)) {
|
||||||
|
add_config("ck0_edge", bool_or_default(cell->params, id_ck0_edge, false));
|
||||||
|
add_config("ck1_edge", bool_or_default(cell->params, id_ck1_edge, false));
|
||||||
|
add_config("ack_sel", bool_or_default(cell->params, id_ack_sel, false));
|
||||||
|
add_config("bck_sel", bool_or_default(cell->params, id_bck_sel, false));
|
||||||
|
add_config("use_adest_arst", bool_or_default(cell->params, id_use_adest_arst, false));
|
||||||
|
add_config("use_bdest_arst", bool_or_default(cell->params, id_use_bdest_arst, false));
|
||||||
|
if (cell->type != id_DDE) {
|
||||||
|
add_config("use_asrc_arst", bool_or_default(cell->params, id_use_asrc_arst, false));
|
||||||
|
add_config("use_bsrc_arst", bool_or_default(cell->params, id_use_bsrc_arst, false));
|
||||||
|
}
|
||||||
|
if (cell->type == id_XCDC) {
|
||||||
|
add_config("cck_sel", bool_or_default(cell->params, id_cck_sel, false));
|
||||||
|
add_config("dck_sel", bool_or_default(cell->params, id_dck_sel, false));
|
||||||
|
add_config("use_csrc_arst", bool_or_default(cell->params, id_use_csrc_arst, false));
|
||||||
|
add_config("use_dsrc_arst", bool_or_default(cell->params, id_use_dsrc_arst, false));
|
||||||
|
add_config("use_cdest_arst", bool_or_default(cell->params, id_use_cdest_arst, false));
|
||||||
|
add_config("use_ddest_arst", bool_or_default(cell->params, id_use_ddest_arst, false));
|
||||||
|
add_config("link_BA", bool_or_default(cell->params, id_link_BA, false));
|
||||||
|
add_config("link_CB", bool_or_default(cell->params, id_link_CB, false));
|
||||||
|
add_config("link_DC", bool_or_default(cell->params, id_link_DC, false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_fifo(CellInfo *cell)
|
||||||
|
{
|
||||||
|
open_instance(cell);
|
||||||
|
add_config("rck_edge", bool_or_default(cell->params, id_rck_edge, false));
|
||||||
|
add_config("wck_edge", bool_or_default(cell->params, id_wck_edge, false));
|
||||||
|
if (cell->type != id_FIFO) {
|
||||||
|
add_config("use_read_arst", bool_or_default(cell->params, id_use_read_arst, false));
|
||||||
|
add_config("use_write_arst", bool_or_default(cell->params, id_use_write_arst, false));
|
||||||
|
}
|
||||||
|
add_config("read_addr_inv", extract_bits_or_default(cell->params, id_read_addr_inv, 7));
|
||||||
|
close_instance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_interconnections()
|
||||||
|
{
|
||||||
|
for (auto &net : ctx->nets) {
|
||||||
|
NetInfo *ni = net.second.get();
|
||||||
|
if (ni->wires.size() == 0)
|
||||||
|
continue;
|
||||||
|
std::vector<std::string> nets;
|
||||||
|
for (auto &w : ni->wires) {
|
||||||
|
if (w.second.pip != PipId()) {
|
||||||
|
PipId pip = w.second.pip;
|
||||||
|
const auto &extra_data = *uarch->pip_extra_data(w.second.pip);
|
||||||
|
if (!extra_data.name || extra_data.type != PipExtra::PIP_EXTRA_INTERCONNECT)
|
||||||
|
continue;
|
||||||
|
auto &pd = chip_pip_info(ctx->chip_info, pip);
|
||||||
|
IdString src = IdString(chip_tile_info(ctx->chip_info, pip.tile).wires[pd.src_wire].name);
|
||||||
|
std::string tile_name = uarch->tile_name(pip.tile);
|
||||||
|
std::string src_name = src.c_str(ctx);
|
||||||
|
std::string type = "OTC";
|
||||||
|
if (src_name.find("UI1x") != std::string::npos)
|
||||||
|
type = "ITC";
|
||||||
|
if (boost::starts_with(src_name, "SO1."))
|
||||||
|
type = "OTS";
|
||||||
|
if (boost::starts_with(src_name, "SI1."))
|
||||||
|
type = "ITS";
|
||||||
|
src_name = update_name(tile_name, src_name);
|
||||||
|
src_name = src_name.substr(0, src_name.size() - 2);
|
||||||
|
|
||||||
|
std::string name = cleanup_name(std::string(ni->name.c_str(ctx)) + "_" + src_name.substr(4));
|
||||||
|
out << stringf(",\n\t\t%s: {\n", get_string(name).c_str());
|
||||||
|
out << stringf("\t\t\t\"location\": %s,\n", get_string(tile_name + ":" + src_name).c_str());
|
||||||
|
out << stringf("\t\t\t\"type\": %s\n\t\t}", get_string(type).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_instances()
|
||||||
|
{
|
||||||
|
out << "\t\"instances\": {\n";
|
||||||
|
first_instance = true;
|
||||||
|
for (auto &cell : ctx->cells) {
|
||||||
|
switch (cell.second->type.index) {
|
||||||
|
case id_BEYOND_FE.index:
|
||||||
|
write_fe(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_IOP.index:
|
||||||
|
case id_IP.index:
|
||||||
|
case id_OP.index:
|
||||||
|
case id_IOTP.index:
|
||||||
|
case id_ITP.index:
|
||||||
|
case id_OTP.index:
|
||||||
|
write_iop(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_CY.index:
|
||||||
|
write_cy(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_WFB.index:
|
||||||
|
write_wfb(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_WFG.index:
|
||||||
|
write_wfg(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_GCK.index:
|
||||||
|
write_gck(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_IOM.index:
|
||||||
|
write_iom(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_BFR.index:
|
||||||
|
write_bfr(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_DDFR.index:
|
||||||
|
write_ddfr(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_DFR.index:
|
||||||
|
write_dfr(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_RAM.index:
|
||||||
|
write_ram(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_RF.index:
|
||||||
|
case id_RFSP.index:
|
||||||
|
case id_XHRF.index:
|
||||||
|
case id_XWRF.index:
|
||||||
|
case id_XPRF.index:
|
||||||
|
write_rfb(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_XLUT.index:
|
||||||
|
write_xlut(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_FIFO.index: // mode 0
|
||||||
|
case id_XHFIFO.index: // mode 1
|
||||||
|
case id_XWFIFO.index:
|
||||||
|
write_fifo(cell.second.get());
|
||||||
|
break; // mode 2
|
||||||
|
case id_DDE.index: // mode 0
|
||||||
|
case id_TDE.index: // mode 1
|
||||||
|
case id_CDC.index: // mode 2
|
||||||
|
case id_BGC.index: // mode 3
|
||||||
|
case id_GBC.index: // mode 4
|
||||||
|
case id_XCDC.index:
|
||||||
|
write_cdc(cell.second.get());
|
||||||
|
break; // mode 5
|
||||||
|
case id_DSP.index:
|
||||||
|
write_dsp(cell.second.get());
|
||||||
|
break;
|
||||||
|
case id_PLL.index:
|
||||||
|
write_pll(cell.second.get());
|
||||||
|
break;
|
||||||
|
// case id_CRX.index:
|
||||||
|
// case id_CTX.index:
|
||||||
|
// case id_PMA.index:
|
||||||
|
// case id_Service.index:
|
||||||
|
// case id_SOCIF.index:
|
||||||
|
default:
|
||||||
|
log_error("Unhandled cell %s of type %s\n", cell.second.get()->name.c_str(ctx),
|
||||||
|
cell.second->type.c_str(ctx));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write_interconnections();
|
||||||
|
out << "\n\t},\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_setup()
|
||||||
|
{
|
||||||
|
out << "\t\"setup\": {\n";
|
||||||
|
out << "\t\t\"variant\": \"NG-ULTRA\",\n";
|
||||||
|
out << "\t\t\"iobanks\": {\n";
|
||||||
|
bool first = true;
|
||||||
|
for (auto &bank : uarch->bank_voltage) {
|
||||||
|
out << (first ? "" : ",\n");
|
||||||
|
out << stringf("\t\t\t%s:%s", get_string(bank.first).c_str(), get_string(bank.second).c_str());
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
out << "\n\t\t}\n\t}\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_json()
|
||||||
|
{
|
||||||
|
out << "{\n";
|
||||||
|
write_nets();
|
||||||
|
write_instances();
|
||||||
|
write_setup();
|
||||||
|
out << "}\n";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void NgUltraImpl::write_bitstream_json(const std::string &filename)
|
||||||
|
{
|
||||||
|
std::ofstream out(filename);
|
||||||
|
if (!out)
|
||||||
|
log_error("failed to open file %s for writing (%s)\n", filename.c_str(), strerror(errno));
|
||||||
|
|
||||||
|
BitstreamJsonBackend be(ctx, this, out);
|
||||||
|
be.write_json();
|
||||||
|
}
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
84
himbaechel/uarch/ng-ultra/cells.cc
Normal file
84
himbaechel/uarch/ng-ultra/cells.cc
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 "pack.h"
|
||||||
|
|
||||||
|
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"
|
||||||
|
#include "himbaechel_constids.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
CellInfo *NgUltraPacker::create_cell_ptr(IdString type, IdString name)
|
||||||
|
{
|
||||||
|
CellInfo *cell = ctx->createCell(name, type);
|
||||||
|
|
||||||
|
auto add_port = [&](const IdString id, PortType dir) {
|
||||||
|
cell->ports[id].name = id;
|
||||||
|
cell->ports[id].type = dir;
|
||||||
|
};
|
||||||
|
if (type == id_BEYOND_FE) {
|
||||||
|
add_port(id_I1, PORT_IN);
|
||||||
|
add_port(id_I2, PORT_IN);
|
||||||
|
add_port(id_I3, PORT_IN);
|
||||||
|
add_port(id_I4, PORT_IN);
|
||||||
|
add_port(id_LO, PORT_OUT);
|
||||||
|
add_port(id_DI, PORT_IN);
|
||||||
|
add_port(id_L, PORT_IN);
|
||||||
|
add_port(id_CK, PORT_IN);
|
||||||
|
add_port(id_R, PORT_IN);
|
||||||
|
add_port(id_DO, PORT_OUT);
|
||||||
|
} else if (type == id_BFR) {
|
||||||
|
add_port(id_I, PORT_IN);
|
||||||
|
add_port(id_O, PORT_OUT);
|
||||||
|
} else if (type == id_DFR) {
|
||||||
|
add_port(id_I, PORT_IN);
|
||||||
|
add_port(id_O, PORT_OUT);
|
||||||
|
add_port(id_L, PORT_IN);
|
||||||
|
add_port(id_CK, PORT_IN);
|
||||||
|
add_port(id_R, PORT_IN);
|
||||||
|
} else if (type == id_DDFR) {
|
||||||
|
add_port(id_I, PORT_IN);
|
||||||
|
add_port(id_O, PORT_OUT);
|
||||||
|
add_port(id_L, PORT_IN);
|
||||||
|
add_port(id_CK, PORT_IN);
|
||||||
|
add_port(id_R, PORT_IN);
|
||||||
|
add_port(id_I2, PORT_IN);
|
||||||
|
add_port(id_O2, PORT_OUT);
|
||||||
|
add_port(id_CKF, PORT_IN);
|
||||||
|
} else if (type == id_IOM) {
|
||||||
|
add_port(id_P17RI, PORT_IN);
|
||||||
|
add_port(id_CKO1, PORT_OUT);
|
||||||
|
add_port(id_P19RI, PORT_IN);
|
||||||
|
add_port(id_CKO2, PORT_OUT);
|
||||||
|
} else if (type == id_WFB) {
|
||||||
|
add_port(id_ZI, PORT_IN);
|
||||||
|
add_port(id_ZO, PORT_OUT);
|
||||||
|
} else if (type == id_GCK) {
|
||||||
|
add_port(id_SI1, PORT_IN);
|
||||||
|
add_port(id_SI2, PORT_IN);
|
||||||
|
add_port(id_CMD, PORT_IN);
|
||||||
|
add_port(id_SO, PORT_OUT);
|
||||||
|
} else {
|
||||||
|
log_error("Trying to create unknown cell type %s\n", type.c_str(ctx));
|
||||||
|
}
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
6026
himbaechel/uarch/ng-ultra/constids.inc
Normal file
6026
himbaechel/uarch/ng-ultra/constids.inc
Normal file
File diff suppressed because it is too large
Load Diff
304
himbaechel/uarch/ng-ultra/csv.cc
Normal file
304
himbaechel/uarch/ng-ultra/csv.cc
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 <algorithm>
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <fstream>
|
||||||
|
#include <regex>
|
||||||
|
|
||||||
|
#include "extra_data.h"
|
||||||
|
#include "himbaechel_api.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "ng_ultra.h"
|
||||||
|
|
||||||
|
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"
|
||||||
|
#include "himbaechel_constids.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
void NgUltraImpl::parse_csv(const std::string &filename)
|
||||||
|
{
|
||||||
|
std::ifstream in(filename);
|
||||||
|
if (!in)
|
||||||
|
log_error("failed to open CSV file '%s'\n", filename.c_str());
|
||||||
|
log_info("Parsing CSV file..\n");
|
||||||
|
std::string line;
|
||||||
|
std::string linebuf;
|
||||||
|
int lineno = 0;
|
||||||
|
enum uint8_t
|
||||||
|
{
|
||||||
|
IO_PADS = 0,
|
||||||
|
IO_BANKS,
|
||||||
|
IO_GCKS,
|
||||||
|
IO_ERROR
|
||||||
|
} line_type;
|
||||||
|
|
||||||
|
auto isempty = [](const std::string &str) {
|
||||||
|
return std::all_of(str.begin(), str.end(), [](char c) { return std::isspace(c); });
|
||||||
|
};
|
||||||
|
auto is_number = [](const std::string &str) {
|
||||||
|
return !str.empty() && std::all_of(str.begin(), str.end(), ::isdigit);
|
||||||
|
};
|
||||||
|
auto get_cells = [&](std::string str) {
|
||||||
|
std::vector<CellInfo *> tgt_cells;
|
||||||
|
IdString cellname = ctx->id(str);
|
||||||
|
if (ctx->cells.count(cellname))
|
||||||
|
tgt_cells.push_back(ctx->cells.at(cellname).get());
|
||||||
|
return tgt_cells;
|
||||||
|
};
|
||||||
|
|
||||||
|
line_type = IO_PADS;
|
||||||
|
pool<std::string> banks_used;
|
||||||
|
bool old_format = false;
|
||||||
|
while (std::getline(in, line)) {
|
||||||
|
++lineno;
|
||||||
|
// Trim comments, from # until end of the line
|
||||||
|
size_t cstart = line.find('#');
|
||||||
|
if (cstart != std::string::npos)
|
||||||
|
line = line.substr(0, cstart);
|
||||||
|
if (isempty(line))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::vector<std::string> arguments;
|
||||||
|
boost::split(arguments, line, boost::is_any_of(","));
|
||||||
|
if (arguments.empty())
|
||||||
|
continue;
|
||||||
|
switch (line_type) {
|
||||||
|
case IO_PADS: {
|
||||||
|
if (arguments.size() == 1 && arguments[0][0] == '!') {
|
||||||
|
line_type = IO_BANKS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arguments.size() != 15)
|
||||||
|
log_error("number of parameters in line %d must be 15\n", lineno);
|
||||||
|
|
||||||
|
std::string arg_iobname = arguments.at(0);
|
||||||
|
std::string arg_location = arguments.at(1);
|
||||||
|
std::string arg_standard = arguments.at(2);
|
||||||
|
std::string arg_drive = arguments.at(3);
|
||||||
|
std::string arg_slewRate = arguments.at(4);
|
||||||
|
std::string arg_inputDelayLine = arguments.at(5);
|
||||||
|
std::string arg_outputDelayLine = arguments.at(6);
|
||||||
|
std::string arg_differential = arguments.at(7);
|
||||||
|
std::string arg_weakTermination = arguments.at(8);
|
||||||
|
std::string arg_termination = arguments.at(9);
|
||||||
|
std::string arg_terminationReference = arguments.at(10);
|
||||||
|
std::string arg_turbo = arguments.at(11);
|
||||||
|
std::string arg_inputSignalSlope = arguments.at(12);
|
||||||
|
std::string arg_outputCapacity = arguments.at(13);
|
||||||
|
std::string arg_registered = arguments.at(14);
|
||||||
|
|
||||||
|
// TODO: Remove this block
|
||||||
|
const std::vector<std::string> weak_values_check = {"None", "PullDown", "PullUp", "Keeper"};
|
||||||
|
auto it2 = std::find(std::begin(weak_values_check), std::end(weak_values_check), arguments.at(4));
|
||||||
|
if (it2 != std::end(weak_values_check)) {
|
||||||
|
if (!old_format) {
|
||||||
|
log_warning("Old CSV format detected. Please update file.\n");
|
||||||
|
old_format = true;
|
||||||
|
}
|
||||||
|
arg_weakTermination = arguments.at(4);
|
||||||
|
arg_slewRate = arguments.at(5);
|
||||||
|
arg_termination = arguments.at(6);
|
||||||
|
arg_inputDelayLine = arguments.at(7);
|
||||||
|
arg_outputDelayLine = arguments.at(8);
|
||||||
|
arg_differential = arguments.at(9);
|
||||||
|
}
|
||||||
|
// End of block
|
||||||
|
|
||||||
|
if (!(boost::starts_with(arg_location, "IOB") && boost::contains(arg_location, "_D")))
|
||||||
|
log_error("invalid location name '%s' must start with 'IOB' in line %d\n", arg_location.c_str(),
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
const std::vector<std::string> standard_values = {"LVDS", "LVCMOS", "SSTL", "HSTL"}; // , "POD"
|
||||||
|
auto it = std::find(std::begin(standard_values), std::end(standard_values), arg_standard);
|
||||||
|
if (it == std::end(standard_values))
|
||||||
|
log_error("unknown standard value '%s' in line %d\n", arg_standard.c_str(), lineno);
|
||||||
|
|
||||||
|
const std::vector<std::string> drive_values = {"2mA", "4mA", "8mA", "16mA",
|
||||||
|
"CatI", "CatII", "Undefined"}; // "6mA", "12mA",
|
||||||
|
it = std::find(std::begin(drive_values), std::end(drive_values), arg_drive);
|
||||||
|
if (it == std::end(drive_values))
|
||||||
|
log_error("unknown drive value '%s' in line %d\n", arg_drive.c_str(), lineno);
|
||||||
|
|
||||||
|
const std::vector<std::string> slew_values = {"Slow", "Medium", "Fast"};
|
||||||
|
it = std::find(std::begin(slew_values), std::end(slew_values), arg_slewRate);
|
||||||
|
if (it == std::end(slew_values))
|
||||||
|
log_error("unknown weak termination value '%s' in line %d\n", arg_slewRate.c_str(), lineno);
|
||||||
|
|
||||||
|
if (!is_number(arg_inputDelayLine)) {
|
||||||
|
log_error("input delay must be number, value '%s' in line %d\n", arg_inputDelayLine.c_str(), lineno);
|
||||||
|
} else {
|
||||||
|
int delay = std::stoi(arg_inputDelayLine);
|
||||||
|
if (delay < 0 || delay > 63)
|
||||||
|
log_error("input delay value must be in range from 0 to 63 in line %d\n", lineno);
|
||||||
|
}
|
||||||
|
if (!is_number(arg_outputDelayLine)) {
|
||||||
|
log_error("output delay must be number, value '%s' in line %d\n", arg_outputDelayLine.c_str(), lineno);
|
||||||
|
} else {
|
||||||
|
int delay = std::stoi(arg_outputDelayLine);
|
||||||
|
if (delay < 0 || delay > 63)
|
||||||
|
log_error("output delay value must be in range from 0 to 63 in line %d\n", lineno);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arg_differential.empty() && arg_differential != "True" && arg_differential != "False")
|
||||||
|
log_error("differential must be boolean, value '%s' in line %d\n", arg_differential.c_str(), lineno);
|
||||||
|
|
||||||
|
const std::vector<std::string> weak_values = {"None", "PullDown", "PullUp", "Keeper"};
|
||||||
|
it = std::find(std::begin(weak_values), std::end(weak_values), arg_weakTermination);
|
||||||
|
if (it == std::end(weak_values))
|
||||||
|
log_error("unknown weak termination value '%s' in line %d\n", arg_weakTermination.c_str(), lineno);
|
||||||
|
|
||||||
|
if (!arg_termination.empty()) {
|
||||||
|
if (!is_number(arg_termination)) {
|
||||||
|
log_error("termination must be string containing int, value '%s' in line %d\n",
|
||||||
|
arg_termination.c_str(), lineno);
|
||||||
|
} else {
|
||||||
|
int termination = std::stoi(arg_termination);
|
||||||
|
if (termination < 30 || termination > 80)
|
||||||
|
log_error("termination value must be in range from 30 to 80 in line %d\n", lineno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> termref_values = {"Floating", "VT"};
|
||||||
|
it = std::find(std::begin(termref_values), std::end(termref_values), arg_terminationReference);
|
||||||
|
if (it == std::end(termref_values))
|
||||||
|
log_error("unknown termination reference value '%s' in line %d\n", arg_terminationReference.c_str(),
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
if (!arg_turbo.empty() && arg_turbo != "True" && arg_turbo != "False")
|
||||||
|
log_error("turbo must be boolean, value '%s' in line %d\n", arg_turbo.c_str(), lineno);
|
||||||
|
|
||||||
|
if (!arg_inputSignalSlope.empty() && !is_number(arg_inputSignalSlope))
|
||||||
|
log_error("signal slope must be number, value '%s' in line %d\n", arg_inputSignalSlope.c_str(), lineno);
|
||||||
|
if (!arg_outputCapacity.empty() && !is_number(arg_outputCapacity))
|
||||||
|
log_error("output capacity must be number, value '%s' in line %d\n", arg_outputCapacity.c_str(),
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
const std::vector<std::string> registered_values = {"Auto", "I", "IC", "O", "OC", "IO", "IOC"};
|
||||||
|
it = std::find(std::begin(registered_values), std::end(registered_values), arg_registered);
|
||||||
|
if (it == std::end(registered_values))
|
||||||
|
log_error("unknown registered value '%s' in line %d\n", arg_registered.c_str(), lineno);
|
||||||
|
|
||||||
|
if (arg_standard == "LVDS" && arg_drive != "Undefined")
|
||||||
|
log_error("for port in line %d when standard is 'LVDS' drive must be 'Undefined'\n", lineno);
|
||||||
|
if (arg_standard == "LVCMOS" && !boost::ends_with(arg_drive, "mA"))
|
||||||
|
log_error("for port in line %d when standard is 'LVCMOS' drive current must be in mA\n", lineno);
|
||||||
|
if ((arg_standard == "SSTL" || arg_standard == "HSTL") && !boost::starts_with(arg_drive, "Cat"))
|
||||||
|
log_error("for port in line %d when standard is 'SSTL' or 'HSTL' drive current must be in 'CatI' or "
|
||||||
|
"'CatII'\n",
|
||||||
|
lineno);
|
||||||
|
|
||||||
|
if (arg_terminationReference == "Floating") {
|
||||||
|
if (!(arg_differential == "True" && arg_weakTermination == "None")) {
|
||||||
|
log_error("for floating termination, differential myst be 'True' and weakTermination must be "
|
||||||
|
"'None' in line %d\n",
|
||||||
|
lineno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::vector<CellInfo *> dest = get_cells(arg_iobname);
|
||||||
|
for (auto c : dest) {
|
||||||
|
c->params[id_iobname] = arg_iobname;
|
||||||
|
c->params[id_location] = arg_location;
|
||||||
|
c->params[id_standard] = arg_standard;
|
||||||
|
c->params[id_drive] = arg_drive;
|
||||||
|
c->params[id_slewRate] = arg_slewRate;
|
||||||
|
c->params[id_inputDelayLine] = arg_inputDelayLine;
|
||||||
|
c->params[id_outputDelayLine] = arg_outputDelayLine;
|
||||||
|
c->params[id_inputDelayOn] = std::string((std::stoi(arg_inputDelayLine) != 0) ? "True" : "False");
|
||||||
|
c->params[id_outputDelayOn] = std::string((std::stoi(arg_outputDelayLine) != 0) ? "True" : "False");
|
||||||
|
c->params[id_differential] = arg_differential;
|
||||||
|
c->params[id_weakTermination] = arg_weakTermination;
|
||||||
|
if (!arg_termination.empty()) {
|
||||||
|
c->params[id_termination] = arg_termination;
|
||||||
|
c->params[id_terminationReference] = arg_terminationReference;
|
||||||
|
}
|
||||||
|
c->params[id_turbo] = arg_turbo;
|
||||||
|
c->params[id_inputSignalSlope] = arg_inputSignalSlope;
|
||||||
|
c->params[id_outputCapacity] = arg_outputCapacity;
|
||||||
|
c->params[id_registered] = arg_registered;
|
||||||
|
}
|
||||||
|
if (dest.size() == 0)
|
||||||
|
log_warning("Pad with name '%s' not found in netlist.\n", arg_iobname.c_str());
|
||||||
|
|
||||||
|
std::string bank_name = arg_location.substr(0, arg_location.find_first_of('_'));
|
||||||
|
banks_used.emplace(bank_name);
|
||||||
|
} break;
|
||||||
|
case IO_BANKS: {
|
||||||
|
if (arguments.size() == 1 && arguments[0][0] == '!') {
|
||||||
|
line_type = IO_GCKS;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arguments.size() != 3)
|
||||||
|
log_error("number of parameters in line %d must be 3\n", lineno);
|
||||||
|
|
||||||
|
if (!boost::starts_with(arguments.at(0), "IOB"))
|
||||||
|
log_error("wrong bank name '%s' in line %d\n", arguments.at(0).c_str(), lineno);
|
||||||
|
|
||||||
|
const char *voltages[] = {"1.2V", "1.5V", "1.8V", "2.5V", "3.3V"};
|
||||||
|
auto it = std::find(std::begin(voltages), std::end(voltages), arguments.at(1));
|
||||||
|
if (it == std::end(voltages))
|
||||||
|
log_error("unknown voltage level '%s' in line %d\n", arguments.at(1).c_str(), lineno);
|
||||||
|
|
||||||
|
const char *direct_io_voltages[] = {"1.8V", "2.5V", "3.3V"};
|
||||||
|
const char *complex_io_voltages[] = {"1.2V", "1.5V", "1.8V"};
|
||||||
|
|
||||||
|
int bank = std::stoi(arguments.at(0).substr(3));
|
||||||
|
switch (bank) {
|
||||||
|
// direct
|
||||||
|
case 0:
|
||||||
|
case 1:
|
||||||
|
case 6:
|
||||||
|
case 7: {
|
||||||
|
auto it = std::find(std::begin(direct_io_voltages), std::end(direct_io_voltages), arguments.at(1));
|
||||||
|
if (it == std::end(direct_io_voltages))
|
||||||
|
log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(),
|
||||||
|
arguments.at(0).c_str());
|
||||||
|
} break;
|
||||||
|
// complex
|
||||||
|
default:
|
||||||
|
auto it = std::find(std::begin(complex_io_voltages), std::end(complex_io_voltages), arguments.at(1));
|
||||||
|
if (it == std::end(complex_io_voltages))
|
||||||
|
log_error("unsupported voltage level '%s' for bank '%s'\n", arguments.at(1).c_str(),
|
||||||
|
arguments.at(0).c_str());
|
||||||
|
}
|
||||||
|
bank_voltage[arguments.at(0)] = arguments.at(1);
|
||||||
|
} break;
|
||||||
|
case IO_GCKS: {
|
||||||
|
if (arguments.size() == 1 && arguments[0][0] == '!') {
|
||||||
|
line_type = IO_ERROR;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (arguments.size() != 2)
|
||||||
|
log_error("number of parameters in line %d must be 2\n", lineno);
|
||||||
|
} break;
|
||||||
|
default:
|
||||||
|
log_error("switching to unknown block of data in line %d\n", lineno);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (auto &bank_name : banks_used) {
|
||||||
|
if (bank_voltage.count(bank_name) == 0) {
|
||||||
|
log_error("IO for bank '%s' defined, but no bank configuration.\n", bank_name.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
265
himbaechel/uarch/ng-ultra/extra_data.h
Normal file
265
himbaechel/uarch/ng-ultra/extra_data.h
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 NGULTRA_EXTRA_DATA_H
|
||||||
|
#define NGULTRA_EXTRA_DATA_H
|
||||||
|
|
||||||
|
#include "nextpnr.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
NPNR_PACKED_STRUCT(struct NGUltraTileInstExtraDataPOD {
|
||||||
|
int32_t name;
|
||||||
|
uint8_t lobe;
|
||||||
|
uint8_t tile_type;
|
||||||
|
uint16_t dummy2;
|
||||||
|
});
|
||||||
|
|
||||||
|
NPNR_PACKED_STRUCT(struct NGUltraPipExtraDataPOD {
|
||||||
|
int32_t name;
|
||||||
|
uint16_t type;
|
||||||
|
uint8_t input;
|
||||||
|
uint8_t output;
|
||||||
|
});
|
||||||
|
|
||||||
|
NPNR_PACKED_STRUCT(struct NGUltraBelExtraDataPOD { int32_t flags; });
|
||||||
|
|
||||||
|
struct GckConfig
|
||||||
|
{
|
||||||
|
explicit GckConfig(BelId belid)
|
||||||
|
{
|
||||||
|
bel = belid;
|
||||||
|
si1 = IdString();
|
||||||
|
si2 = IdString();
|
||||||
|
used = false;
|
||||||
|
}
|
||||||
|
BelId bel;
|
||||||
|
IdString si1;
|
||||||
|
IdString si2;
|
||||||
|
bool used;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TILETypeZ
|
||||||
|
{
|
||||||
|
BEL_LUT_Z = 0,
|
||||||
|
BEL_LUT_MAX_Z = 31,
|
||||||
|
BEL_CY_Z = 32,
|
||||||
|
BEL_XLUT_Z = BEL_CY_Z + 4,
|
||||||
|
BEL_RF_Z = BEL_XLUT_Z + 8,
|
||||||
|
BEL_XRF_Z = BEL_RF_Z + 2,
|
||||||
|
BEL_FIFO_Z = BEL_XRF_Z + 1,
|
||||||
|
BEL_XFIFO_Z = BEL_FIFO_Z + 2,
|
||||||
|
BEL_CDC_Z = BEL_XFIFO_Z + 1,
|
||||||
|
BEL_XCDC_Z = BEL_CDC_Z + 2
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ClusterPlacement
|
||||||
|
{
|
||||||
|
PLACE_CY_CHAIN = 1024,
|
||||||
|
PLACE_CY_FE1,
|
||||||
|
PLACE_CY_FE2,
|
||||||
|
PLACE_CY_FE3,
|
||||||
|
PLACE_CY_FE4,
|
||||||
|
PLACE_XLUT_FE1,
|
||||||
|
PLACE_XLUT_FE2,
|
||||||
|
PLACE_XLUT_FE3,
|
||||||
|
PLACE_XLUT_FE4,
|
||||||
|
PLACE_XRF_I1,
|
||||||
|
PLACE_XRF_I2,
|
||||||
|
PLACE_XRF_I3,
|
||||||
|
PLACE_XRF_I4,
|
||||||
|
PLACE_XRF_I5,
|
||||||
|
PLACE_XRF_I6,
|
||||||
|
PLACE_XRF_I7,
|
||||||
|
PLACE_XRF_I8,
|
||||||
|
PLACE_XRF_I9,
|
||||||
|
PLACE_XRF_I10,
|
||||||
|
PLACE_XRF_I11,
|
||||||
|
PLACE_XRF_I12,
|
||||||
|
PLACE_XRF_I13,
|
||||||
|
PLACE_XRF_I14,
|
||||||
|
PLACE_XRF_I15,
|
||||||
|
PLACE_XRF_I16,
|
||||||
|
PLACE_XRF_I17,
|
||||||
|
PLACE_XRF_I18,
|
||||||
|
PLACE_XRF_I19,
|
||||||
|
PLACE_XRF_I20,
|
||||||
|
PLACE_XRF_I21,
|
||||||
|
PLACE_XRF_I22,
|
||||||
|
PLACE_XRF_I23,
|
||||||
|
PLACE_XRF_I24,
|
||||||
|
PLACE_XRF_I25,
|
||||||
|
PLACE_XRF_I26,
|
||||||
|
PLACE_XRF_I27,
|
||||||
|
PLACE_XRF_I28,
|
||||||
|
PLACE_XRF_I29,
|
||||||
|
PLACE_XRF_I30,
|
||||||
|
PLACE_XRF_I31,
|
||||||
|
PLACE_XRF_I32,
|
||||||
|
PLACE_XRF_I33,
|
||||||
|
PLACE_XRF_I34,
|
||||||
|
PLACE_XRF_I35,
|
||||||
|
PLACE_XRF_I36,
|
||||||
|
PLACE_XRF_RA1,
|
||||||
|
PLACE_XRF_RA2,
|
||||||
|
PLACE_XRF_RA3,
|
||||||
|
PLACE_XRF_RA4,
|
||||||
|
PLACE_XRF_RA5,
|
||||||
|
PLACE_XRF_RA6,
|
||||||
|
PLACE_XRF_RA7,
|
||||||
|
PLACE_XRF_RA8,
|
||||||
|
PLACE_XRF_RA9,
|
||||||
|
PLACE_XRF_RA10,
|
||||||
|
PLACE_XRF_WA1,
|
||||||
|
PLACE_XRF_WA2,
|
||||||
|
PLACE_XRF_WA3,
|
||||||
|
PLACE_XRF_WA4,
|
||||||
|
PLACE_XRF_WA5,
|
||||||
|
PLACE_XRF_WA6,
|
||||||
|
PLACE_XRF_WE,
|
||||||
|
PLACE_XRF_WEA,
|
||||||
|
PLACE_DSP_CHAIN,
|
||||||
|
PLACE_CDC_AI1,
|
||||||
|
PLACE_CDC_AI2,
|
||||||
|
PLACE_CDC_AI3,
|
||||||
|
PLACE_CDC_AI4,
|
||||||
|
PLACE_CDC_AI5,
|
||||||
|
PLACE_CDC_AI6,
|
||||||
|
PLACE_CDC_BI1,
|
||||||
|
PLACE_CDC_BI2,
|
||||||
|
PLACE_CDC_BI3,
|
||||||
|
PLACE_CDC_BI4,
|
||||||
|
PLACE_CDC_BI5,
|
||||||
|
PLACE_CDC_BI6,
|
||||||
|
PLACE_CDC_ASRSTI,
|
||||||
|
PLACE_CDC_ADRSTI,
|
||||||
|
PLACE_CDC_BSRSTI,
|
||||||
|
PLACE_CDC_BDRSTI,
|
||||||
|
PLACE_CDC_CI1,
|
||||||
|
PLACE_CDC_CI2,
|
||||||
|
PLACE_CDC_CI3,
|
||||||
|
PLACE_CDC_CI4,
|
||||||
|
PLACE_CDC_CI5,
|
||||||
|
PLACE_CDC_CI6,
|
||||||
|
PLACE_CDC_DI1,
|
||||||
|
PLACE_CDC_DI2,
|
||||||
|
PLACE_CDC_DI3,
|
||||||
|
PLACE_CDC_DI4,
|
||||||
|
PLACE_CDC_DI5,
|
||||||
|
PLACE_CDC_DI6,
|
||||||
|
PLACE_CDC_CSRSTI,
|
||||||
|
PLACE_CDC_CDRSTI,
|
||||||
|
PLACE_CDC_DSRSTI,
|
||||||
|
PLACE_CDC_DDRSTI,
|
||||||
|
PLACE_FIFO_I1,
|
||||||
|
PLACE_FIFO_I2,
|
||||||
|
PLACE_FIFO_I3,
|
||||||
|
PLACE_FIFO_I4,
|
||||||
|
PLACE_FIFO_I5,
|
||||||
|
PLACE_FIFO_I6,
|
||||||
|
PLACE_FIFO_I7,
|
||||||
|
PLACE_FIFO_I8,
|
||||||
|
PLACE_FIFO_I9,
|
||||||
|
PLACE_FIFO_I10,
|
||||||
|
PLACE_FIFO_I11,
|
||||||
|
PLACE_FIFO_I12,
|
||||||
|
PLACE_FIFO_I13,
|
||||||
|
PLACE_FIFO_I14,
|
||||||
|
PLACE_FIFO_I15,
|
||||||
|
PLACE_FIFO_I16,
|
||||||
|
PLACE_FIFO_I17,
|
||||||
|
PLACE_FIFO_I18,
|
||||||
|
PLACE_FIFO_I19,
|
||||||
|
PLACE_FIFO_I20,
|
||||||
|
PLACE_FIFO_I21,
|
||||||
|
PLACE_FIFO_I22,
|
||||||
|
PLACE_FIFO_I23,
|
||||||
|
PLACE_FIFO_I24,
|
||||||
|
PLACE_FIFO_I25,
|
||||||
|
PLACE_FIFO_I26,
|
||||||
|
PLACE_FIFO_I27,
|
||||||
|
PLACE_FIFO_I28,
|
||||||
|
PLACE_FIFO_I29,
|
||||||
|
PLACE_FIFO_I30,
|
||||||
|
PLACE_FIFO_I31,
|
||||||
|
PLACE_FIFO_I32,
|
||||||
|
PLACE_FIFO_I33,
|
||||||
|
PLACE_FIFO_I34,
|
||||||
|
PLACE_FIFO_I35,
|
||||||
|
PLACE_FIFO_I36,
|
||||||
|
PLACE_FIFO_RAI1,
|
||||||
|
PLACE_FIFO_RAI2,
|
||||||
|
PLACE_FIFO_RAI3,
|
||||||
|
PLACE_FIFO_RAI4,
|
||||||
|
PLACE_FIFO_RAI5,
|
||||||
|
PLACE_FIFO_RAI6,
|
||||||
|
PLACE_FIFO_RAI7,
|
||||||
|
PLACE_FIFO_WAI1,
|
||||||
|
PLACE_FIFO_WAI2,
|
||||||
|
PLACE_FIFO_WAI3,
|
||||||
|
PLACE_FIFO_WAI4,
|
||||||
|
PLACE_FIFO_WAI5,
|
||||||
|
PLACE_FIFO_WAI6,
|
||||||
|
PLACE_FIFO_WAI7,
|
||||||
|
PLACE_FIFO_WE,
|
||||||
|
PLACE_FIFO_WEA,
|
||||||
|
PLACE_FIFO_WRSTI1,
|
||||||
|
PLACE_FIFO_RRSTI1,
|
||||||
|
PLACE_FIFO_WRSTI2,
|
||||||
|
PLACE_FIFO_RRSTI2,
|
||||||
|
PLACE_FIFO_WRSTI3,
|
||||||
|
PLACE_FIFO_RRSTI3,
|
||||||
|
PLACE_FIFO_WRSTI4,
|
||||||
|
PLACE_FIFO_RRSTI4,
|
||||||
|
PLACE_FIFO_WEQ1,
|
||||||
|
PLACE_FIFO_REQ1,
|
||||||
|
PLACE_FIFO_WEQ2,
|
||||||
|
PLACE_FIFO_REQ2,
|
||||||
|
PLACE_LUT_CHAIN,
|
||||||
|
PLACE_DFF_CHAIN,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PipExtra
|
||||||
|
{
|
||||||
|
PIP_EXTRA_CROSSBAR = 1,
|
||||||
|
PIP_EXTRA_MUX = 2,
|
||||||
|
PIP_EXTRA_BYPASS = 3,
|
||||||
|
PIP_EXTRA_LUT_PERMUTATION = 4,
|
||||||
|
PIP_EXTRA_INTERCONNECT = 5,
|
||||||
|
PIP_EXTRA_VIRTUAL = 6,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum BelExtra
|
||||||
|
{
|
||||||
|
BEL_EXTRA_FE_CSC = 1,
|
||||||
|
BEL_EXTRA_FE_SCC = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum TileTypeExtra
|
||||||
|
{
|
||||||
|
TILE_EXTRA_FABRIC = 0,
|
||||||
|
TILE_EXTRA_TUBE = 1,
|
||||||
|
TILE_EXTRA_SOC = 2,
|
||||||
|
TILE_EXTRA_RING = 3,
|
||||||
|
TILE_EXTRA_FENCE = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
726
himbaechel/uarch/ng-ultra/gen/arch_gen.py
Normal file
726
himbaechel/uarch/ng-ultra/gen/arch_gen.py
Normal file
@ -0,0 +1,726 @@
|
|||||||
|
# nextpnr -- Next Generation Place and Route
|
||||||
|
#
|
||||||
|
# Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
#
|
||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
import json
|
||||||
|
from os import path
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
import gzip
|
||||||
|
|
||||||
|
# Configuration flags
|
||||||
|
USE_LUT_PERMUTATION = True
|
||||||
|
|
||||||
|
sys.path.append(path.join(path.dirname(__file__), "../../.."))
|
||||||
|
from himbaechel_dbgen.chip import *
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class TileExtraData(BBAStruct):
|
||||||
|
name: IdString
|
||||||
|
lobe: int = 0
|
||||||
|
tile_type: int = 0
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
pass
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
bba.u32(self.name.index)
|
||||||
|
bba.u8(self.lobe)
|
||||||
|
bba.u8(self.tile_type)
|
||||||
|
bba.u16(0) # dummy
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class PipExtraData(BBAStruct):
|
||||||
|
name: IdString = field(default_factory=IdString)
|
||||||
|
data_type: int = 0
|
||||||
|
input: int = 0
|
||||||
|
output: int = 0
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
pass
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
bba.u32(self.name.index)
|
||||||
|
bba.u16(self.data_type)
|
||||||
|
bba.u8(self.input)
|
||||||
|
bba.u8(self.output)
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class BelExtraData(BBAStruct):
|
||||||
|
flags: int = 0
|
||||||
|
|
||||||
|
def serialise_lists(self, context: str, bba: BBAWriter):
|
||||||
|
pass
|
||||||
|
def serialise(self, context: str, bba: BBAWriter):
|
||||||
|
bba.u32(self.flags)
|
||||||
|
|
||||||
|
PLL_Z = 0
|
||||||
|
WFG_C_Z = 1
|
||||||
|
WFG_R_Z = 11
|
||||||
|
|
||||||
|
IOM_Z = 136
|
||||||
|
|
||||||
|
RAM_Z = 0
|
||||||
|
DSP1_Z = 1
|
||||||
|
DSP2_Z = 2
|
||||||
|
|
||||||
|
SOCIF_Z = 0
|
||||||
|
SERVICE_Z = 1
|
||||||
|
|
||||||
|
LUT_Z = 0
|
||||||
|
CY_Z = 32
|
||||||
|
XLUT_Z = CY_Z + 4
|
||||||
|
RF_Z = XLUT_Z + 8
|
||||||
|
XRF_Z = RF_Z + 2
|
||||||
|
FIFO_Z = XRF_Z + 1
|
||||||
|
XFIFO_Z = FIFO_Z + 2
|
||||||
|
CDC_Z = XFIFO_Z + 1
|
||||||
|
XCDC_Z = CDC_Z + 2
|
||||||
|
|
||||||
|
PIP_EXTRA_CROSSBAR = 1
|
||||||
|
PIP_EXTRA_MUX = 2
|
||||||
|
PIP_EXTRA_BYPASS = 3
|
||||||
|
PIP_EXTRA_LUT_PERMUTATION = 4
|
||||||
|
PIP_EXTRA_INTERCONNECT = 5
|
||||||
|
PIP_EXTRA_VIRTUAL = 6
|
||||||
|
|
||||||
|
BEL_EXTRA_FE_CSC = 1
|
||||||
|
BEL_EXTRA_FE_SCC = 2
|
||||||
|
|
||||||
|
TILE_EXTRA_FABRIC = 0
|
||||||
|
TILE_EXTRA_TUBE = 1
|
||||||
|
TILE_EXTRA_SOC = 2
|
||||||
|
TILE_EXTRA_RING = 3
|
||||||
|
TILE_EXTRA_FENCE = 4
|
||||||
|
|
||||||
|
def bel_z(tile_type, bel_name, bel_type):
|
||||||
|
if tile_type.startswith("CKG"):
|
||||||
|
if (bel_type=="PLL"):
|
||||||
|
return PLL_Z
|
||||||
|
else:
|
||||||
|
if bel_name.startswith("WFG.WFG_C"):
|
||||||
|
return int(bel_name.replace("WFG.WFG_C","")) + WFG_C_Z -1
|
||||||
|
else:
|
||||||
|
return int(bel_name.replace("WFG.WFG_R","")) + WFG_R_Z -1
|
||||||
|
elif tile_type.startswith("HSSL"):
|
||||||
|
if bel_type=="PMA":
|
||||||
|
return 0
|
||||||
|
elif bel_type=="CRX":
|
||||||
|
return int(bel_name.split(".")[0][7:]) * 2 - 1
|
||||||
|
else:
|
||||||
|
return int(bel_name.split(".")[0][7:]) * 2
|
||||||
|
elif tile_type.startswith("IOB") and tile_type in ["IOB0","IOB1","IOB6","IOB7"]: #direct
|
||||||
|
sp = bel_name.split(".")
|
||||||
|
if bel_type=="IOP":
|
||||||
|
return int(sp[0][1:]) * 4
|
||||||
|
else:
|
||||||
|
return (int(sp[0][3:])-1) * 4 + (1 if sp[1][0]=='I' else 2 if sp[1][0]=='O' else 3)
|
||||||
|
elif tile_type.startswith("IOB"): # complex
|
||||||
|
sp = bel_name.split(".")
|
||||||
|
if bel_type=="IOTP":
|
||||||
|
return (int(sp[0][1:3]) *2 + (1 if sp[0][3]=='N' else 0)) * 4
|
||||||
|
elif bel_type=="IOM":
|
||||||
|
return IOM_Z
|
||||||
|
else:
|
||||||
|
return (int(sp[0][3:])-1) * 4 + (1 if sp[1][0]=='I' else 2 if sp[1][0]=='O' else 3)
|
||||||
|
elif tile_type == "CGB":
|
||||||
|
if bel_type=="RAM":
|
||||||
|
return RAM_Z
|
||||||
|
elif bel_name=="S2.DSP1":
|
||||||
|
return DSP1_Z
|
||||||
|
else:
|
||||||
|
return DSP2_Z
|
||||||
|
elif tile_type == "SOCBank":
|
||||||
|
if bel_type=="SOCIF":
|
||||||
|
return SOCIF_Z
|
||||||
|
else:
|
||||||
|
return SERVICE_Z
|
||||||
|
elif tile_type == "TILE":
|
||||||
|
sp = bel_name.split(".")
|
||||||
|
if bel_type=="BEYOND_FE":
|
||||||
|
return (int(sp[1][2:])-1) % 32
|
||||||
|
elif bel_type=="CY":
|
||||||
|
pos = int(sp[1][2:])-1
|
||||||
|
# in S1, S5 and S9 they are ordered other way arround
|
||||||
|
return ((pos % 4) if pos < 12 else 3 - (pos % 4)) + CY_Z
|
||||||
|
elif bel_type=="XLUT":
|
||||||
|
return (int(sp[1][4:])-1) % 8 + XLUT_Z
|
||||||
|
elif bel_type=="RF":
|
||||||
|
return (int(sp[1][2:])-1) + RF_Z
|
||||||
|
elif bel_type=="XRF":
|
||||||
|
return (int(sp[1][3:])-1) + XRF_Z
|
||||||
|
elif bel_type=="FIFO":
|
||||||
|
return (int(sp[1][4:])-1) + FIFO_Z
|
||||||
|
elif bel_type=="XFIFO":
|
||||||
|
return (int(sp[1][5:])-1) + XFIFO_Z
|
||||||
|
elif bel_type=="CDC":
|
||||||
|
return (int(sp[1][3:])-1) + CDC_Z
|
||||||
|
elif bel_type=="XCDC":
|
||||||
|
return (int(sp[1][4:])-1) + XCDC_Z
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown bel type {bel_type}")
|
||||||
|
elif tile_type == "TUBE":
|
||||||
|
sp = bel_name.split(".")
|
||||||
|
return (int(sp[0][1:])-1)*20 + (int(sp[1][1:])-1)
|
||||||
|
else:
|
||||||
|
raise Exception(f"Unknown type {tile_type}")
|
||||||
|
|
||||||
|
if USE_LUT_PERMUTATION:
|
||||||
|
# Note PI1-PI4 are not real inputs but will appear
|
||||||
|
# before actual BEL input to enable LUT permutation
|
||||||
|
lut_to_beyond_fe = {
|
||||||
|
"I1" : "PI1",
|
||||||
|
"I2" : "PI2",
|
||||||
|
"I3" : "PI3",
|
||||||
|
"I4" : "PI4",
|
||||||
|
"O" : "LO",
|
||||||
|
"J" : "LJ",
|
||||||
|
"K" : "LK",
|
||||||
|
"D" : "LD",
|
||||||
|
"X" : "LX",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
lut_to_beyond_fe = {
|
||||||
|
"I1" : "I1",
|
||||||
|
"I2" : "I2",
|
||||||
|
"I3" : "I3",
|
||||||
|
"I4" : "I4",
|
||||||
|
"O" : "LO",
|
||||||
|
"J" : "LJ",
|
||||||
|
"K" : "LK",
|
||||||
|
"D" : "LD",
|
||||||
|
"X" : "LX",
|
||||||
|
}
|
||||||
|
|
||||||
|
dff_to_beyond_fe = {
|
||||||
|
"I" : "DI",
|
||||||
|
"O" : "DO",
|
||||||
|
"L" : "L",
|
||||||
|
"CK" : "CK",
|
||||||
|
"R" : "R",
|
||||||
|
"J" : "DJ",
|
||||||
|
"P" : "DP",
|
||||||
|
"C" : "DC",
|
||||||
|
"S" : "DS",
|
||||||
|
"K" : "DK",
|
||||||
|
}
|
||||||
|
|
||||||
|
def is_complex(tile_type):
|
||||||
|
return tile_type not in ["IOB0","IOB1","IOB6","IOB7"]
|
||||||
|
|
||||||
|
def map_to_beyond(tile_type,bel_name,bel_type=None):
|
||||||
|
if not tile_type in ["TILE"]:
|
||||||
|
return (bel_name,bel_type)
|
||||||
|
s = bel_name.split(".")
|
||||||
|
if tile_type in ["TILE"]:
|
||||||
|
# BEYOND_FE
|
||||||
|
if not (s[1].startswith("LUT") or s[1].startswith("DFF")):
|
||||||
|
return (bel_name,bel_type)
|
||||||
|
if len(s)==3:
|
||||||
|
# BEL and PORT
|
||||||
|
if s[1].startswith("LUT"):
|
||||||
|
pin = lut_to_beyond_fe[s[2]]
|
||||||
|
else:
|
||||||
|
pin = dff_to_beyond_fe[s[2]]
|
||||||
|
if pin is None:
|
||||||
|
return (None,bel_type)
|
||||||
|
return (s[0]+".FE"+s[1][3:]+"."+pin, bel_type if type(bel_type) is int else "BEYOND_FE")
|
||||||
|
else:
|
||||||
|
# just BEL
|
||||||
|
return (s[0]+".FE"+s[1][3:], "BEYOND_FE")
|
||||||
|
|
||||||
|
split_map = ["TILE", "CGB"]
|
||||||
|
|
||||||
|
def split_tilegrid(tilegrid):
|
||||||
|
new_tilegrid = dict()
|
||||||
|
for k,v in tilegrid.items():
|
||||||
|
if v["type"] not in split_map:
|
||||||
|
new_tilegrid[k] = dict()
|
||||||
|
data = dict(v)
|
||||||
|
data["orig"] = data["type"]
|
||||||
|
data["x"]=data["x"]*4
|
||||||
|
data["y"]=data["y"]*4
|
||||||
|
new_tilegrid[k][0] = data
|
||||||
|
else:
|
||||||
|
new_tilegrid[k] = dict()
|
||||||
|
for i in range(4*4):
|
||||||
|
data = dict(v)
|
||||||
|
data["orig"] = data["type"]
|
||||||
|
data["type"] = data["type"]+"_"+str(i)
|
||||||
|
data["x"]=data["x"]*4 + i // 4
|
||||||
|
data["y"]=data["y"]*4 + i % 4
|
||||||
|
new_tilegrid[k][i] = data
|
||||||
|
return new_tilegrid
|
||||||
|
|
||||||
|
def determine_subtile(tile,bel):
|
||||||
|
if tile=="TILE":
|
||||||
|
if bel.startswith("SYSTEM"):
|
||||||
|
s = 3
|
||||||
|
elif bel.startswith("RE") or bel.startswith("RS") or bel.startswith("RI"):
|
||||||
|
s = int(bel.split(".")[0][2:])-1
|
||||||
|
elif bel.startswith("S"):
|
||||||
|
s = int(bel.split(".")[0][1:])+3
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
return s
|
||||||
|
elif tile=="CGB":
|
||||||
|
if bel.startswith("SYSTEM"):
|
||||||
|
s = 6
|
||||||
|
elif bel.startswith("RE"):
|
||||||
|
s = 8
|
||||||
|
elif bel.startswith("RS"):
|
||||||
|
s = int(bel.split(".")[0][2:])
|
||||||
|
elif bel.startswith("RI"):
|
||||||
|
s = 5
|
||||||
|
elif bel.startswith("S1"):
|
||||||
|
s = 0
|
||||||
|
elif bel.startswith("S2.DSP1"):
|
||||||
|
s = 7
|
||||||
|
else:
|
||||||
|
return 15
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def split_per_bels(bels):
|
||||||
|
new_bels = dict()
|
||||||
|
for k,v in bels.items():
|
||||||
|
if k not in split_map:
|
||||||
|
new_bels[k] = dict()
|
||||||
|
data = dict(v)
|
||||||
|
new_bels[k][0] = data
|
||||||
|
else:
|
||||||
|
new_bels[k] = dict()
|
||||||
|
for i in range(4*4):
|
||||||
|
new_bels[k][i] = dict()
|
||||||
|
for item,bel in v.items():
|
||||||
|
(item, bel) = map_to_beyond(k,item,bel)
|
||||||
|
if item is not None:
|
||||||
|
num = determine_subtile(k,item)
|
||||||
|
new_bels[k][num][item] = bel
|
||||||
|
return new_bels
|
||||||
|
|
||||||
|
def lookup_port_type(t):
|
||||||
|
if t == "Input": return PinType.INPUT
|
||||||
|
elif t == "Output": return PinType.OUTPUT
|
||||||
|
elif t == "Bidir": return PinType.INOUT
|
||||||
|
else: assert False
|
||||||
|
|
||||||
|
def create_pips(tt, tile_type, muxes, num, args):
|
||||||
|
file_path = path.join(args.db, args.device, tile_type + ".txt")
|
||||||
|
if not path.isfile(file_path):
|
||||||
|
return
|
||||||
|
with open(file_path) as f:
|
||||||
|
for item in f:
|
||||||
|
line = item.strip().split(" ")
|
||||||
|
name1,_ = map_to_beyond(tile_type,line[0])
|
||||||
|
name2,_ = map_to_beyond(tile_type,line[1])
|
||||||
|
if name1 is None or name2 is None:
|
||||||
|
continue
|
||||||
|
num1 = determine_subtile(tile_type,name1)
|
||||||
|
num2 = determine_subtile(tile_type,name2)
|
||||||
|
|
||||||
|
if name2 in muxes:
|
||||||
|
name2 = name2 + "." + line[2]
|
||||||
|
if num1==num and not tt.has_wire(name1):
|
||||||
|
tt.create_wire(name=name1, type=tile_type + "_WIRE")
|
||||||
|
if num2==num and not tt.has_wire(name2):
|
||||||
|
tt.create_wire(name=name2, type=tile_type + "_WIRE")
|
||||||
|
timing_class = line[3]
|
||||||
|
# Only create PIP if both ends are in same subtile
|
||||||
|
if num1==num and num2==num:
|
||||||
|
tt.create_pip(name1,name2,timing_class)
|
||||||
|
|
||||||
|
def create_tile_types(ch: Chip, bels, bel_pins, crossbars, interconnects, muxes, args):
|
||||||
|
for tile_type,items in bels.items():
|
||||||
|
for num in items.keys():
|
||||||
|
if len(items)==1:
|
||||||
|
sub_type = tile_type
|
||||||
|
else:
|
||||||
|
sub_type = f"{tile_type}_{num}"
|
||||||
|
tt = ch.create_tile_type(sub_type)
|
||||||
|
|
||||||
|
def lookup_site_wire(canon_name):
|
||||||
|
if not tt.has_wire(canon_name):
|
||||||
|
tt.create_wire(name=canon_name, type="BEL_PIN_WIRE")
|
||||||
|
return canon_name
|
||||||
|
|
||||||
|
# Create BELs inside tile
|
||||||
|
for name,bel in bels[tile_type][num].items():
|
||||||
|
nb = tt.create_bel(name, bel, z=bel_z(tile_type,name,bel))
|
||||||
|
# Create wires for each BEL port
|
||||||
|
for index in bel_pins[bel].keys():
|
||||||
|
pin = bel_pins[bel][index]
|
||||||
|
tt.add_bel_pin(nb, pin["name"], lookup_site_wire(f"{name}."+pin["name"]), lookup_port_type(pin["direction"]))
|
||||||
|
if (tile_type.startswith("TILE") and bel=="BEYOND_FE"):
|
||||||
|
flag = 0
|
||||||
|
fe_nxd = int(name[name.index(".")+3:])
|
||||||
|
if (((fe_nxd-1) & 127) < 64):
|
||||||
|
if ((fe_nxd-1)&31) < 16:
|
||||||
|
if (fe_nxd & 1)==1:
|
||||||
|
flag |= BEL_EXTRA_FE_SCC
|
||||||
|
else:
|
||||||
|
if (fe_nxd & 1)==0:
|
||||||
|
flag |= BEL_EXTRA_FE_SCC
|
||||||
|
|
||||||
|
if fe_nxd in (65, 80, 81, 96, 225,240,241,256, 321,336,337,352):
|
||||||
|
flag |= BEL_EXTRA_FE_CSC
|
||||||
|
nb.extra_data = BelExtraData(flag)
|
||||||
|
|
||||||
|
# LUT drawers, LO already connected to LJ
|
||||||
|
vi = tt.create_pip(f"{name}.LJ",f"{name}.LK","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
vi = tt.create_pip(f"{name}.LJ",f"{name}.LD","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
vi = tt.create_pip(f"{name}.LJ",f"{name}.LX","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
# DFF drawers, DO already connected to DJ
|
||||||
|
vi = tt.create_pip(f"{name}.DJ",f"{name}.DP","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
vi = tt.create_pip(f"{name}.DJ",f"{name}.DC","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
vi = tt.create_pip(f"{name}.DJ",f"{name}.DS","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
vi = tt.create_pip(f"{name}.DJ",f"{name}.DK","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
# DFF bypass
|
||||||
|
by = tt.create_pip(f"{name}.DI",f"{name}.DO","BYPASS")
|
||||||
|
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)
|
||||||
|
# LUT bypass
|
||||||
|
by = tt.create_pip(f"{name}.I1",f"{name}.LO","BYPASS")
|
||||||
|
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,1,0)
|
||||||
|
elif (tile_type.startswith("TILE") and bel=="XLUT"):
|
||||||
|
for out in ["G1","G2","G3","G4"]:
|
||||||
|
vi = tt.create_pip(f"{name}.J",f"{name}.{out}","Virtual")
|
||||||
|
vi.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_VIRTUAL,0,0)
|
||||||
|
elif (tile_type.startswith("TILE") and bel=="CY"):
|
||||||
|
# matrix of each input to each output combination
|
||||||
|
# crossbar but use mux placeholder for convenience
|
||||||
|
for inp in ["I1","I2","I3","I4"]:
|
||||||
|
for out in ["O1","O2","O3","O4"]:
|
||||||
|
pd = tt.create_pip(f"{name}."+inp,f"{name}."+out,"MATRIX_PIP")
|
||||||
|
pd.extra_data = PipExtraData(ch.strs.id(f"{name}."+inp),PIP_EXTRA_MUX,int(inp[1:])-1,int(out[1:])-1)
|
||||||
|
|
||||||
|
elif (tile_type.startswith("CKG") and bel=="WFG"):
|
||||||
|
by = tt.create_pip(f"{name}.ZI",f"{name}.ZO","BYPASS")
|
||||||
|
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)
|
||||||
|
elif (tile_type.startswith("TUBE") and bel=="GCK"):
|
||||||
|
# 20 clock signals comming to 20 GCK, SI1 is bypass
|
||||||
|
by = tt.create_pip(f"{name}.SI1",f"{name}.SO","BYPASS")
|
||||||
|
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,0,0)
|
||||||
|
# there are CMD signals that can be bypassed as well
|
||||||
|
by = tt.create_pip(f"{name}.CMD",f"{name}.SO","BYPASS")
|
||||||
|
by.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_BYPASS,1,0)
|
||||||
|
|
||||||
|
|
||||||
|
# Add LUT permutation
|
||||||
|
if USE_LUT_PERMUTATION and tile_type=="TILE":
|
||||||
|
for name,bel in bels[tile_type][num].items():
|
||||||
|
if bel=="BEYOND_FE":
|
||||||
|
for inp in ["PI1","PI2","PI3","PI4"]:
|
||||||
|
tt.create_wire(name=f"{name}."+inp, type="LUT_PERMUTATION_WIRE")
|
||||||
|
for out in ["I1","I2","I3","I4"]:
|
||||||
|
pd = tt.create_pip(f"{name}."+inp,f"{name}."+out,"LUT_PERMUTATION")
|
||||||
|
pd.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_LUT_PERMUTATION,int(inp[2:])-1,int(out[1:])-1)
|
||||||
|
|
||||||
|
# Create crossbars as multiple PIPs
|
||||||
|
for name,xb in crossbars[tile_type][num].items():
|
||||||
|
inputs = list()
|
||||||
|
outputs = list()
|
||||||
|
for index in bel_pins[xb].keys():
|
||||||
|
pin = bel_pins[xb][index]
|
||||||
|
tt.create_wire(name=f"{name}."+pin["name"], type="CROSSBAR_"+xb+"_INPUT_WIRE" if pin["direction"] == "Input" else "CROSSBAR_"+xb+"_OUTPUT_WIRE")
|
||||||
|
for index in bel_pins[xb].keys():
|
||||||
|
pin = bel_pins[xb][index]
|
||||||
|
if pin["direction"] == "Input":
|
||||||
|
inputs.append(pin["name"])
|
||||||
|
else:
|
||||||
|
outputs.append(pin["name"])
|
||||||
|
for inp in inputs:
|
||||||
|
for out in outputs:
|
||||||
|
pd = tt.create_pip(f"{name}."+inp,f"{name}."+out,"CROSSBAR_"+xb)
|
||||||
|
pd.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_CROSSBAR,int(inp[1:])-1,int(out[1:])-1)
|
||||||
|
|
||||||
|
# Interconnects are just PIPs with one I and one O
|
||||||
|
for name,xb in interconnects[tile_type][num].items():
|
||||||
|
for index in bel_pins[xb].keys():
|
||||||
|
pin = bel_pins[xb][index]
|
||||||
|
tt.create_wire(name=f"{name}."+pin["name"], type="INTERCONNECT_INPUT" if pin["direction"] == "Input" else "INTERCONNECT_OUTPUT")
|
||||||
|
inp = f"{name}."+bel_pins[xb]["I"]["name"]
|
||||||
|
out = f"{name}."+bel_pins[xb]["O"]["name"]
|
||||||
|
pd = tt.create_pip(inp,out,"INTERCONNECT")
|
||||||
|
pd.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_INTERCONNECT,0,0)
|
||||||
|
|
||||||
|
# Create MUXes as many to one connections
|
||||||
|
if tile_type in muxes:
|
||||||
|
for (name, n) in muxes[tile_type][num].items():
|
||||||
|
for i in range(0,n+1):
|
||||||
|
new_name = name + "." + str(i)
|
||||||
|
if not tt.has_wire(new_name):
|
||||||
|
tt.create_wire(name=new_name, type="MUX_WIRE")
|
||||||
|
pd = tt.create_pip(new_name,name,"MUX_PIP")
|
||||||
|
pd.extra_data = PipExtraData(ch.strs.id(name),PIP_EXTRA_MUX,i,0)
|
||||||
|
|
||||||
|
m = muxes[tile_type] if tile_type in muxes else dict()
|
||||||
|
mux = muxes[tile_type][num] if num in m else dict()
|
||||||
|
create_pips(tt, tile_type, mux, num, args)
|
||||||
|
|
||||||
|
def create_null(ch: Chip):
|
||||||
|
tt = ch.create_tile_type("NULL")
|
||||||
|
|
||||||
|
def set_timings(ch, pip_timings, bel_timings):
|
||||||
|
speed = "DEFAULT"
|
||||||
|
tmg = ch.set_speed_grades([speed])
|
||||||
|
for k,v in pip_timings.items():
|
||||||
|
tmg.set_pip_class(grade=speed, name=k, delay=TimingValue(v[0]))
|
||||||
|
tmg.set_node_class(grade=speed, name=k, delay=TimingValue(v[0]))
|
||||||
|
tmg.set_pip_class(grade=speed, name="INTERCONNECT", delay=TimingValue(0))
|
||||||
|
tmg.set_pip_class(grade=speed, name="MUX_PIP", delay=TimingValue(0))
|
||||||
|
tmg.set_pip_class(grade=speed, name="MATRIX_PIP", delay=TimingValue(0))
|
||||||
|
tmg.set_pip_class(grade=speed, name="LUT_PERMUTATION", delay=TimingValue(0))
|
||||||
|
tmg.set_pip_class(grade=speed, name="BYPASS", delay=TimingValue(142))
|
||||||
|
for k,g in bel_timings.items():
|
||||||
|
primitive = ch.timing.add_cell_variant(speed, k)
|
||||||
|
for t,v in g.items():
|
||||||
|
if t=="IOPath":
|
||||||
|
for from_port,values in v.items():
|
||||||
|
for to_port,data in values.items():
|
||||||
|
primitive.add_comb_arc(from_port, to_port, TimingValue(data[0], data[1]))
|
||||||
|
elif t=="SetupHold":
|
||||||
|
for from_port,values in v.items():
|
||||||
|
for to_port,data in values.items():
|
||||||
|
primitive.add_setup_hold(from_port, to_port, ClockEdge.RISING, TimingValue(data[0]), TimingValue(data[1]))
|
||||||
|
elif t=="ClockOut":
|
||||||
|
for from_port,values in v.items():
|
||||||
|
for to_port,data in values.items():
|
||||||
|
primitive.add_clock_out(from_port, to_port, ClockEdge.RISING, TimingValue(data[0],data[1]))
|
||||||
|
|
||||||
|
def get_pos(tilegrid,name,bel):
|
||||||
|
tile = tilegrid[name][0]["orig"]
|
||||||
|
num = determine_subtile(tile,bel)
|
||||||
|
item = tilegrid[name][num]
|
||||||
|
x = item["x"]
|
||||||
|
y = item["y"]
|
||||||
|
return (tile,num,x,y)
|
||||||
|
|
||||||
|
|
||||||
|
global_connections = dict()
|
||||||
|
def load_globals(args):
|
||||||
|
print("Load global connections...")
|
||||||
|
with gzip.open(path.join(args.db, args.device, "GLOBAL.txt.gz"),"rt") as f:
|
||||||
|
for item in f:
|
||||||
|
line = item.strip().split(" ")
|
||||||
|
tile_name = line[0].split(":")[0]
|
||||||
|
if tile_name not in global_connections:
|
||||||
|
global_connections[tile_name] = dict()
|
||||||
|
if line[0] not in global_connections[tile_name]:
|
||||||
|
global_connections[tile_name][line[0]] = list()
|
||||||
|
global_connections[tile_name][line[0]].append(line)
|
||||||
|
|
||||||
|
def create_nodes(ch, tile_name, tilegrid, muxes, pip_timings):
|
||||||
|
if tile_name not in global_connections:
|
||||||
|
return
|
||||||
|
connections = global_connections[tile_name]
|
||||||
|
for key,val in connections.items():
|
||||||
|
name1 = key.split(":")
|
||||||
|
t1,_,x1,y1 = get_pos(tilegrid,name1[0],name1[1])
|
||||||
|
name1[1],_ = map_to_beyond(t1,name1[1])
|
||||||
|
if name1[1] is None:
|
||||||
|
continue
|
||||||
|
node = [NodeWire(x1, y1, name1[1])]
|
||||||
|
timing = None
|
||||||
|
timing_val = -1
|
||||||
|
for v in val:
|
||||||
|
name2 = v[1].split(":")
|
||||||
|
name2[1],_ = map_to_beyond(tilegrid[name2[0]][0]["orig"],name2[1])
|
||||||
|
t2,num,x2,y2 = get_pos(tilegrid,name2[0],name2[1])
|
||||||
|
if name2[1] is None:
|
||||||
|
continue
|
||||||
|
if pip_timings[v[3]][0] > timing_val:
|
||||||
|
timing_val = pip_timings[v[3]][0]
|
||||||
|
timing = v[3]
|
||||||
|
if t2 in muxes and num in muxes[t2] and name2[1] in muxes[t2][num]:
|
||||||
|
node.append(NodeWire(x2, y2, name2[1]+"."+v[2]))
|
||||||
|
else:
|
||||||
|
node.append(NodeWire(x2, y2, name2[1]))
|
||||||
|
|
||||||
|
ch.add_node(node,timing_class=timing)
|
||||||
|
|
||||||
|
|
||||||
|
subtile_connections = dict()
|
||||||
|
def create_nodes_subtiles(ch, tilegrid, name, tile_type, muxes, pip_timings, args):
|
||||||
|
if tile_type not in subtile_connections:
|
||||||
|
subtile_connections[tile_type] = dict()
|
||||||
|
|
||||||
|
file_path = path.join(args.db, args.device, tile_type + ".txt")
|
||||||
|
if not path.isfile(file_path):
|
||||||
|
return
|
||||||
|
with open(file_path) as f:
|
||||||
|
for item in f:
|
||||||
|
line = item.strip().split(" ")
|
||||||
|
name1 = line[0]
|
||||||
|
name2 = line[1]
|
||||||
|
name1,_ = map_to_beyond(tile_type,line[0])
|
||||||
|
name2,_ = map_to_beyond(tile_type,line[1])
|
||||||
|
if name1 is None or name2 is None:
|
||||||
|
continue
|
||||||
|
num1 = determine_subtile(tile_type,name1)
|
||||||
|
num2 = determine_subtile(tile_type,name2)
|
||||||
|
# Only create WIRE if ends are NOT in same subtile
|
||||||
|
if num1!=num2:
|
||||||
|
if name1 not in subtile_connections[tile_type] :
|
||||||
|
subtile_connections[tile_type][name1] = list()
|
||||||
|
subtile_connections[tile_type][name1].append([name1, name2, line[2], line[3]])
|
||||||
|
|
||||||
|
for name1,val in subtile_connections[tile_type].items():
|
||||||
|
_,_,x1,y1 = get_pos(tilegrid,name,name1)
|
||||||
|
node = [NodeWire(x1, y1, name1)]
|
||||||
|
timing_val = -1
|
||||||
|
timing = None
|
||||||
|
for v in val:
|
||||||
|
name2 = v[1]
|
||||||
|
t2,num,x2,y2 = get_pos(tilegrid,name,name2)
|
||||||
|
if pip_timings[v[3]][0] > timing_val:
|
||||||
|
timing_val = pip_timings[v[3]][0]
|
||||||
|
timing = v[3]
|
||||||
|
if t2 in muxes and num in muxes[t2] and name2 in muxes[t2][num]:
|
||||||
|
node.append(NodeWire(x2, y2, name2+"."+v[2]))
|
||||||
|
else:
|
||||||
|
node.append(NodeWire(x2, y2, name2))
|
||||||
|
|
||||||
|
ch.add_node(node,timing_class=timing)
|
||||||
|
|
||||||
|
def import_package(ch, package, bels, tilegrid):
|
||||||
|
pkg = ch.create_package(package)
|
||||||
|
for name, data in tilegrid.items():
|
||||||
|
for key, item in data.items():
|
||||||
|
ty = item["orig"]
|
||||||
|
x = item["x"]
|
||||||
|
y = item["y"]
|
||||||
|
if ty.startswith("IOB"):
|
||||||
|
for bel,ty in bels[ty][key].items():
|
||||||
|
# Support for native primitives
|
||||||
|
if ty =="IOTP":
|
||||||
|
pin = name+"_"+bel[:4]
|
||||||
|
elif ty =="IOP":
|
||||||
|
pin = name+"_"+bel[:3]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
pkg.create_pad(pin, f"X{x}Y{y}", bel, "", int(name[3:]))
|
||||||
|
|
||||||
|
def main():
|
||||||
|
xlbase = path.join(path.dirname(path.realpath(__file__)), "..")
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument("--db", help="Project Beyond device database path (e.g. ../prjbeyond/database)", type=str, required=True)
|
||||||
|
parser.add_argument("--device", help="name of device to export", type=str, required=True)
|
||||||
|
parser.add_argument("--constids", help="name of nextpnr constids file to read", type=str, default=path.join(xlbase, "constids.inc"))
|
||||||
|
parser.add_argument("--bba", help="bba file to write", type=str, required=True)
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
with open(path.join(args.db, "devices.json")) as f:
|
||||||
|
devices = json.load(f)
|
||||||
|
|
||||||
|
width = (devices["families"][args.device]["max_col"] + 1) * 4
|
||||||
|
height = (devices["families"][args.device]["max_row"] + 1) * 4
|
||||||
|
packages = devices["families"][args.device]["packages"]
|
||||||
|
|
||||||
|
ch = Chip("ng-ultra",args.device, width, height)
|
||||||
|
ch.strs.read_constids(path.join(path.dirname(__file__), "..", "constids.inc"))
|
||||||
|
|
||||||
|
# Data that is depending of location
|
||||||
|
with open(path.join(args.db, args.device, "tilegrid.json")) as f:
|
||||||
|
tilegrid = split_tilegrid(json.load(f))
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "bels.json")) as f:
|
||||||
|
bels = split_per_bels(json.load(f))
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "crossbars.json")) as f:
|
||||||
|
crossbars = split_per_bels(json.load(f))
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "interconnects.json")) as f:
|
||||||
|
interconnects = split_per_bels(json.load(f))
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "muxes.json")) as f:
|
||||||
|
muxes = split_per_bels(json.load(f))
|
||||||
|
|
||||||
|
# Data that is not related to position
|
||||||
|
with open(path.join(args.db, args.device, "bel_pins.json")) as f:
|
||||||
|
bel_pins = json.load(f)
|
||||||
|
bel_pins["IOP"]["IO"] = { "direction": "Bidir", "name": "IO" }
|
||||||
|
bel_pins["IOTP"]["IO"] = { "direction": "Bidir", "name": "IO" }
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "pip_timings.json")) as f:
|
||||||
|
pip_timings = json.load(f)
|
||||||
|
|
||||||
|
with open(path.join(args.db, args.device, "bel_timings.json")) as f:
|
||||||
|
bel_timings = json.load(f)
|
||||||
|
|
||||||
|
create_tile_types(ch, bels, bel_pins, crossbars, interconnects, muxes, args)
|
||||||
|
create_null(ch)
|
||||||
|
set_timings(ch, pip_timings, bel_timings)
|
||||||
|
|
||||||
|
for x in range(width):
|
||||||
|
for y in range(height):
|
||||||
|
ch.set_tile_type(x,y,"NULL")
|
||||||
|
|
||||||
|
load_globals(args)
|
||||||
|
for name, data in tilegrid.items():
|
||||||
|
for item in data.values():
|
||||||
|
ti = ch.set_tile_type(item["x"],item["y"],item["type"])
|
||||||
|
lobe = 0
|
||||||
|
if item["orig"] in ["TILE","CGB"]:
|
||||||
|
tmp = name.replace("TILE[","").replace("CGB[","").replace("]","")
|
||||||
|
x,y = tmp.split("x")
|
||||||
|
lobe = ((int(y)-1) // 12)*2 + (1 if int(x)>46 else 0) + 1
|
||||||
|
elif item["orig"].startswith("IOB") or item["orig"].startswith("HSSL"):
|
||||||
|
match item["orig"]:
|
||||||
|
case "IOB0" | "IOB1":
|
||||||
|
lobe = 5
|
||||||
|
case "IOB6" | "IOB7":
|
||||||
|
lobe = 6
|
||||||
|
case "IOB8" | "IOB9" | "IOB10":
|
||||||
|
lobe = 2
|
||||||
|
case "IOB11" | "IOB12" | "IOB13":
|
||||||
|
lobe = 1
|
||||||
|
case "IOB2" | "IOB3" | "HSSL0" | "HSSL1" | "HSSL2" | "HSSL3":
|
||||||
|
lobe = 7
|
||||||
|
case "IOB4" | "IOB5" | "HSSL4" | "HSSL5" | "HSSL6" | "HSSL7":
|
||||||
|
lobe = 8
|
||||||
|
tile_type = 0
|
||||||
|
if item["orig"] in ["TILE","CGB","MESH"]:
|
||||||
|
tile_type = TILE_EXTRA_FABRIC
|
||||||
|
elif item["orig"] in ["TUBE"]:
|
||||||
|
tile_type = TILE_EXTRA_TUBE
|
||||||
|
elif item["orig"] in ["SOCBank"]:
|
||||||
|
tile_type = TILE_EXTRA_SOC
|
||||||
|
elif item["orig"].startswith("IOB") or item["orig"].startswith("HSSL") or item["orig"].startswith("CKG"):
|
||||||
|
tile_type = TILE_EXTRA_RING
|
||||||
|
elif item["orig"].startswith("FENCE"):
|
||||||
|
tile_type = TILE_EXTRA_FENCE
|
||||||
|
|
||||||
|
ti.extra_data = TileExtraData(ch.strs.id(name),lobe, tile_type)
|
||||||
|
|
||||||
|
for name, data in tilegrid.items():
|
||||||
|
print(f"Generate nodes for {name}...")
|
||||||
|
create_nodes_subtiles(ch, tilegrid, name, data[0]["orig"], muxes, pip_timings, args)
|
||||||
|
create_nodes(ch, name, tilegrid, muxes, pip_timings)
|
||||||
|
|
||||||
|
for package in packages:
|
||||||
|
import_package(ch, package, bels, tilegrid)
|
||||||
|
|
||||||
|
ch.write_bba(args.bba)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
569
himbaechel/uarch/ng-ultra/location_map.cc
Normal file
569
himbaechel/uarch/ng-ultra/location_map.cc
Normal file
@ -0,0 +1,569 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 "location_map.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
/* clang-format off */
|
||||||
|
const Loc ng_ultra_place_cy_map[24] = {
|
||||||
|
{ 0, 1, 0}, // S1 0 -> S2 0 CY24->CY1
|
||||||
|
{ 0, 0, -1}, // S1 1 -> S1 0 CY23->CY24
|
||||||
|
{ 0, 0, -1}, // S1 2 -> S1 1 CY22->CY23
|
||||||
|
{ 0, 0, -1}, // S1 3 -> S1 2 CY21->CY22
|
||||||
|
|
||||||
|
{-1, 0, +3}, // S5 0 -> S1 1 CY20->CY21
|
||||||
|
{ 0, 0, -1}, // S5 1 -> S5 0 CY19->CY20
|
||||||
|
{ 0, 0, -1}, // S5 2 -> S5 1 CY18->CY19
|
||||||
|
{ 0, 0, -1}, // S5 3 -> S5 2 CY17->CY18
|
||||||
|
|
||||||
|
{-1, 0, +3}, // S9 0 -> S5 1 CY16->CY17
|
||||||
|
{ 0, 0, -1}, // S9 1 -> S9 0 CY15->CY16
|
||||||
|
{ 0, 0, -1}, // S9 2 -> S9 1 CY14->CY15
|
||||||
|
{ 0, 0, -1}, // S9 3 -> S9 2 CY13->CY14
|
||||||
|
|
||||||
|
{ 0, 0, +1}, // S2 0 -> S2 1 CY1->CY2
|
||||||
|
{ 0, 0, +1}, // S2 1 -> S2 2 CY2->CY3
|
||||||
|
{ 0, 0, +1}, // S2 2 -> S2 3 CY3->CY4
|
||||||
|
{ 1, 0, -3}, // S2 3 -> S6 0 CY4->CY5
|
||||||
|
|
||||||
|
{ 0, 0, +1}, // S6 0 -> S6 1 CY5->CY6
|
||||||
|
{ 0, 0, +1}, // S6 1 -> S6 2 CY6->CY7
|
||||||
|
{ 0, 0, +1}, // S6 2 -> S6 3 CY7->CY8
|
||||||
|
{ 1, 0, -3}, // S6 3 -> S10 0 CY8->CY9
|
||||||
|
|
||||||
|
{ 0, 0, +1}, // S10 0 -> S10 1 CY9->CY10
|
||||||
|
{ 0, 0, +1}, // S10 1 -> S10 2 CY10->CY11
|
||||||
|
{ 0, 0, +1}, // S10 2 -> S10 3 CY11->CY12
|
||||||
|
{ 0, -1, 0}, // S10 3 -> S9 3 CY12->CY13
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_xrf[] = {
|
||||||
|
{-1, 0, 1}, // I/O1
|
||||||
|
{-1, 0, 2}, // I/O2
|
||||||
|
{-1, 0, 5}, // I/O3
|
||||||
|
{-1, 0, 6}, // I/O4
|
||||||
|
{-1, 0, 7}, // I/O5
|
||||||
|
{-1, 0, 9}, // I/O6
|
||||||
|
{-1, 0, 10}, // I/O7
|
||||||
|
{-1, 0, 13}, // I/O8
|
||||||
|
{-1, 0, 14}, // I/O9
|
||||||
|
{-1, 0, 15}, // I/O10
|
||||||
|
{-1, 0, 16}, // I/O11
|
||||||
|
{-1, 0, 17}, // I/O12
|
||||||
|
{-1, 0, 18}, // I/O13
|
||||||
|
{-1, 0, 21}, // I/O14
|
||||||
|
{-1, 0, 24}, // I/O15
|
||||||
|
{-1, 0, 25}, // I/O16
|
||||||
|
{-1, 0, 26}, // I/O17
|
||||||
|
{-1, 0, 29}, // I/O18
|
||||||
|
|
||||||
|
{+1, 0, 1}, // I/O19
|
||||||
|
{+1, 0, 2}, // I/O20
|
||||||
|
{+1, 0, 5}, // I/O21
|
||||||
|
{+1, 0, 6}, // I/O22
|
||||||
|
{+1, 0, 7}, // I/O23
|
||||||
|
{+1, 0, 9}, // I/O24
|
||||||
|
{+1, 0, 10}, // I/O25
|
||||||
|
{+1, 0, 13}, // I/O26
|
||||||
|
{+1, 0, 14}, // I/O27
|
||||||
|
{+1, 0, 15}, // I/O28
|
||||||
|
{+1, 0, 16}, // I/O29
|
||||||
|
{+1, 0, 17}, // I/O30
|
||||||
|
{+1, 0, 18}, // I/O31
|
||||||
|
{+1, 0, 21}, // I/O32
|
||||||
|
{+1, 0, 24}, // I/O33
|
||||||
|
{+1, 0, 25}, // I/O34
|
||||||
|
{+1, 0, 26}, // I/O35
|
||||||
|
{+1, 0, 29}, // I/O36
|
||||||
|
|
||||||
|
{-1, 0, 4}, // RA1
|
||||||
|
{-1, 0, 12}, // RA2
|
||||||
|
{-1, 0, 20}, // RA3
|
||||||
|
{-1, 0, 27}, // RA4
|
||||||
|
{-1, 0, 31}, // RA5
|
||||||
|
|
||||||
|
{+1, 0, 4}, // RA6
|
||||||
|
{+1, 0, 12}, // RA7
|
||||||
|
{+1, 0, 20}, // RA8
|
||||||
|
{+1, 0, 27}, // RA9
|
||||||
|
{+1, 0, 31}, // RA10
|
||||||
|
|
||||||
|
{-1, 0, 3}, // WA1
|
||||||
|
{-1, 0, 11}, // WA2
|
||||||
|
{-1, 0, 19}, // WA3
|
||||||
|
{-1, 0, 23}, // WA4
|
||||||
|
{-1, 0, 28}, // WA5
|
||||||
|
|
||||||
|
{+1, 0, 3}, // WA6
|
||||||
|
|
||||||
|
{-1, 0, 0}, // WE
|
||||||
|
{-1, 0, 8}, // WEA
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_cdc1[] = {
|
||||||
|
{+1, 0, 1}, // AI1
|
||||||
|
{+1, 0, 2}, // AI2
|
||||||
|
{+1, 0, 9}, // AI3
|
||||||
|
{+1, 0, 17}, // AI4
|
||||||
|
{+1, 0, 18}, // AI5
|
||||||
|
{+1, 0, 25}, // AI6
|
||||||
|
|
||||||
|
{+1, 0, 3}, // BI1
|
||||||
|
{+1, 0, 10}, // BI2
|
||||||
|
{+1, 0, 11}, // BI3
|
||||||
|
{+1, 0, 19}, // BI4
|
||||||
|
{+1, 0, 26}, // BI5
|
||||||
|
{+1, 0, 27}, // BI6
|
||||||
|
|
||||||
|
{ 0, 0, 22}, // ASRSTI
|
||||||
|
{ 0, 0, 30}, // ADRSTI
|
||||||
|
{+1, 0, 24}, // BSRSTI
|
||||||
|
{+1, 0, 8}, // BDRSTI
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_cdc2[] = {
|
||||||
|
{-1, 0, 4}, // AI1
|
||||||
|
{-1, 0, 5}, // AI2
|
||||||
|
{-1, 0, 12}, // AI3
|
||||||
|
{-1, 0, 20}, // AI4
|
||||||
|
{-1, 0, 21}, // AI5
|
||||||
|
{-1, 0, 28}, // AI6
|
||||||
|
|
||||||
|
{-1, 0, 6}, // BI1
|
||||||
|
{-1, 0, 13}, // BI2
|
||||||
|
{-1, 0, 14}, // BI3
|
||||||
|
{-1, 0, 22}, // BI4
|
||||||
|
{-1, 0, 29}, // BI5
|
||||||
|
{-1, 0, 30}, // BI6
|
||||||
|
|
||||||
|
{ 0, 0, 22}, // ASRSTI
|
||||||
|
{ 0, 0, 30}, // ADRSTI
|
||||||
|
{-1, 0, 23}, // BSRSTI
|
||||||
|
{-1, 0, 7}, // BDRSTI
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_xcdc[] = {
|
||||||
|
{ 0, 0, 1}, // AI1
|
||||||
|
{ 0, 0, 2}, // AI2
|
||||||
|
{ 0, 0, 9}, // AI3
|
||||||
|
{ 0, 0, 17}, // AI4
|
||||||
|
{ 0, 0, 18}, // AI5
|
||||||
|
{ 0, 0, 25}, // AI6
|
||||||
|
|
||||||
|
{ 0, 0, 4}, // BI1
|
||||||
|
{ 0, 0, 5}, // BI2
|
||||||
|
{ 0, 0, 12}, // BI3
|
||||||
|
{ 0, 0, 20}, // BI4
|
||||||
|
{ 0, 0, 21}, // BI5
|
||||||
|
{ 0, 0, 28}, // BI6
|
||||||
|
|
||||||
|
{-1, 0, 22}, // ASRSTI
|
||||||
|
{-1, 0, 30}, // ADRSTI
|
||||||
|
{+1, 0, 22}, // BSRSTI
|
||||||
|
{+1, 0, 30}, // BDRSTI
|
||||||
|
|
||||||
|
{ 0, 0, 3}, // CI1
|
||||||
|
{ 0, 0, 10}, // CI2
|
||||||
|
{ 0, 0, 11}, // CI3
|
||||||
|
{ 0, 0, 19}, // CI4
|
||||||
|
{ 0, 0, 26}, // CI5
|
||||||
|
{ 0, 0, 27}, // CI6
|
||||||
|
|
||||||
|
{ 0, 0, 6}, // DI1
|
||||||
|
{ 0, 0, 13}, // DI2
|
||||||
|
{ 0, 0, 14}, // DI3
|
||||||
|
{ 0, 0, 22}, // DI4
|
||||||
|
{ 0, 0, 29}, // DI5
|
||||||
|
{ 0, 0, 30}, // DI6
|
||||||
|
|
||||||
|
{ 0, 0, 24}, // CSRSTI
|
||||||
|
{ 0, 0, 8}, // CDRSTI
|
||||||
|
{ 0, 0, 23}, // DSRSTI
|
||||||
|
{ 0, 0, 7}, // DDRSTI
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_fifo1[] = {
|
||||||
|
{-1, 0, 1}, // I/O1
|
||||||
|
{-1, 0, 2}, // I/O2
|
||||||
|
{-1, 0, 5}, // I/O3
|
||||||
|
{-1, 0, 6}, // I/O4
|
||||||
|
{-1, 0, 7}, // I/O5
|
||||||
|
{-1, 0, 9}, // I/O6
|
||||||
|
{-1, 0, 10}, // I/O7
|
||||||
|
{-1, 0, 13}, // I/O8
|
||||||
|
{-1, 0, 14}, // I/O9
|
||||||
|
{-1, 0, 15}, // I/O10
|
||||||
|
{-1, 0, 16}, // I/O11
|
||||||
|
{-1, 0, 17}, // I/O12
|
||||||
|
{-1, 0, 18}, // I/O13
|
||||||
|
{-1, 0, 21}, // I/O14
|
||||||
|
{-1, 0, 24}, // I/O15
|
||||||
|
{-1, 0, 25}, // I/O16
|
||||||
|
{-1, 0, 26}, // I/O17
|
||||||
|
{-1, 0, 29}, // I/O18
|
||||||
|
|
||||||
|
{ 0, 0, 0}, // I/O19
|
||||||
|
{ 0, 0, 0}, // I/O20
|
||||||
|
{ 0, 0, 0}, // I/O21
|
||||||
|
{ 0, 0, 0}, // I/O22
|
||||||
|
{ 0, 0, 0}, // I/O23
|
||||||
|
{ 0, 0, 0}, // I/O24
|
||||||
|
{ 0, 0, 0}, // I/O25
|
||||||
|
{ 0, 0, 0}, // I/O26
|
||||||
|
{ 0, 0, 0}, // I/O27
|
||||||
|
{ 0, 0, 0}, // I/O28
|
||||||
|
{ 0, 0, 0}, // I/O29
|
||||||
|
{ 0, 0, 0}, // I/O30
|
||||||
|
{ 0, 0, 0}, // I/O31
|
||||||
|
{ 0, 0, 0}, // I/O32
|
||||||
|
{ 0, 0, 0}, // I/O33
|
||||||
|
{ 0, 0, 0}, // I/O34
|
||||||
|
{ 0, 0, 0}, // I/O35
|
||||||
|
{ 0, 0, 0}, // I/O36
|
||||||
|
|
||||||
|
{ 0, 0, 3}, // RAI1/RAO1
|
||||||
|
{ 0, 0, 10}, // RAI2/RAO2
|
||||||
|
{ 0, 0, 11}, // RAI3/RAO3
|
||||||
|
{ 0, 0, 19}, // RAI4/RAO4
|
||||||
|
{ 0, 0, 26}, // RAI5/RAO5
|
||||||
|
{ 0, 0, 27}, // RAI6/RAO6
|
||||||
|
{ 0, 0, 0}, // RAI7/RAO7
|
||||||
|
|
||||||
|
{ 0, 0, 1}, // WAI1/WAO1
|
||||||
|
{ 0, 0, 2}, // WAI2/WAO2
|
||||||
|
{ 0, 0, 9}, // WAI3/WAO3
|
||||||
|
{ 0, 0, 17}, // WAI4/WAO4
|
||||||
|
{ 0, 0, 18}, // WAI5/WAO5
|
||||||
|
{ 0, 0, 25}, // WAI6/WAO6
|
||||||
|
{ 0, 0, 0}, // WAI7/WAO7
|
||||||
|
|
||||||
|
{-1, 0, 0}, // WE
|
||||||
|
{-1, 0, 8}, // WEA
|
||||||
|
|
||||||
|
{-1, 0, 22}, // WRSTI1/WRSTO
|
||||||
|
{-1, 0, 30}, // RRSTI1/RRSTO
|
||||||
|
{ 0, 0, 8}, // WRSTI2
|
||||||
|
{ 0, 0, 24}, // RRSTI2
|
||||||
|
{ 0, 0, 0}, // WRSTI3/WRSTO
|
||||||
|
{ 0, 0, 0}, // RRSTI3/RRSTO
|
||||||
|
{ 0, 0, 0}, // WRSTI4
|
||||||
|
{ 0, 0, 0}, // RRSTI4
|
||||||
|
|
||||||
|
{-1, 0, 3}, // WEQ
|
||||||
|
{-1, 0, 4}, // REQ
|
||||||
|
// {-1, 0, 11}, WEQ
|
||||||
|
// {-1, 0, 12}, REQ
|
||||||
|
// {-1, 0, 19}, WEQ
|
||||||
|
// {-1, 0, 20}, REQ
|
||||||
|
// {-1, 0, 27}, WEQ
|
||||||
|
// {-1, 0, 28}, REQ
|
||||||
|
{ 0, 0, 0}, // WEQ2
|
||||||
|
{ 0, 0, 0}, // REQ2
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_fifo2[] = {
|
||||||
|
{+1, 0, 1}, // I/O1
|
||||||
|
{+1, 0, 2}, // I/O2
|
||||||
|
{+1, 0, 5}, // I/O3
|
||||||
|
{+1, 0, 6}, // I/O4
|
||||||
|
{+1, 0, 7}, // I/O5
|
||||||
|
{+1, 0, 9}, // I/O6
|
||||||
|
{+1, 0, 10}, // I/O7
|
||||||
|
{+1, 0, 13}, // I/O8
|
||||||
|
{+1, 0, 14}, // I/O9
|
||||||
|
{+1, 0, 15}, // I/O10
|
||||||
|
{+1, 0, 16}, // I/O11
|
||||||
|
{+1, 0, 17}, // I/O12
|
||||||
|
{+1, 0, 18}, // I/O13
|
||||||
|
{+1, 0, 21}, // I/O14
|
||||||
|
{+1, 0, 24}, // I/O15
|
||||||
|
{+1, 0, 25}, // I/O16
|
||||||
|
{+1, 0, 26}, // I/O17
|
||||||
|
{+1, 0, 29}, // I/O18
|
||||||
|
|
||||||
|
{ 0, 0, 0}, // I/O19
|
||||||
|
{ 0, 0, 0}, // I/O20
|
||||||
|
{ 0, 0, 0}, // I/O21
|
||||||
|
{ 0, 0, 0}, // I/O22
|
||||||
|
{ 0, 0, 0}, // I/O23
|
||||||
|
{ 0, 0, 0}, // I/O24
|
||||||
|
{ 0, 0, 0}, // I/O25
|
||||||
|
{ 0, 0, 0}, // I/O26
|
||||||
|
{ 0, 0, 0}, // I/O27
|
||||||
|
{ 0, 0, 0}, // I/O28
|
||||||
|
{ 0, 0, 0}, // I/O29
|
||||||
|
{ 0, 0, 0}, // I/O30
|
||||||
|
{ 0, 0, 0}, // I/O31
|
||||||
|
{ 0, 0, 0}, // I/O32
|
||||||
|
{ 0, 0, 0}, // I/O33
|
||||||
|
{ 0, 0, 0}, // I/O34
|
||||||
|
{ 0, 0, 0}, // I/O35
|
||||||
|
{ 0, 0, 0}, // I/O36
|
||||||
|
|
||||||
|
{ 0, 0, 6}, // RAI1/RAO1
|
||||||
|
{ 0, 0, 13}, // RAI2/RAO2
|
||||||
|
{ 0, 0, 14}, // RAI3/RAO3
|
||||||
|
{ 0, 0, 22}, // RAI4/RAO4
|
||||||
|
{ 0, 0, 29}, // RAI5/RAO5
|
||||||
|
{ 0, 0, 30}, // RAI6/RAO6
|
||||||
|
{ 0, 0, 0}, // RAI7/RAO7
|
||||||
|
|
||||||
|
{ 0, 0, 4}, // WAI1/WAO1
|
||||||
|
{ 0, 0, 5}, // WAI2/WAO2
|
||||||
|
{ 0, 0, 12}, // WAI3/WAO3
|
||||||
|
{ 0, 0, 20}, // WAI4/WAO4
|
||||||
|
{ 0, 0, 21}, // WAI5/WAO5
|
||||||
|
{ 0, 0, 28}, // WAI6/WAO6
|
||||||
|
{ 0, 0, 0}, // WAI7/WAO7
|
||||||
|
|
||||||
|
{+1, 0, 0}, // WE
|
||||||
|
{+1, 0, 8}, // WEA
|
||||||
|
|
||||||
|
{+1, 0, 22}, // WRSTI1/WRSTO
|
||||||
|
{+1, 0, 30}, // RRSTI1/RRSTO
|
||||||
|
{ 0, 0, 7}, // WRSTI2
|
||||||
|
{ 0, 0, 23}, // RRSTI2
|
||||||
|
{ 0, 0, 0}, // WRSTI3/WRSTO
|
||||||
|
{ 0, 0, 0}, // RRSTI3/RRSTO
|
||||||
|
{ 0, 0, 0}, // WRSTI4
|
||||||
|
{ 0, 0, 0}, // RRSTI4
|
||||||
|
|
||||||
|
{+1, 0, 3}, // WEQ
|
||||||
|
{+1, 0, 4}, // REQ
|
||||||
|
// {+1, 0, 11}, WEQ
|
||||||
|
// {+1, 0, 12}, REQ
|
||||||
|
// {+1, 0, 19}, WEQ
|
||||||
|
// {+1, 0, 20}, REQ
|
||||||
|
// {+1, 0, 27}, WEQ
|
||||||
|
// {+1, 0, 28}, REQ
|
||||||
|
{ 0, 0, 0}, // WEQ2
|
||||||
|
{ 0, 0, 0}, // REQ2
|
||||||
|
};
|
||||||
|
|
||||||
|
const Loc ng_ultra_place_xfifo[] = {
|
||||||
|
{-1, 0, 1}, // I/O1
|
||||||
|
{-1, 0, 2}, // I/O2
|
||||||
|
{-1, 0, 5}, // I/O3
|
||||||
|
{-1, 0, 6}, // I/O4
|
||||||
|
{-1, 0, 7}, // I/O5
|
||||||
|
{-1, 0, 9}, // I/O6
|
||||||
|
{-1, 0, 10}, // I/O7
|
||||||
|
{-1, 0, 13}, // I/O8
|
||||||
|
{-1, 0, 14}, // I/O9
|
||||||
|
{-1, 0, 15}, // I/O10
|
||||||
|
{-1, 0, 16}, // I/O11
|
||||||
|
{-1, 0, 17}, // I/O12
|
||||||
|
{-1, 0, 18}, // I/O13
|
||||||
|
{-1, 0, 21}, // I/O14
|
||||||
|
{-1, 0, 24}, // I/O15
|
||||||
|
{-1, 0, 25}, // I/O16
|
||||||
|
{-1, 0, 26}, // I/O17
|
||||||
|
{-1, 0, 29}, // I/O18
|
||||||
|
{+1, 0, 1}, // I/O19
|
||||||
|
{+1, 0, 2}, // I/O20
|
||||||
|
{+1, 0, 5}, // I/O21
|
||||||
|
{+1, 0, 6}, // I/O22
|
||||||
|
{+1, 0, 7}, // I/O23
|
||||||
|
{+1, 0, 9}, // I/O24
|
||||||
|
{+1, 0, 10}, // I/O25
|
||||||
|
{+1, 0, 13}, // I/O26
|
||||||
|
{+1, 0, 14}, // I/O27
|
||||||
|
{+1, 0, 15}, // I/O28
|
||||||
|
{+1, 0, 16}, // I/O29
|
||||||
|
{+1, 0, 17}, // I/O30
|
||||||
|
{+1, 0, 18}, // I/O31
|
||||||
|
{+1, 0, 21}, // I/O32
|
||||||
|
{+1, 0, 24}, // I/O33
|
||||||
|
{+1, 0, 25}, // I/O34
|
||||||
|
{+1, 0, 26}, // I/O35
|
||||||
|
{+1, 0, 29}, // I/O36
|
||||||
|
|
||||||
|
{ 0, 0, 3}, // RAI1/RAO1
|
||||||
|
{ 0, 0, 10}, // RAI2/RAO2
|
||||||
|
{ 0, 0, 11}, // RAI3/RAO3
|
||||||
|
{ 0, 0, 19}, // RAI4/RAO4
|
||||||
|
{ 0, 0, 26}, // RAI5/RAO5
|
||||||
|
{ 0, 0, 27}, // RAI6/RAO6
|
||||||
|
{ 0, 0, 6}, // RAI7/RAO7
|
||||||
|
|
||||||
|
{ 0, 0, 1}, // WAI1/WAO1
|
||||||
|
{ 0, 0, 2}, // WAI2/WAO2
|
||||||
|
{ 0, 0, 9}, // WAI3/WAO3
|
||||||
|
{ 0, 0, 17}, // WAI4/WAO4
|
||||||
|
{ 0, 0, 18}, // WAI5/WAO5
|
||||||
|
{ 0, 0, 25}, // WAI6/WAO6
|
||||||
|
{ 0, 0, 4}, // WAI7/WAO7
|
||||||
|
|
||||||
|
{-1, 0, 0}, // WE
|
||||||
|
{-1, 0, 8}, // WEA
|
||||||
|
|
||||||
|
{-1, 0, 22}, // WRSTI1/WRSTO
|
||||||
|
{-1, 0, 30}, // RRSTI1/RRSTO
|
||||||
|
{ 0, 0, 8}, // WRSTI2
|
||||||
|
{ 0, 0, 24}, // RRSTI2
|
||||||
|
{+1, 0, 22}, // WRSTI3/WRSTO
|
||||||
|
{+1, 0, 30}, // RRSTI3/RRSTO
|
||||||
|
{ 0, 0, 7}, // WRSTI4
|
||||||
|
{ 0, 0, 23}, // RRSTI4
|
||||||
|
|
||||||
|
{-1, 0, 3}, // WEQ1
|
||||||
|
{-1, 0, 4}, // REQ1
|
||||||
|
// {-1, 0, 11}, WEQ1
|
||||||
|
// {-1, 0, 12}, REQ1
|
||||||
|
// {-1, 0, 19}, WEQ1
|
||||||
|
// {-1, 0, 20}, REQ1
|
||||||
|
// {-1, 0, 27}, WEQ1
|
||||||
|
// {-1, 0, 28}, REQ1
|
||||||
|
{+1, 0, 3}, // WEQ2
|
||||||
|
{+1, 0, 4}, // REQ2
|
||||||
|
// {+1, 0, 11}, WEQ2
|
||||||
|
// {+1, 0, 12}, REQ2
|
||||||
|
// {+1, 0, 19}, WEQ2
|
||||||
|
// {+1, 0, 20}, REQ2
|
||||||
|
// {+1, 0, 27}, WEQ2
|
||||||
|
// {+1, 0, 28}, REQ2
|
||||||
|
};
|
||||||
|
/* clang-format on */
|
||||||
|
|
||||||
|
}; // namespace
|
||||||
|
|
||||||
|
namespace ng_ultra {
|
||||||
|
|
||||||
|
Loc getNextLocInDSPChain(const NgUltraImpl *impl, Loc loc)
|
||||||
|
{
|
||||||
|
BelId bel = impl->ctx->getBelByLocation(loc);
|
||||||
|
if (impl->dsp_cascade.count(bel) == 0) {
|
||||||
|
loc.z = -1; // End of chain
|
||||||
|
return loc;
|
||||||
|
}
|
||||||
|
BelId dsp = impl->dsp_cascade.at(bel);
|
||||||
|
return impl->ctx->getBelLocation(dsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getNextLocInCYChain(Loc loc)
|
||||||
|
{
|
||||||
|
int section = (loc.x % 4 - 1 + 3 * (loc.y % 4)) * 4 + loc.z - BEL_CY_Z;
|
||||||
|
Loc result = ng_ultra_place_cy_map[section];
|
||||||
|
result.x += loc.x;
|
||||||
|
result.y += loc.y;
|
||||||
|
result.z += loc.z;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getNextLocInLUTChain(Loc loc)
|
||||||
|
{
|
||||||
|
Loc result = loc;
|
||||||
|
result.x = loc.x;
|
||||||
|
result.y = loc.y;
|
||||||
|
result.z = (loc.z + 8) % 32; // BEL_LUT_Z is 0
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getNextLocInDFFChain(Loc loc)
|
||||||
|
{
|
||||||
|
Loc result = loc;
|
||||||
|
if (loc.z == 31) {
|
||||||
|
if ((loc.x & 3) == 3) {
|
||||||
|
result.z = -1; // End of chain
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.z = 0;
|
||||||
|
result.x++;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int z = loc.z + 8;
|
||||||
|
if (z > 31)
|
||||||
|
z++;
|
||||||
|
result.z = z % 32; // BEL_LUT_Z is 0
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getCYFE(Loc root, int pos)
|
||||||
|
{
|
||||||
|
int p[] = {2 - 1, 25 - 1, 10 - 1, 17 - 1};
|
||||||
|
int cy = root.z - BEL_CY_Z;
|
||||||
|
Loc result;
|
||||||
|
result.x = root.x;
|
||||||
|
result.y = root.y;
|
||||||
|
result.z = p[pos] + cy * 2;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getXLUTFE(Loc root, int pos)
|
||||||
|
{
|
||||||
|
Loc result;
|
||||||
|
result.x = root.x;
|
||||||
|
result.y = root.y;
|
||||||
|
result.z = root.z - BEL_XLUT_Z + 8 * pos;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getXRFFE(Loc root, int pos)
|
||||||
|
{
|
||||||
|
Loc result = ng_ultra_place_xrf[pos];
|
||||||
|
if (root.z == BEL_XRF_Z) {
|
||||||
|
// XRF1
|
||||||
|
result.x += root.x;
|
||||||
|
} else {
|
||||||
|
// RF1 or RF2
|
||||||
|
result.x = root.x + ((root.z == BEL_RF_Z) ? -1 : +1);
|
||||||
|
}
|
||||||
|
result.y = root.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getCDCFE(Loc root, int pos)
|
||||||
|
{
|
||||||
|
Loc result;
|
||||||
|
if (root.z == BEL_CDC_Z) {
|
||||||
|
result = ng_ultra_place_cdc1[pos];
|
||||||
|
} else if (root.z == BEL_CDC_Z + 1) {
|
||||||
|
result = ng_ultra_place_cdc2[pos];
|
||||||
|
} else if (root.z == BEL_XCDC_Z) {
|
||||||
|
result = ng_ultra_place_xcdc[pos];
|
||||||
|
} else {
|
||||||
|
log_error("Trying to place CDC on wrong location.\n");
|
||||||
|
}
|
||||||
|
result.x += root.x;
|
||||||
|
result.y = root.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loc getFIFOFE(Loc root, int pos)
|
||||||
|
{
|
||||||
|
Loc result;
|
||||||
|
if (root.z == BEL_FIFO_Z) {
|
||||||
|
result = ng_ultra_place_fifo1[pos];
|
||||||
|
} else if (root.z == BEL_FIFO_Z + 1) {
|
||||||
|
result = ng_ultra_place_fifo2[pos];
|
||||||
|
} else if (root.z == BEL_XFIFO_Z) {
|
||||||
|
result = ng_ultra_place_xfifo[pos];
|
||||||
|
} else {
|
||||||
|
log_error("Trying to place CDC on wrong location.\n");
|
||||||
|
}
|
||||||
|
result.x += root.x;
|
||||||
|
result.y = root.y;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}; // namespace ng_ultra
|
||||||
|
NEXTPNR_NAMESPACE_END
|
43
himbaechel/uarch/ng-ultra/location_map.h
Normal file
43
himbaechel/uarch/ng-ultra/location_map.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 "ng_ultra.h"
|
||||||
|
|
||||||
|
#ifndef NG_ULTRA_LOCATION_MAP_H
|
||||||
|
#define NG_ULTRA_LOCATION_MAP_H
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace ng_ultra {
|
||||||
|
|
||||||
|
Loc getNextLocInDSPChain(const NgUltraImpl *impl, Loc loc);
|
||||||
|
Loc getNextLocInCYChain(Loc loc);
|
||||||
|
Loc getNextLocInLUTChain(Loc loc);
|
||||||
|
Loc getNextLocInDFFChain(Loc loc);
|
||||||
|
Loc getCYFE(Loc root, int pos);
|
||||||
|
Loc getXLUTFE(Loc root, int pos);
|
||||||
|
Loc getXRFFE(Loc root, int pos);
|
||||||
|
Loc getCDCFE(Loc root, int pos);
|
||||||
|
Loc getFIFOFE(Loc root, int pos);
|
||||||
|
|
||||||
|
}; // namespace ng_ultra
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
#endif
|
1069
himbaechel/uarch/ng-ultra/ng_ultra.cc
Normal file
1069
himbaechel/uarch/ng-ultra/ng_ultra.cc
Normal file
File diff suppressed because it is too large
Load Diff
126
himbaechel/uarch/ng-ultra/ng_ultra.h
Normal file
126
himbaechel/uarch/ng-ultra/ng_ultra.h
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 HIMBAECHEL_NG_ULTRA_H
|
||||||
|
#define HIMBAECHEL_NG_ULTRA_H
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
|
#include "extra_data.h"
|
||||||
|
#include "himbaechel_api.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include "himbaechel_helpers.h"
|
||||||
|
|
||||||
|
#ifdef GTEST_API_
|
||||||
|
#define TESTABLE_PRIVATE public
|
||||||
|
#else
|
||||||
|
#define TESTABLE_PRIVATE private
|
||||||
|
#endif
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct NgUltraImpl : HimbaechelAPI
|
||||||
|
{
|
||||||
|
~NgUltraImpl();
|
||||||
|
void init_database(Arch *arch) override;
|
||||||
|
|
||||||
|
void init(Context *ctx) override;
|
||||||
|
|
||||||
|
bool isBelLocationValid(BelId bel, bool explain_invalid = false) const override;
|
||||||
|
IdString getBelBucketForCellType(IdString cell_type) const override;
|
||||||
|
bool isValidBelForCellType(IdString cell_type, BelId bel) const override;
|
||||||
|
BelBucketId getBelBucketForBel(BelId bel) const override;
|
||||||
|
|
||||||
|
// Flow management
|
||||||
|
void pack() override;
|
||||||
|
void postPlace() override;
|
||||||
|
void postRoute() override;
|
||||||
|
|
||||||
|
void configurePlacerHeap(PlacerHeapCfg &cfg) override;
|
||||||
|
|
||||||
|
bool getClusterPlacement(ClusterId cluster, BelId root_bel,
|
||||||
|
std::vector<std::pair<CellInfo *, BelId>> &placement) const override;
|
||||||
|
bool getChildPlacement(const BaseClusterInfo *cluster, Loc root_loc,
|
||||||
|
std::vector<std::pair<CellInfo *, BelId>> &placement) const;
|
||||||
|
|
||||||
|
BoundingBox getRouteBoundingBox(WireId src, WireId dst) const override;
|
||||||
|
delay_t estimateDelay(WireId src, WireId dst) const override;
|
||||||
|
delay_t predictDelay(BelId src_bel, IdString src_pin, BelId dst_bel, IdString dst_pin) const override;
|
||||||
|
|
||||||
|
bool checkPipAvail(PipId pip) const override { return blocked_pips.count(pip) == 0; }
|
||||||
|
bool checkPipAvailForNet(PipId pip, const NetInfo *net) const override { return checkPipAvail(pip); };
|
||||||
|
|
||||||
|
void expandBoundingBox(BoundingBox &bb) const override;
|
||||||
|
|
||||||
|
void drawBel(std::vector<GraphicElement> &g, GraphicElement::style_t style, IdString bel_type, Loc loc) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int tile_lobe(int tile) const;
|
||||||
|
TileTypeExtra tile_type(int tile) const;
|
||||||
|
IdString tile_name_id(int tile) const;
|
||||||
|
std::string tile_name(int tile) const;
|
||||||
|
|
||||||
|
const dict<IdString, pool<IdString>> &get_fabric_lowskew_sinks();
|
||||||
|
bool is_fabric_lowskew_sink(const PortRef &ref);
|
||||||
|
bool is_ring_clock_sink(const PortRef &ref);
|
||||||
|
bool is_ring_over_tile_clock_sink(const PortRef &ref);
|
||||||
|
bool is_tube_clock_sink(const PortRef &ref);
|
||||||
|
|
||||||
|
bool is_ring_clock_source(const PortRef &ref);
|
||||||
|
bool is_tube_clock_source(const PortRef &ref);
|
||||||
|
|
||||||
|
const NGUltraPipExtraDataPOD *pip_extra_data(PipId pip) const;
|
||||||
|
const NGUltraBelExtraDataPOD *bel_extra_data(BelId bel) const;
|
||||||
|
|
||||||
|
dict<IdString, BelId> iom_bels;
|
||||||
|
dict<std::string, std::string> bank_voltage;
|
||||||
|
dict<BelId, IdString> global_capable_bels;
|
||||||
|
dict<std::string, BelId> locations;
|
||||||
|
dict<std::string, Loc> tile_locations;
|
||||||
|
dict<int, std::vector<GckConfig>> gck_per_lobe;
|
||||||
|
|
||||||
|
pool<PipId> blocked_pips;
|
||||||
|
dict<IdString, std::pair<IdString, IdString>> bank_to_ckg;
|
||||||
|
dict<BelId, IdString> unused_wfg;
|
||||||
|
dict<BelId, IdString> unused_pll;
|
||||||
|
dict<BelId, BelId> dsp_cascade;
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
TESTABLE_PRIVATE:
|
||||||
|
void write_bitstream_json(const std::string &filename);
|
||||||
|
/* clang-format on */
|
||||||
|
void parse_csv(const std::string &filename);
|
||||||
|
void remove_constants();
|
||||||
|
bool update_bff_to_csc(CellInfo *cell, BelId bel, PipId dst_pip);
|
||||||
|
bool update_bff_to_scc(CellInfo *cell, BelId bel, PipId dst_pip);
|
||||||
|
void disable_beyond_fe_s_output(BelId bel);
|
||||||
|
|
||||||
|
void fixup_crossbars();
|
||||||
|
|
||||||
|
// Misc utility functions
|
||||||
|
bool get_mux_data(BelId bel, IdString port, uint8_t *value);
|
||||||
|
bool get_mux_data(WireId wire, uint8_t *value);
|
||||||
|
|
||||||
|
const NGUltraTileInstExtraDataPOD *tile_extra_data(int tile) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
#endif
|
2738
himbaechel/uarch/ng-ultra/pack.cc
Normal file
2738
himbaechel/uarch/ng-ultra/pack.cc
Normal file
File diff suppressed because it is too large
Load Diff
131
himbaechel/uarch/ng-ultra/pack.h
Normal file
131
himbaechel/uarch/ng-ultra/pack.h
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 <algorithm>
|
||||||
|
#include <boost/optional.hpp>
|
||||||
|
#include <iterator>
|
||||||
|
#include <queue>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include "chain_utils.h"
|
||||||
|
#include "design_utils.h"
|
||||||
|
#include "log.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "ng_ultra.h"
|
||||||
|
|
||||||
|
#ifndef NG_ULTRA_PACK_H
|
||||||
|
#define NG_ULTRA_PACK_H
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
struct NgUltraPacker
|
||||||
|
{
|
||||||
|
NgUltraPacker(Context *ctx, NgUltraImpl *uarch) : ctx(ctx), uarch(uarch) { h.init(ctx); };
|
||||||
|
|
||||||
|
void remove_not_used();
|
||||||
|
// Constants
|
||||||
|
void pack_constants();
|
||||||
|
void remove_constants();
|
||||||
|
|
||||||
|
// LUTs & FFs
|
||||||
|
void update_lut_init();
|
||||||
|
void update_dffs();
|
||||||
|
void pack_xluts();
|
||||||
|
void pack_lut_multi_dffs();
|
||||||
|
void pack_dff_chains();
|
||||||
|
void pack_lut_dffs();
|
||||||
|
void pack_dffs();
|
||||||
|
void pack_cys();
|
||||||
|
void pack_rfs();
|
||||||
|
void pack_cdcs();
|
||||||
|
void pack_fifos();
|
||||||
|
|
||||||
|
void pack_rams();
|
||||||
|
void pack_dsps();
|
||||||
|
|
||||||
|
// IO
|
||||||
|
void pack_iobs();
|
||||||
|
void pack_ioms();
|
||||||
|
|
||||||
|
void pack_gcks();
|
||||||
|
void pack_plls();
|
||||||
|
void pack_wfgs();
|
||||||
|
void pre_place();
|
||||||
|
|
||||||
|
void insert_ioms();
|
||||||
|
void insert_wfbs();
|
||||||
|
|
||||||
|
// Post placement
|
||||||
|
void duplicate_gck();
|
||||||
|
void insert_bypass_gck();
|
||||||
|
void insert_csc();
|
||||||
|
|
||||||
|
/* clang-format off */
|
||||||
|
TESTABLE_PRIVATE:
|
||||||
|
void set_lut_input_if_constant(CellInfo *cell, IdString input);
|
||||||
|
/* clang-format on */
|
||||||
|
void lut_to_fe(CellInfo *lut, CellInfo *fe, bool no_dff, Property lut_table);
|
||||||
|
void dff_to_fe(CellInfo *dff, CellInfo *fe, bool pass_thru_lut);
|
||||||
|
void dff_rewrite(CellInfo *cell);
|
||||||
|
void ddfr_rewrite(CellInfo *cell);
|
||||||
|
|
||||||
|
void exchange_if_constant(CellInfo *cell, IdString input1, IdString input2);
|
||||||
|
void pack_cy_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port, int placer,
|
||||||
|
int &lut_only, int &lut_and_ff, int &dff_only);
|
||||||
|
|
||||||
|
void pack_xrf_input_and_output(CellInfo *cy, IdString cluster, IdString in_port, IdString out_port,
|
||||||
|
ClusterPlacement placement, int &lut_only, int &lut_and_ff, int &dff_only);
|
||||||
|
|
||||||
|
void connect_gnd_if_unconnected(CellInfo *cell, IdString input, bool warn);
|
||||||
|
void disconnect_if_gnd(CellInfo *cell, IdString input);
|
||||||
|
|
||||||
|
void insert_wfb(CellInfo *cell, IdString port);
|
||||||
|
|
||||||
|
void mandatory_param(CellInfo *cell, IdString param);
|
||||||
|
void disconnect_unused(CellInfo *cell, IdString port);
|
||||||
|
void bind_attr_loc(CellInfo *cell, dict<IdString, Property> *attrs);
|
||||||
|
BelId get_available_gck(int lobe, NetInfo *si1, NetInfo *si2);
|
||||||
|
BelId getCSC(Loc l, int row);
|
||||||
|
// General helper functions
|
||||||
|
void flush_cells();
|
||||||
|
|
||||||
|
IdString assign_wfg(IdString ckg, IdString ckg2, CellInfo *cell);
|
||||||
|
void dsp_same_driver(IdString port, CellInfo *cell, CellInfo **target);
|
||||||
|
void dsp_same_sink(IdString port, CellInfo *cell, CellInfo **target);
|
||||||
|
|
||||||
|
int make_init_with_const_input(int init, int input, bool value);
|
||||||
|
|
||||||
|
int memory_width(int config, bool ecc);
|
||||||
|
int memory_addr_bits(int config, bool ecc);
|
||||||
|
|
||||||
|
void constrain_location(CellInfo *cell);
|
||||||
|
void extract_lowskew_signals(CellInfo *cell, dict<IdString, dict<IdString, std::vector<PortRef>>> &lowskew_signals);
|
||||||
|
// Cell creating
|
||||||
|
CellInfo *create_cell_ptr(IdString type, IdString name);
|
||||||
|
|
||||||
|
Context *ctx;
|
||||||
|
NgUltraImpl *uarch;
|
||||||
|
|
||||||
|
pool<IdString> packed_cells;
|
||||||
|
pool<IdString> global_lowskew;
|
||||||
|
|
||||||
|
HimbaechelHelpers h;
|
||||||
|
};
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
#endif
|
161
himbaechel/uarch/ng-ultra/tests/lut_dff.cc
Normal file
161
himbaechel/uarch/ng-ultra/tests/lut_dff.cc
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 <vector>
|
||||||
|
#include "command.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
|
#include "uarch/ng-ultra/ng_ultra.h"
|
||||||
|
#include "uarch/ng-ultra/pack.h"
|
||||||
|
#define HIMBAECHEL_CONSTIDS "uarch/ng-ultra/constids.inc"
|
||||||
|
#include "himbaechel_constids.h"
|
||||||
|
|
||||||
|
USING_NEXTPNR_NAMESPACE
|
||||||
|
|
||||||
|
class NGUltraLutDffTest : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
virtual void SetUp()
|
||||||
|
{
|
||||||
|
init_share_dirname();
|
||||||
|
chipArgs.device = "NG-ULTRA";
|
||||||
|
ctx = new Context(chipArgs);
|
||||||
|
ctx->uarch->init(ctx);
|
||||||
|
ctx->late_init();
|
||||||
|
impl = (NgUltraImpl *)(ctx->uarch.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void TearDown() { delete ctx; }
|
||||||
|
|
||||||
|
int const_autoidx = 0;
|
||||||
|
NetInfo *add_constant_driver(const char *name, char constval)
|
||||||
|
{
|
||||||
|
IdString cell_name = ctx->idf("%s%s%d", name, (constval == '1' ? "$VCC$" : "$GND$"), const_autoidx++);
|
||||||
|
CellInfo *cc = ctx->createCell(cell_name, ctx->id(constval == '1' ? "VCC" : "GND"));
|
||||||
|
cc->ports[ctx->id("Y")].name = ctx->id("Y");
|
||||||
|
cc->ports[ctx->id("Y")].type = PORT_OUT;
|
||||||
|
NetInfo *net = ctx->createNet(cell_name);
|
||||||
|
cc->connectPort(ctx->id("Y"), net);
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_port(CellInfo *cell, const std::string &name, PortType dir)
|
||||||
|
{
|
||||||
|
IdString id = ctx->id(name);
|
||||||
|
cell->ports[id].name = id;
|
||||||
|
cell->ports[id].type = dir;
|
||||||
|
};
|
||||||
|
|
||||||
|
int evaluate_lut(int I1, int I2, int I3, int I4, int lut_table)
|
||||||
|
{
|
||||||
|
int S1 = I4 ? (lut_table >> 8) & 0xff : lut_table & 0xff;
|
||||||
|
int S2 = I3 ? (S1 >> 4 & 0xf) : S1 & 0xf;
|
||||||
|
int S3 = I2 ? (S2 >> 2 & 0x3) : S2 & 0x3;
|
||||||
|
int O = I1 ? (S3 >> 1 & 0x1) : S3 & 0x1;
|
||||||
|
return O;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArchArgs chipArgs;
|
||||||
|
Context *ctx;
|
||||||
|
NgUltraImpl *impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(NGUltraLutDffTest, pack_constants)
|
||||||
|
{
|
||||||
|
NgUltraPacker packer(ctx, impl);
|
||||||
|
packer.pack_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 2LU);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NGUltraLutDffTest, remove_constants)
|
||||||
|
{
|
||||||
|
NgUltraPacker packer(ctx, impl);
|
||||||
|
packer.pack_constants();
|
||||||
|
impl->remove_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 0LU);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NGUltraLutDffTest, remove_unused_gnd)
|
||||||
|
{
|
||||||
|
NgUltraPacker packer(ctx, impl);
|
||||||
|
CellInfo *cell = ctx->createCell(ctx->id("TEST"), id_NX_LUT);
|
||||||
|
add_port(cell, "I1", PORT_IN);
|
||||||
|
add_port(cell, "I2", PORT_IN);
|
||||||
|
add_port(cell, "I3", PORT_IN);
|
||||||
|
add_port(cell, "I4", PORT_IN);
|
||||||
|
cell->connectPort(id_I1, add_constant_driver("TEST", '1'));
|
||||||
|
cell->connectPort(id_I2, add_constant_driver("TEST", '1'));
|
||||||
|
cell->connectPort(id_I3, add_constant_driver("TEST", '1'));
|
||||||
|
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 4LU);
|
||||||
|
packer.pack_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 3LU);
|
||||||
|
impl->remove_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 2LU);
|
||||||
|
ASSERT_EQ(ctx->cells.find(ctx->id("$PACKER_GND_DRV")), ctx->cells.end());
|
||||||
|
ASSERT_NE(ctx->cells.find(ctx->id("$PACKER_VCC_DRV")), ctx->cells.end());
|
||||||
|
ASSERT_EQ(ctx->nets.find(ctx->id("$PACKER_GND")), ctx->nets.end());
|
||||||
|
ASSERT_NE(ctx->nets.find(ctx->id("$PACKER_VCC")), ctx->nets.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NGUltraLutDffTest, remove_unused_vcc)
|
||||||
|
{
|
||||||
|
NgUltraPacker packer(ctx, impl);
|
||||||
|
CellInfo *cell = ctx->createCell(ctx->id("TEST"), id_NX_LUT);
|
||||||
|
add_port(cell, "I1", PORT_IN);
|
||||||
|
add_port(cell, "I2", PORT_IN);
|
||||||
|
add_port(cell, "I3", PORT_IN);
|
||||||
|
add_port(cell, "I4", PORT_IN);
|
||||||
|
cell->connectPort(id_I1, add_constant_driver("TEST", '0'));
|
||||||
|
cell->connectPort(id_I2, add_constant_driver("TEST", '0'));
|
||||||
|
cell->connectPort(id_I3, add_constant_driver("TEST", '0'));
|
||||||
|
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 4LU);
|
||||||
|
packer.pack_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 3LU);
|
||||||
|
impl->remove_constants();
|
||||||
|
ASSERT_EQ(ctx->cells.size(), 2LU);
|
||||||
|
ASSERT_NE(ctx->cells.find(ctx->id("$PACKER_GND_DRV")), ctx->cells.end());
|
||||||
|
ASSERT_EQ(ctx->cells.find(ctx->id("$PACKER_VCC_DRV")), ctx->cells.end());
|
||||||
|
ASSERT_NE(ctx->nets.find(ctx->id("$PACKER_GND")), ctx->nets.end());
|
||||||
|
ASSERT_EQ(ctx->nets.find(ctx->id("$PACKER_VCC")), ctx->nets.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(NGUltraLutDffTest, make_init_with_const_input)
|
||||||
|
{
|
||||||
|
NgUltraPacker packer(ctx, impl);
|
||||||
|
for (int lut_table = 0; lut_table < 0x10000; lut_table++) {
|
||||||
|
for (int lut = 0; lut < 16; lut++) {
|
||||||
|
int I4 = (lut & 8) ? 1 : 0;
|
||||||
|
int I3 = (lut & 4) ? 1 : 0;
|
||||||
|
int I2 = (lut & 2) ? 1 : 0;
|
||||||
|
int I1 = (lut & 1) ? 1 : 0;
|
||||||
|
|
||||||
|
int tab1 = packer.make_init_with_const_input(lut_table, 0, I1);
|
||||||
|
int tab2 = packer.make_init_with_const_input(tab1, 1, I2);
|
||||||
|
int tab3 = packer.make_init_with_const_input(tab2, 2, I3);
|
||||||
|
int tab4 = packer.make_init_with_const_input(tab3, 3, I4);
|
||||||
|
|
||||||
|
ASSERT_EQ(evaluate_lut(I1, I2, I3, I4, lut_table), evaluate_lut(I1, I2, I3, I4, tab1));
|
||||||
|
ASSERT_EQ(evaluate_lut(I1, I2, I3, I4, lut_table), evaluate_lut(I1, I2, I3, I4, tab2));
|
||||||
|
ASSERT_EQ(evaluate_lut(I1, I2, I3, I4, lut_table), evaluate_lut(I1, I2, I3, I4, tab3));
|
||||||
|
ASSERT_EQ(evaluate_lut(I1, I2, I3, I4, lut_table), evaluate_lut(I1, I2, I3, I4, tab4));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
himbaechel/uarch/ng-ultra/tests/main.cc
Normal file
32
himbaechel/uarch/ng-ultra/tests/main.cc
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2024 The Project Beyond Authors.
|
||||||
|
*
|
||||||
|
* 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 <vector>
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
USING_NEXTPNR_NAMESPACE
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
// TODO: Remove for delivery, useful while checking tests
|
||||||
|
log_streams.push_back(std::make_pair(&std::cerr, LogLevel::LOG_MSG));
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user