Skip to content

Commit 81ccada

Browse files
authored
Gowin. Add I3C io buffer. (#1445)
* 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]>
1 parent a76c5b5 commit 81ccada

File tree

6 files changed

+80
-0
lines changed

6 files changed

+80
-0
lines changed

himbaechel/uarch/gowin/constids.inc

+3
Original file line numberDiff line numberDiff line change
@@ -1313,6 +1313,9 @@ X(LSREN)
13131313
// EMCU
13141314
X(EMCU)
13151315

1316+
// I3C
1317+
X(I3C_IOBUF)
1318+
13161319
// MIPI
13171320
X(IL)
13181321
X(OH)

himbaechel/uarch/gowin/gowin.h

+7
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ inline bool is_diffio(const CellInfo *cell) { return type_is_diffio(cell->type);
3636
inline bool type_is_mipi(IdString cell_type) { return cell_type.in(id_MIPI_OBUF, id_MIPI_OBUF_A, id_MIPI_IBUF); }
3737
inline bool is_mipi(const CellInfo *cell) { return type_is_mipi(cell->type); }
3838

39+
// I3C
40+
inline bool type_is_i3c(IdString cell_type) { return cell_type.in(id_I3C_IOBUF); }
41+
inline bool is_i3c(const CellInfo *cell) { return type_is_i3c(cell->type); }
42+
3943
// IOLOGIC input and output separately
4044

4145
inline bool type_is_iologico(IdString cell_type)
@@ -106,6 +110,9 @@ NPNR_PACKED_STRUCT(struct Tile_extra_data_POD {
106110
int32_t class_id;
107111
int16_t io16_x_off;
108112
int16_t io16_y_off;
113+
int32_t tile_flags;
114+
// tile flags
115+
static constexpr int32_t TILE_I3C_CAPABLE_IO = 1;
109116
});
110117

111118
NPNR_PACKED_STRUCT(struct Bottom_io_cnd_POD {

himbaechel/uarch/gowin/gowin_arch_gen.py

+7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@
2121
CHIP_NEED_BLKSEL_FIX = 0x8
2222
CHIP_HAS_BANDGAP = 0x10
2323

24+
# Tile flags
25+
TILE_I3C_CAPABLE_IO = 0x1
26+
2427
# Z of the bels
2528
# sync with C++ part!
2629
LUT0_Z = 0 # z(DFFx) = z(LUTx) + 1
@@ -126,13 +129,15 @@ class TileExtraData(BBAStruct):
126129
# then we assign them to the same LOGIC class.
127130
io16_x_off: int = 0 # OSER16/IDES16 offsets to the aux cell
128131
io16_y_off: int = 0
132+
tile_flags: int = 0
129133

130134
def serialise_lists(self, context: str, bba: BBAWriter):
131135
pass
132136
def serialise(self, context: str, bba: BBAWriter):
133137
bba.u32(self.tile_class.index)
134138
bba.u16(self.io16_x_off)
135139
bba.u16(self.io16_y_off)
140+
bba.u32(self.tile_flags)
136141

137142
@dataclass
138143
class BottomIOCnd(BBAStruct):
@@ -582,6 +587,8 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
582587
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)
583588
else:
584589
tt.add_bel_pin(bel, port, wire, PinType.INPUT)
590+
elif func == 'i3c_capable':
591+
tt.extra_data.tile_flags |= TILE_I3C_CAPABLE_IO
585592
elif func == 'mipi_obuf':
586593
bel = tt.create_bel('MIPI_OBUF', 'MIPI_OBUF', MIPIOBUF_Z)
587594
elif func == 'mipi_ibuf':

himbaechel/uarch/gowin/gowin_utils.cc

+9
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ Loc GowinUtils::get_tile_io16_offs(int x, int y)
3030
return Loc(extra->io16_x_off, extra->io16_y_off, 0);
3131
}
3232

33+
// oser16/ides16 aux cell offsets
34+
bool GowinUtils::get_i3c_capable(int x, int y)
35+
{
36+
int tile = tile_by_xy(ctx->chip_info, x, y);
37+
const Tile_extra_data_POD *extra =
38+
reinterpret_cast<const Tile_extra_data_POD *>(chip_tile_info(ctx->chip_info, tile).extra_data.get());
39+
return extra->tile_flags & Tile_extra_data_POD::TILE_I3C_CAPABLE_IO;
40+
}
41+
3342
// pin functions: GCLKT_4, SSPI_CS, READY etc
3443
IdStringList GowinUtils::get_pin_funcs(BelId io_bel)
3544
{

himbaechel/uarch/gowin/gowin_utils.h

+1
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct GowinUtils
2323
// tile
2424
IdString get_tile_class(int x, int y);
2525
Loc get_tile_io16_offs(int x, int y);
26+
bool get_i3c_capable(int x, int y);
2627

2728
// pin functions: GCLKT_4, SSPI_CS, READY etc
2829
IdStringList get_pin_funcs(BelId io_bel);

himbaechel/uarch/gowin/pack.cc

+53
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,47 @@ struct GowinPacker
308308
}
309309
}
310310

311+
// ===================================
312+
// I3C
313+
// ===================================
314+
void pack_i3c(void)
315+
{
316+
log_info("Pack I3C IOs...\n");
317+
std::vector<IdString> cells_to_remove;
318+
319+
for (auto &cell : ctx->cells) {
320+
CellInfo &ci = *cell.second;
321+
if (!is_i3c(&ci)) {
322+
continue;
323+
}
324+
// check for I3C-capable pin A
325+
CellInfo *iob = net_only_drives(ctx, ci.ports.at(id_IO).net, is_iob, id_I);
326+
if (iob == nullptr || iob->bel == BelId()) {
327+
log_error("I3C %s IO is not connected to the input pin or the pin is not constrained.\n",
328+
ctx->nameOf(&ci));
329+
}
330+
BelId iob_bel = iob->bel;
331+
Loc iob_loc = ctx->getBelLocation(iob_bel);
332+
333+
if (!gwu.get_i3c_capable(iob_loc.x, iob_loc.y)) {
334+
log_error("Can't place %s. Not I3C capable X%dY%d.\n", ctx->nameOf(&ci), iob_loc.x, iob_loc.y);
335+
}
336+
ci.disconnectPort(id_IO);
337+
iob->disconnectPort(id_I);
338+
ci.movePortTo(id_I, iob, id_I);
339+
ci.movePortTo(id_O, iob, id_O);
340+
iob->disconnectPort(id_OEN);
341+
ci.movePortTo(id_MODESEL, iob, id_OEN);
342+
343+
iob->setParam(id_I3C_IOBUF, 1);
344+
cells_to_remove.push_back(ci.name);
345+
}
346+
347+
for (auto cell : cells_to_remove) {
348+
ctx->cells.erase(cell);
349+
}
350+
}
351+
311352
// ===================================
312353
// MIPI IO
313354
// ===================================
@@ -330,6 +371,9 @@ struct GowinPacker
330371
log_error("MIPI %s is not connected to the output pin or the pin is not constrained.\n",
331372
ctx->nameOf(&ci));
332373
}
374+
if (out_iob->params.count(id_I3C_IOBUF)) {
375+
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(out_iob));
376+
}
333377
BelId iob_bel = out_iob->bel;
334378
Loc iob_loc = ctx->getBelLocation(iob_bel);
335379
iob_loc.z = BelZ::MIPIOBUF_Z;
@@ -383,6 +427,9 @@ struct GowinPacker
383427
ctx->nameOf(&ci));
384428
}
385429
// check A IO placing
430+
if (in_iob->params.count(id_I3C_IOBUF)) {
431+
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(in_iob));
432+
}
386433
BelId iob_bel = in_iob->bel;
387434
Loc iob_loc = ctx->getBelLocation(iob_bel);
388435
if (iob_loc.z != BelZ::IOBA_Z) {
@@ -402,6 +449,9 @@ struct GowinPacker
402449
ctx->nameOf(&ci));
403450
}
404451
// check B IO placing
452+
if (inb_iob->params.count(id_I3C_IOBUF)) {
453+
log_error("Can't place MIPI %s. Conflict with I3C %s.\n", ctx->nameOf(&ci), ctx->nameOf(inb_iob));
454+
}
405455
BelId iobb_bel = inb_iob->bel;
406456
Loc iobb_loc = ctx->getBelLocation(iobb_bel);
407457
if (iobb_loc.z != BelZ::IOBB_Z || iobb_loc.x != iob_loc.x || iobb_loc.y != iob_loc.y) {
@@ -4108,6 +4158,9 @@ struct GowinPacker
41084158
pack_iobs();
41094159
ctx->check();
41104160

4161+
pack_i3c();
4162+
ctx->check();
4163+
41114164
pack_mipi();
41124165
ctx->check();
41134166

0 commit comments

Comments
 (0)