diff --git a/himbaechel/uarch/gowin/globals.cc b/himbaechel/uarch/gowin/globals.cc index 1011bc41..e5b89e92 100644 --- a/himbaechel/uarch/gowin/globals.cc +++ b/himbaechel/uarch/gowin/globals.cc @@ -44,6 +44,16 @@ struct GowinGlobalRouter bool segment_wire_filter(PipId pip) const { return !gwu.is_segment_pip(pip); } + // To avoid a cycle where we connect the clock wire to the gate in + // the global clock system and it ends up in the global clock MUX + // again, we only allow connections from general-purpose wires. + bool clock_gate_wire_filter(PipId pip) const + { + WireId dst = ctx->getPipDstWire(pip); + IdString src_type = ctx->getWireType(ctx->getPipSrcWire(pip)); + return !(gwu.wire_is_clock_gate(dst) && src_type.in(id_GLOBAL_CLK, id_TILE_CLK)); + } + bool dcs_input_filter(PipId pip) const { return !ctx->getWireName(ctx->getPipSrcWire(pip))[1].in( @@ -79,8 +89,8 @@ struct GowinGlobalRouter if (ctx->debug && false /*&& res*/) { log_info("%s <- %s [%s <- %s]\n", ctx->nameOfWire(ctx->getPipDstWire(pip)), ctx->nameOfWire(ctx->getPipSrcWire(pip)), dst_type.c_str(ctx), src_type.c_str(ctx)); - log_info(" res:%d, src_valid:%d, dst_valid:%d, src local:%d, dst local:%d\n", res, src_valid, dst_valid, - is_local(src_type), is_local(dst_type)); + log_info(" res:%d, src_valid:%d, dst_valid:%d, src local:%d, dst local:%d, dst gate:%d\n", res, src_valid, + dst_valid, is_local(src_type), is_local(dst_type), gwu.wire_is_clock_gate(dst)); } return res; } @@ -623,7 +633,7 @@ struct GowinGlobalRouter src = ctx->getBelPinWire(true_src_ci->bel, net_before_buf->driver.port); ctx->bindWire(src, net, STRENGTH_LOCKED); backwards_bfs_route(net, src, dst, 1000000, false, [&](PipId pip, WireId src_wire) { - return segment_wire_filter(pip) && dcs_input_filter(pip); + return clock_gate_wire_filter(pip) && segment_wire_filter(pip) && dcs_input_filter(pip); }); // remove net buf_ci->movePortTo(id_O, true_src_ci, net_before_buf->driver.port); @@ -635,7 +645,8 @@ struct GowinGlobalRouter 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); + return clock_gate_wire_filter(pip) && global_pip_filter(pip, src_wire) && segment_wire_filter(pip) && + dcs_input_filter(pip); }); if (route_result != NOT_ROUTED) { log_info(" '%s' net was routed using global resources %s.\n", ctx->nameOf(net), diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index 5a82ccb8..c6172355 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -14,6 +14,9 @@ from apycula import chipdb # Bel flags BEL_FLAG_SIMPLE_IO = 0x100 +# Wire flags +WIRE_FLAG_CLOCK_GATE = 0x1 + # Chip flags CHIP_HAS_SP32 = 0x1 CHIP_NEED_SP_FIX = 0x2 @@ -768,6 +771,14 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int): tt.create_wire(wire, "PINCFG_IN") tt.add_bel_pin(bel, port, wire, PinType.INPUT) +def set_wire_flags(tt: TileType, tdesc: TypeDesc): + if tdesc.extra_func and 'clock_gates' in tdesc.extra_func: + for wire_name in tdesc.extra_func['clock_gates']: + wname_id = tt.strs.id(wire_name) + for wire_data in tt.wires: + if wire_data.name == wname_id: + wire_data.flags |= WIRE_FLAG_CLOCK_GATE + def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int): has_extra_func = (y, x) in db.extra_func @@ -817,6 +828,7 @@ def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: i create_extra_funcs(tt, db, x, y) create_hclk_switch_matrix(tt, db, x, y) create_switch_matrix(tt, db, x, y) + set_wire_flags(tt, tdesc) chip.set_tile_type(x, y, tdesc.tiletype) def add_port_wire(tt, bel, portmap, name, wire_type, port_type, pin_name = None): diff --git a/himbaechel/uarch/gowin/gowin_utils.h b/himbaechel/uarch/gowin/gowin_utils.h index 3c8fd453..c3a598ea 100644 --- a/himbaechel/uarch/gowin/gowin_utils.h +++ b/himbaechel/uarch/gowin/gowin_utils.h @@ -12,6 +12,10 @@ namespace BelFlags { static constexpr uint32_t FLAG_SIMPLE_IO = 0x100; } +namespace WireFlags { +static constexpr uint32_t FLAG_CLOCK_GATE = 0x1; +} + struct GowinUtils { Context *ctx; @@ -85,6 +89,12 @@ struct GowinUtils } bool driver_is_clksrc(const PortRef &driver); + // clock nets + bool wire_is_clock_gate(WireId wire) const + { + return chip_wire_info(ctx->chip_info, wire).flags & WireFlags::FLAG_CLOCK_GATE; + } + // BSRAM bool has_SP32(void); bool need_SP_fix(void);