From b1c147083d66f0d3d37e192d8dfced3674c2af84 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Tue, 13 May 2025 20:00:30 +1000 Subject: [PATCH] Gowin. Fill in delay values in HCLK. Fill in the delays for PIP classes related to HCLK and IODELAY. Also: - if clock routing fails, we try to use the next fastest mechanism - segment networks; - fixing harmless typos. Signed-off-by: YRabbit --- himbaechel/uarch/gowin/globals.cc | 22 ++++++++++++++-------- himbaechel/uarch/gowin/gowin_arch_gen.py | 9 +++++---- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/himbaechel/uarch/gowin/globals.cc b/himbaechel/uarch/gowin/globals.cc index 4e24a68d..ea1889c2 100644 --- a/himbaechel/uarch/gowin/globals.cc +++ b/himbaechel/uarch/gowin/globals.cc @@ -62,11 +62,11 @@ struct GowinGlobalRouter src = ctx->getPipSrcWire(pip); dst = ctx->getPipDstWire(pip); IdString dst_name = ctx->getWireName(dst)[1]; - bool not_dsc_pip = dst_name != id_CLKOUT; + bool not_dcs_pip = dst_name != id_CLKOUT; IdString src_type = ctx->getWireType(src); IdString dst_type = ctx->getWireType(dst); - bool src_valid = not_dsc_pip && src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O, id_HCLK, id_DLLDLY); - bool dst_valid = not_dsc_pip && dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I, id_HCLK); + bool src_valid = not_dcs_pip && src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O, id_HCLK, id_DLLDLY); + bool dst_valid = not_dcs_pip && dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I, id_HCLK); bool res; if (src == src_wire && (!src_type.in(id_IO_O, id_HCLK, id_DLLDLY_O))) { @@ -101,11 +101,11 @@ struct GowinGlobalRouter dst = ctx->getPipDstWire(pip); IdString src_name = ctx->getWireName(dst)[1]; IdString dst_name = ctx->getWireName(dst)[1]; - bool not_dsc_pip = dst_name != id_CLKOUT && !is_dcs_input(src_name); + bool not_dcs_pip = dst_name != id_CLKOUT && !is_dcs_input(src_name); IdString src_type = ctx->getWireType(src); IdString dst_type = ctx->getWireType(dst); - bool src_valid = not_dsc_pip && src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O, id_HCLK); - bool dst_valid = not_dsc_pip && dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I, id_HCLK); + bool src_valid = not_dcs_pip && src_type.in(id_GLOBAL_CLK, id_IO_O, id_PLL_O, id_HCLK); + bool dst_valid = not_dcs_pip && dst_type.in(id_GLOBAL_CLK, id_TILE_CLK, id_PLL_I, id_IO_I, id_HCLK); // If DQCE is used, then the source can only connect to SPINEs as only they can be switched off/on. bool res; @@ -692,7 +692,7 @@ struct GowinGlobalRouter log_info(" '%s' net was routed.\n", ctx->nameOf(net)); } - void route_clk_net(NetInfo *net) + RouteResult route_clk_net(NetInfo *net) { RouteResult route_result = route_direct_net(net, [&](PipId pip, WireId src_wire) { return global_pip_filter(pip, src_wire) && segment_wire_filter(pip) && dcs_input_filter(pip); @@ -701,6 +701,7 @@ struct GowinGlobalRouter log_info(" '%s' net was routed using global resources %s.\n", ctx->nameOf(net), route_result == ROUTED_ALL ? "only" : "partially"); } + return route_result; } // segmented wires @@ -1303,7 +1304,12 @@ struct GowinGlobalRouter if (ctx->verbose) { log_info("route clock net '%s', src:%s\n", ctx->nameOf(ni), ctx->nameOf(ni->driver.cell)); } - route_clk_net(ni); + if (route_clk_net(ni) == NOT_ROUTED) { + if (ctx->verbose) { + log_info(" try to route as a segmented network.\n"); + } + seg_nets.push_back(net_name); + } } // segmented nets diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 7eab4576..e81d145d 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -1512,15 +1512,16 @@ def create_timing_info(chip: Chip, db: chipdb.Device): elif group == "fanout": pass # handled in "wire" elif group == "glbsrc": - # TODO # no fanout delay for clock wires for name in ["CENT_SPINE_PCLK", "SPINE_TAP_PCLK", "TAP_BRANCH_PCLK"]: tmg.set_pip_class(speed, name, group_to_timingvalue(arc[name])) tmg.set_pip_class(speed, 'GCLK_BRANCH', group_to_timingvalue(arc['BRANCH_PCLK'])) elif group == "hclk": - pass # TODO + for name in ['HclkInMux', 'HclkHbrgMux', 'HclkOutMux', 'HclkDivMux']: + tmg.set_pip_class(speed, name, group_to_timingvalue(arc[name])) elif group == "iodelay": - pass # TODO + for name in ['GI_DO', 'SDTAP_DO', 'SETN_DO', 'VALUE_DO', 'SDTAP_DF', 'SETN_DF', 'VALUE_DF']: + tmg.set_pip_class(speed, name, group_to_timingvalue(arc[name])) elif group == "wire": # wires with delay and fanout delay for name in ["X0", "X2", "X8"]: @@ -1529,7 +1530,7 @@ def create_timing_info(chip: Chip, db: chipdb.Device): for name in ["X0CTL", "X0CLK", "FX1"]: tmg.set_pip_class(speed, name, group_to_timingvalue(arc[name])) # wires with presently-unknown delay - for name in ["LUT_IN", "DI", "SEL", "CIN", "COUT", "VCC", "VSS", "LW_TAP", "LW_TAP_0", "LW_BRANCH", "LW_SPAN"]: + for name in ["LUT_IN", "DI", "SEL", "CIN", "COUT", "VCC", "VSS", "LW_TAP", "LW_TAP_0", "LW_BRANCH", "LW_SPAN", "ISB"]: tmg.set_pip_class(speed, name, TimingValue()) # wires with fanout-only delay; used on cell output pips for name, mapping in [("LUT_OUT", "FFan"), ("FF_OUT", "QFan"), ("OF", "OFFan")]: