Skip to content

Commit

Permalink
Gowin. Add I3C io buffer. (YosysHQ#1445)
Browse files Browse the repository at this point in the history
* Gowin. Add I3C io buffer.

A buffer is added that can operate as a normal IOBUF in PUSH-PULL mode
or switch to open-drain IOBUF mode.

Signed-off-by: YRabbit <[email protected]>

* Gowin. Turn a variable into a set of flags

Signed-off-by: YRabbit <[email protected]>

---------

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit authored Jan 29, 2025
1 parent a76c5b5 commit 81ccada
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 0 deletions.
3 changes: 3 additions & 0 deletions himbaechel/uarch/gowin/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,9 @@ X(LSREN)
// EMCU
X(EMCU)

// I3C
X(I3C_IOBUF)

// MIPI
X(IL)
X(OH)
Expand Down
7 changes: 7 additions & 0 deletions himbaechel/uarch/gowin/gowin.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type);
inline bool type_is_mipi(IdString cell_type) { return cell_type.in(id_MIPI_OBUF, id_MIPI_OBUF_A, id_MIPI_IBUF); }
inline bool is_mipi(const CellInfo *cell) { return type_is_mipi(cell->type); }

// I3C
inline bool type_is_i3c(IdString cell_type) { return cell_type.in(id_I3C_IOBUF); }
inline bool is_i3c(const CellInfo *cell) { return type_is_i3c(cell->type); }

// IOLOGIC input and output separately

inline bool type_is_iologico(IdString cell_type)
Expand Down Expand Up @@ -106,6 +110,9 @@ NPNR_PACKED_STRUCT(struct Tile_extra_data_POD {
int32_t class_id;
int16_t io16_x_off;
int16_t io16_y_off;
int32_t tile_flags;
// tile flags
static constexpr int32_t TILE_I3C_CAPABLE_IO = 1;
});

NPNR_PACKED_STRUCT(struct Bottom_io_cnd_POD {
Expand Down
7 changes: 7 additions & 0 deletions himbaechel/uarch/gowin/gowin_arch_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
CHIP_NEED_BLKSEL_FIX = 0x8
CHIP_HAS_BANDGAP = 0x10

# Tile flags
TILE_I3C_CAPABLE_IO = 0x1

# Z of the bels
# sync with C++ part!
LUT0_Z = 0 # z(DFFx) = z(LUTx) + 1
Expand Down Expand Up @@ -126,13 +129,15 @@ class TileExtraData(BBAStruct):
# then we assign them to the same LOGIC class.
io16_x_off: int = 0 # OSER16/IDES16 offsets to the aux cell
io16_y_off: int = 0
tile_flags: int = 0

def serialise_lists(self, context: str, bba: BBAWriter):
pass
def serialise(self, context: str, bba: BBAWriter):
bba.u32(self.tile_class.index)
bba.u16(self.io16_x_off)
bba.u16(self.io16_y_off)
bba.u32(self.tile_flags)

@dataclass
class BottomIOCnd(BBAStruct):
Expand Down Expand Up @@ -582,6 +587,8 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)
else:
tt.add_bel_pin(bel, port, wire, PinType.INPUT)
elif func == 'i3c_capable':
tt.extra_data.tile_flags |= TILE_I3C_CAPABLE_IO
elif func == 'mipi_obuf':
bel = tt.create_bel('MIPI_OBUF', 'MIPI_OBUF', MIPIOBUF_Z)
elif func == 'mipi_ibuf':
Expand Down
9 changes: 9 additions & 0 deletions himbaechel/uarch/gowin/gowin_utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ Loc GowinUtils::get_tile_io16_offs(int x, int y)
return Loc(extra->io16_x_off, extra->io16_y_off, 0);
}

// oser16/ides16 aux cell offsets
bool GowinUtils::get_i3c_capable(int x, int y)
{
int tile = tile_by_xy(ctx->chip_info, x, y);
const Tile_extra_data_POD *extra =
reinterpret_cast<const Tile_extra_data_POD *>(chip_tile_info(ctx->chip_info, tile).extra_data.get());
return extra->tile_flags & Tile_extra_data_POD::TILE_I3C_CAPABLE_IO;
}

// pin functions: GCLKT_4, SSPI_CS, READY etc
IdStringList GowinUtils::get_pin_funcs(BelId io_bel)
{
Expand Down
1 change: 1 addition & 0 deletions himbaechel/uarch/gowin/gowin_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ struct GowinUtils
// tile
IdString get_tile_class(int x, int y);
Loc get_tile_io16_offs(int x, int y);
bool get_i3c_capable(int x, int y);

// pin functions: GCLKT_4, SSPI_CS, READY etc
IdStringList get_pin_funcs(BelId io_bel);
Expand Down
53 changes: 53 additions & 0 deletions himbaechel/uarch/gowin/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,47 @@ struct GowinPacker
}
}

// ===================================
// I3C
// ===================================
void pack_i3c(void)
{
log_info("Pack I3C IOs...\n");
std::vector<IdString> cells_to_remove;

for (auto &cell : ctx->cells) {
CellInfo &ci = *cell.second;
if (!is_i3c(&ci)) {
continue;
}
// check for I3C-capable pin A
CellInfo *iob = net_only_drives(ctx, ci.ports.at(id_IO).net, is_iob, id_I);
if (iob == nullptr || iob->bel == BelId()) {
log_error("I3C %s IO is not connected to the input pin or the pin is not constrained.\n",
ctx->nameOf(&ci));
}
BelId iob_bel = iob->bel;
Loc iob_loc = ctx->getBelLocation(iob_bel);

if (!gwu.get_i3c_capable(iob_loc.x, iob_loc.y)) {
log_error("Can't place %s. Not I3C capable X%dY%d.\n", ctx->nameOf(&ci), iob_loc.x, iob_loc.y);
}
ci.disconnectPort(id_IO);
iob->disconnectPort(id_I);
ci.movePortTo(id_I, iob, id_I);
ci.movePortTo(id_O, iob, id_O);
iob->disconnectPort(id_OEN);
ci.movePortTo(id_MODESEL, iob, id_OEN);

iob->setParam(id_I3C_IOBUF, 1);
cells_to_remove.push_back(ci.name);
}

for (auto cell : cells_to_remove) {
ctx->cells.erase(cell);
}
}

// ===================================
// MIPI IO
// ===================================
Expand All @@ -330,6 +371,9 @@ struct GowinPacker
log_error("MIPI %s is not connected to the output pin or the pin is not constrained.\n",
ctx->nameOf(&ci));
}
if (out_iob->params.count(id_I3C_IOBUF)) {
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(out_iob));
}
BelId iob_bel = out_iob->bel;
Loc iob_loc = ctx->getBelLocation(iob_bel);
iob_loc.z = BelZ::MIPIOBUF_Z;
Expand Down Expand Up @@ -383,6 +427,9 @@ struct GowinPacker
ctx->nameOf(&ci));
}
// check A IO placing
if (in_iob->params.count(id_I3C_IOBUF)) {
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(in_iob));
}
BelId iob_bel = in_iob->bel;
Loc iob_loc = ctx->getBelLocation(iob_bel);
if (iob_loc.z != BelZ::IOBA_Z) {
Expand All @@ -402,6 +449,9 @@ struct GowinPacker
ctx->nameOf(&ci));
}
// check B IO placing
if (inb_iob->params.count(id_I3C_IOBUF)) {
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(inb_iob));
}
BelId iobb_bel = inb_iob->bel;
Loc iobb_loc = ctx->getBelLocation(iobb_bel);
if (iobb_loc.z != BelZ::IOBB_Z || iobb_loc.x != iob_loc.x || iobb_loc.y != iob_loc.y) {
Expand Down Expand Up @@ -4108,6 +4158,9 @@ struct GowinPacker
pack_iobs();
ctx->check();

pack_i3c();
ctx->check();

pack_mipi();
ctx->check();

Expand Down

0 comments on commit 81ccada

Please sign in to comment.