mirror of https://github.com/YosysHQ/nextpnr.git
Compare commits
4 Commits
a71f75aafc
...
1ad7b655db
| Author | SHA1 | Date |
|---|---|---|
|
|
1ad7b655db | |
|
|
d8117e3cad | |
|
|
de38bd34fb | |
|
|
496df84b3b |
|
|
@ -397,6 +397,8 @@ po::options_description CommandHandler::getGeneralOptions()
|
|||
general.add_options()("parallel-refine", "use new experimental parallelised engine for placement refinement");
|
||||
#endif
|
||||
|
||||
general.add_options()("router1-timeout", po::value<int>(), "Timeout for router1 in iteration count (default: 0, no timeout)");
|
||||
|
||||
general.add_options()("router2-heatmap", po::value<std::string>(),
|
||||
"prefix for router2 resource congestion heatmaps");
|
||||
|
||||
|
|
@ -539,6 +541,10 @@ void CommandHandler::setupContext(Context *ctx)
|
|||
if (vm.count("parallel-refine"))
|
||||
ctx->settings[ctx->id("placerHeap/parallelRefine")] = true;
|
||||
|
||||
if (vm.count("router1-timeout")) {
|
||||
ctx->settings[ctx->id("router1/maxIterCnt")] = std::to_string(std::max(0, vm["router1-timeout"].as<int>()));
|
||||
}
|
||||
|
||||
if (vm.count("router2-heatmap"))
|
||||
ctx->settings[ctx->id("router2/heatmap")] = vm["router2-heatmap"].as<std::string>();
|
||||
if (vm.count("tmg-ripup") || vm.count("router2-tmg-ripup"))
|
||||
|
|
|
|||
|
|
@ -1146,7 +1146,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||
|
||||
Router1Cfg::Router1Cfg(Context *ctx)
|
||||
{
|
||||
maxIterCnt = ctx->setting<int>("router1/maxIterCnt", 200);
|
||||
maxIterCnt = ctx->setting<int>("router1/maxIterCnt", 0);
|
||||
cleanupReroute = ctx->setting<bool>("router1/cleanupReroute", true);
|
||||
fullCleanupReroute = ctx->setting<bool>("router1/fullCleanupReroute", true);
|
||||
useEstimate = ctx->setting<bool>("router1/useEstimate", true);
|
||||
|
|
@ -1199,11 +1199,17 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
|
|||
last_arcs_with_ripup = router.arcs_with_ripup;
|
||||
last_arcs_without_ripup = router.arcs_without_ripup;
|
||||
ctx->yield();
|
||||
|
||||
#ifndef NDEBUG
|
||||
router.check();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (cfg.maxIterCnt){
|
||||
if (iter_cnt > cfg.maxIterCnt) {
|
||||
log_error("Max iteration count reached, stopping routing.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->debug)
|
||||
log("-- %d --\n", iter_cnt);
|
||||
|
||||
|
|
|
|||
|
|
@ -1038,6 +1038,9 @@ X(RPLLA)
|
|||
X(PLLVR)
|
||||
X(PLLA)
|
||||
|
||||
// ADC
|
||||
X(ADC)
|
||||
|
||||
// primitive attributes
|
||||
X(INIT)
|
||||
X(FF_USED)
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue