Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gowin. Add I3C io buffer. #1445

Merged
merged 2 commits into from
Jan 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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