Compare commits

..

7 Commits

Author SHA1 Message Date
Rowan Goemans 6ad7c06795
Merge 45d4a323a9 into d8117e3cad 2025-11-06 23:42:16 -06:00
YRabbit d8117e3cad
Gowin. Implement ADC. (#1597)
ADC support for GW5A-25 chips has been added.

The inputs of this primitive are fixed and do not require routing,
although they can be switched dynamically.

The .CST file also specifies the pins used as signal sources for the
bus0 and bus1 ADC buses.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
2025-11-06 09:17:05 +01:00
Patrick Urban 30669eca60
gatemate: fix SERDES CDR parameters (#1596) 2025-10-28 09:49:55 +01:00
tgingold 35629d0a43
gatemate: handle default parameters for IO (#1595)
* gatemate: handle default parameters for IO

This is probably a VHDL specific issue.  In VHDL, there is no
black-box. Primitive instantiations are done using VHDL component
instantiations and the component must have been declared with all its
ports and parameters (generic).  Currently the components are
translated from cells_sim.v and cells_bb.v

If a user doesn't override a parameter, the default value is used
instead.  As a consequence, nextpnr can have 'UNDEFINED' for DRIVER
or SLEW parameters of CC_IOBUF.  I think this is a main difference
with verilog, where unspecified parameters do not appear.

With this change, the UNPLACED value of PIN_NAME and UNDEFINED value
of DRIVE are simply ignored.

* gatemate/pack_io.cc: also handle UNDEFINED for id_SLEW
2025-10-28 08:16:02 +01:00
Miodrag Milanović a530283600
Cleanup Context API (#1593)
* Cleanup Context API

* Remove exit to prvent crash
2025-10-23 14:44:14 +02:00
YRabbit c133d00e2e
Gowin. Take the arch arguments directly. (#1592)
Since ctx->getArchArgs() no longer returns architecture-specific
arguments, we read the args field directly.

Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
2025-10-23 07:58:01 +02:00
myrtle c7cfb0aa4b
Remove use of boost system and filesystem (#1591)
Signed-off-by: gatecat <gatecat@ds0.me>
2025-10-22 15:01:21 +02:00
17 changed files with 132 additions and 43 deletions

View File

@ -169,7 +169,7 @@ else()
endif()
endif()
set(boost_libs filesystem program_options iostreams system)
set(boost_libs program_options iostreams)
if (Threads_FOUND)
list(APPEND boost_libs thread)
endif()

View File

@ -4,12 +4,10 @@ project(bba CXX)
set(CMAKE_CXX_STANDARD 17)
find_package(Boost REQUIRED COMPONENTS
program_options
system)
program_options)
add_executable(bbasm
main.cc)
target_link_libraries(bbasm LINK_PRIVATE
${Boost_PROGRAM_OPTIONS_LIBRARY}
${Boost_SYSTEM_LIBRARY})
${Boost_PROGRAM_OPTIONS_LIBRARY})
export(TARGETS bbasm FILE ${CMAKE_BINARY_DIR}/bba-export.cmake)

View File

@ -28,9 +28,9 @@
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/program_options.hpp>
#include <cinttypes>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <random>
@ -276,14 +276,14 @@ bool CommandHandler::parseOptions()
bool CommandHandler::executeBeforeContext()
{
if (vm.count("help") || argc == 1) {
std::cerr << boost::filesystem::path(argv[0]).stem()
std::cerr << std::filesystem::path(argv[0]).stem()
<< " -- Next Generation Place and Route (Version " GIT_DESCRIBE_STR ")\n";
std::cerr << options << "\n";
return argc != 1;
}
if (vm.count("version")) {
std::cerr << boost::filesystem::path(argv[0]).stem()
std::cerr << std::filesystem::path(argv[0]).stem()
<< " -- Next Generation Place and Route (Version " GIT_DESCRIBE_STR ")\n";
return true;
}

View File

@ -39,15 +39,7 @@ struct Context : Arch, DeterministicRNG
// True when detailed per-net timing is to be stored / reported
bool detailed_timing_report = false;
ArchArgs arch_args;
Context(ArchArgs args) : Arch(args)
{
BaseCtx::as_ctx = this;
arch_args = args;
}
ArchArgs getArchArgs() { return arch_args; }
Context(ArchArgs args) : Arch(args) { BaseCtx::as_ctx = this; }
// --------------------------------------------------------------

View File

@ -3,8 +3,8 @@
#define NOMINMAX
#include <windows.h>
#endif
#include <boost/filesystem.hpp>
#include <boost/iostreams/device/mapped_file.hpp>
#include <filesystem>
#include "embed.h"
#include "nextpnr.h"
@ -17,7 +17,7 @@ const void *get_chipdb(const std::string &filename)
static std::map<std::string, boost::iostreams::mapped_file> files;
if (!files.count(filename)) {
std::string full_filename = EXTERNAL_CHIPDB_ROOT "/" + filename;
if (boost::filesystem::exists(full_filename))
if (std::filesystem::exists(full_filename))
files[filename].open(full_filename, boost::iostreams::mapped_file::priv);
}
if (files.count(filename))

View File

@ -36,7 +36,7 @@
#include "pack.h"
#include "validity_check.h"
#include <boost/filesystem.hpp>
#include <filesystem>
NEXTPNR_NAMESPACE_BEGIN
@ -62,7 +62,7 @@ struct FabulousImpl : ViaductAPI
ViaductAPI::init(ctx);
h.init(ctx);
fab_root = get_env_var("FAB_ROOT", ", set it to the fabulous build output or project path");
if (boost::filesystem::exists(fab_root + "/.FABulous"))
if (std::filesystem::exists(fab_root + "/.FABulous"))
is_new_fab = true;
else
is_new_fab = false;

View File

@ -368,7 +368,7 @@ void BaseMainWindow::open_json()
if (!fileName.isEmpty()) {
disableActions();
if (ctx->settings.find(ctx->id("synth")) == ctx->settings.end()) {
ArchArgs chipArgs = ctx->getArchArgs();
ArchArgs chipArgs = ctx->args;
ctx = std::unique_ptr<Context>(new Context(chipArgs));
Q_EMIT contextChanged(ctx.get());
}

View File

@ -20,7 +20,6 @@
#include "mainwindow.h"
#include <QMessageBox>
#include <cstdlib>
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
@ -46,7 +45,6 @@ void MainWindow::new_proj()
{
QMessageBox::critical(0, "Error",
"Creating a new project not supported in himbächel mode, please re-start from command line.");
std::exit(1);
}
NEXTPNR_NAMESPACE_END

View File

@ -18,7 +18,6 @@
*/
#include "arch.h"
#include <boost/filesystem/path.hpp>
#include "archdefs.h"
#include "chipdb.h"
#include "log.h"
@ -31,6 +30,8 @@
#include "router2.h"
#include "util.h"
#include <filesystem>
NEXTPNR_NAMESPACE_BEGIN
static constexpr int database_version = 6;
@ -124,7 +125,7 @@ void Arch::load_chipdb(const std::string &path)
db_path = proc_share_dirname();
db_path += "himbaechel/";
db_path += path;
boost::filesystem::path p(db_path);
std::filesystem::path p(db_path);
db_path = p.make_preferred().string();
}
try {

View File

@ -177,8 +177,9 @@ void GateMatePacker::pack_io()
for (auto &p : ci.params) {
if (p.first.in(id_PIN_NAME, id_PIN_NAME_P, id_PIN_NAME_N)) {
if (ctx->get_package_pin_bel(ctx->id(p.second.as_string())) == BelId())
log_error("Unknown %s '%s' for cell '%s'.\n", p.first.c_str(ctx), p.second.as_string().c_str(),
std::string pname = p.second.as_string();
if (pname != "UNPLACED" && ctx->get_package_pin_bel(ctx->id(pname)) == BelId())
log_error("Unknown %s '%s' for cell '%s'.\n", p.first.c_str(ctx), pname.c_str(),
ci.name.c_str(ctx));
keys.push_back(p.first);
continue;
@ -194,9 +195,15 @@ void GateMatePacker::pack_io()
continue;
if (ci.type.in(id_CC_TOBUF) && p.first.in(id_PULLUP, id_PULLDOWN, id_KEEPER))
continue;
if (ci.type.in(id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF) &&
p.first.in(id_DRIVE, id_SLEW, id_DELAY_OBF, id_FF_OBF))
continue;
if (ci.type.in(id_CC_OBUF, id_CC_TOBUF, id_CC_IOBUF)) {
if (p.first.in(id_DRIVE, id_SLEW)) {
if (p.second.is_string && p.second.as_string() == "UNDEFINED")
keys.push_back(p.first);
continue;
}
if (p.first.in(id_DELAY_OBF, id_FF_OBF))
continue;
}
if (ci.type.in(id_CC_LVDS_IBUF, id_CC_LVDS_IOBUF) && p.first.in(id_LVDS_RTERM, id_DELAY_IBF, id_FF_IBF))
continue;
if (ci.type.in(id_CC_LVDS_OBUF, id_CC_LVDS_TOBUF, id_CC_LVDS_IOBUF) &&

View File

@ -70,8 +70,8 @@ static const DefaultParam serdes_defaults[] = {
{id_RX_AFE_VCMSEL, 3, 4},
{id_RX_CDR_CKP, 8, 0xF8},
{id_RX_CDR_CKI, 8, 0},
{id_RX_CDR_TRANS_TH, 9, 128},
{id_RX_CDR_LOCK_CFG, 6, 0x0B},
{id_RX_CDR_TRANS_TH, 7, 0x08},
{id_RX_CDR_LOCK_CFG, 8, 0xD5},
// { id_RX_CDR_LOCKED, 1, 0 },
// { id_RX_CDR_FREQ_ACC_VAL, 15, 0 },
// { id_RX_CDR_PHASE_ACC_VAL, 16, 0 },

View File

@ -1038,6 +1038,9 @@ X(RPLLA)
X(PLLVR)
X(PLLA)
// ADC
X(ADC)
// primitive attributes
X(INIT)
X(FF_USED)

View File

@ -80,6 +80,7 @@ struct GowinCstReader
constrained_cells.insert(std::make_pair(cellId, belId));
}
};
pool<IdString> adc_ios; // bus#/X#Y#
log_info("Reading constraints...\n");
try {
@ -95,6 +96,7 @@ struct GowinCstReader
std::regex hclkre =
std::regex("INS_LOC +\"([^\"]+)\" +(TOP|RIGHT|BOTTOM|LEFT)SIDE\\[([0,1])\\] *;*[\\s\\S]*");
std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])(\\[([0-7])\\])?[^;]*;.*[\\s\\S]*");
std::regex adcre = std::regex("USE_ADC_SRC +bus([0-9]) +IO([TRBL])([0-9]+) *;.*[\\s\\S]*");
std::smatch match, match_attr, match_pinloc;
std::string line, pinlines[2];
std::vector<IdStringList> constrained_clkdivs;
@ -104,7 +106,8 @@ struct GowinCstReader
ioport,
insloc,
clock,
hclk
hclk,
adc
} cst_type;
while (!in.eof()) {
@ -123,10 +126,14 @@ struct GowinCstReader
if (std::regex_match(line, match, hclkre)) {
cst_type = hclk;
} else {
if ((!line.empty()) && (line.rfind("//", 0) == std::string::npos)) {
log_warning("Invalid constraint: %s\n", line.c_str());
if (std::regex_match(line, match, adcre)) {
cst_type = adc;
} else {
if ((!line.empty()) && (line.rfind("//", 0) == std::string::npos)) {
log_warning("Invalid constraint: %s\n", line.c_str());
}
continue;
}
continue;
}
}
}
@ -135,11 +142,26 @@ struct GowinCstReader
IdString net = ctx->id(match[1]);
auto it = ctx->cells.find(net);
if (cst_type != clock && it == ctx->cells.end()) {
if (cst_type != clock && cst_type != adc && it == ctx->cells.end()) {
log_info("Cell %s not found\n", net.c_str(ctx));
continue;
}
switch (cst_type) {
case adc: { // USE_ADC_SRC bus# IOLOC
int col = std::stoi(match[3]);
int row = 1; // Top
std::string side = match[2].str();
if (side == "R") {
row = col;
col = ctx->getGridDimX();
} else if (side == "B") {
row = ctx->getGridDimY();
} else if (side == "L") {
row = col;
col = 1;
}
adc_ios.insert(ctx->idf("%d/X%dY%d", std::stoi(match[1]), row - 1, col - 1));
} break;
case clock: { // CLOCK name BUFG|S=#
std::string which_clock = match[2];
std::string lw = match[4];
@ -258,6 +280,25 @@ struct GowinCstReader
for (auto &cell : constrained_cells) {
log_info("Cell %s is constrained to %s\n", cell.first.c_str(ctx), cell.second.str(ctx).c_str());
}
if (!adc_ios.empty()) {
log_info("ADC iobufs:\n");
for (auto &bus_io : adc_ios) {
log_info(" bus %s\n", bus_io.c_str(ctx));
}
}
}
if (!adc_ios.empty()) {
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (is_adc(&ci)) {
int idx = 0;
for (auto &bus_io : adc_ios) {
ci.setAttr(ctx->idf("ADC_IO_%d", idx), bus_io.str(ctx));
++idx;
}
}
}
}
return true;
} catch (log_execution_error_exception) {

View File

@ -179,7 +179,7 @@ void GowinImpl::init(Context *ctx)
gwu.init(ctx);
const ArchArgs &args = ctx->getArchArgs();
const ArchArgs &args = ctx->args;
// package and speed class
std::regex speedre = std::regex("(.*)(C[0-9]/I[0-9])$");

View File

@ -100,6 +100,10 @@ inline bool is_userflash(const CellInfo *cell) { return type_is_userflash(cell->
inline bool type_is_pll(IdString cell_type) { return cell_type.in(id_rPLL, id_PLLVR); }
inline bool is_pll(const CellInfo *cell) { return type_is_pll(cell->type); }
// Return true if a cell is a ADC
inline bool type_is_adc(IdString cell_type) { return cell_type.in(id_ADC); }
inline bool is_adc(const CellInfo *cell) { return type_is_adc(cell->type); }
// Return true if a cell is a EMCU
inline bool type_is_emcu(IdString cell_type) { return cell_type == id_EMCU; }
inline bool is_emcu(const CellInfo *cell) { return type_is_emcu(cell->type); }
@ -254,6 +258,8 @@ enum
PINCFG_Z = 400,
ADC_Z = 401,
// The two least significant bits encode Z for 9-bit adders and
// multipliers, if they are equal to 0, then we get Z of their common
// 18-bit equivalent.

View File

@ -75,7 +75,8 @@ MIPIIBUF_Z = 302
DLLDLY_Z = 303 # : 305 reserve for 2 DLLDLYs
PINCFG_Z = 400 #
PINCFG_Z = 400
ADC_Z = 401
DSP_Z = 509
@ -463,7 +464,7 @@ def create_nodes(chip: Chip, db: chipdb):
for i in range(5):
nodes.append([NodeWire(x, y, f'COUT{i}'),
NodeWire(x, y, f'CIN{i + 1}')]);
# gobal carry chain
# global carry chain
if x > 1 and chip.tile_type_at(x - 1, y).extra_data.tile_class == chip.strs.id('LOGIC'):
nodes.append([NodeWire(x, y, f'CIN0'),
NodeWire(x - 1, y, f'COUT5')])
@ -788,6 +789,17 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
for pin, wire in desc['inputs'].items():
tt.create_wire(wire, "PLL_I")
tt.add_bel_pin(pll, pin, wire, PinType.INPUT)
elif func == 'adc':
pll = tt.create_bel("ADC", "ADC", z = ADC_Z)
for pin, wire in desc['outputs'].items():
tt.create_wire(wire, "ADC_O")
tt.add_bel_pin(pll, pin, wire, PinType.OUTPUT)
for pin, wire in desc['inputs'].items():
if pin == 'CLK' or pin == 'MDRP_CLK':
tt.create_wire(wire, "TILE_CLK")
else:
tt.create_wire(wire, "ADC_I")
tt.add_bel_pin(pll, pin, wire, PinType.INPUT)
elif func == 'gnd_source':
# GND is the logic low level generator
tt.create_wire('VSS', 'GND', const_value = 'VSS')

View File

@ -2696,7 +2696,7 @@ struct GowinPacker
divide_sdp(ci, new_cells);
} else {
log_error("The fix for SDP when ports A and B have different bit widths has not yet been implemented. "
"Cell'%s'\n",
"Cell: '%s'\n",
ci->type.c_str(ctx));
}
}
@ -3934,7 +3934,7 @@ struct GowinPacker
pincfg_cell->connectPort(port, ctx->nets.at(ctx->id("$PACKER_VCC")).get());
}
const ArchArgs &args = ctx->getArchArgs();
const ArchArgs &args = ctx->args;
pincfg_cell->addInput(id_SSPI);
if (args.options.count("sspi_as_gpio")) {
@ -4073,6 +4073,34 @@ struct GowinPacker
}
}
// ===================================
// ADC
// ===================================
void pack_adc(void)
{
log_info("Pack ADC...\n");
for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (is_adc(&ci)) {
for (int i = 0; i < 14; ++i) {
if (i < 2) {
ci.renamePort(ctx->idf("MDRP_OPCODE[%d]", i), ctx->idf("MDRP_OPCODE%d", i));
}
if (i < 3) {
ci.renamePort(ctx->idf("VSENCTL[%d]", i), ctx->idf("VSENCTL%d", i));
}
if (i < 8) {
ci.renamePort(ctx->idf("MDRP_WDATA[%d]", i), ctx->idf("MDRP_WDATA%d", i));
ci.renamePort(ctx->idf("MDRP_RDATA[%d]", i), ctx->idf("MDRP_RDATA%d", i));
}
ci.renamePort(ctx->idf("ADCVALUE[%d]", i), ctx->idf("ADCVALUE%d", i));
}
}
}
}
// ===================================
// HCLK -- CLKDIV and CLKDIV2 for now
// ===================================
@ -4557,6 +4585,9 @@ struct GowinPacker
pack_pll();
ctx->check();
pack_adc();
ctx->check();
pack_bsram();
ctx->check();