Skip to content

Commit

Permalink
Gowin. Implement the UserFlash primitive
Browse files Browse the repository at this point in the history
Some Gowin chips have embedded flash memory accessible from the fabric.
Here we add primitives that allow access to this memory.

Signed-off-by: YRabbit <[email protected]>
  • Loading branch information
yrabbit committed Sep 2, 2024
1 parent 2dc7121 commit e7223be
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 3 deletions.
37 changes: 36 additions & 1 deletion himbaechel/uarch/gowin/constids.inc
Original file line number Diff line number Diff line change
Expand Up @@ -1193,7 +1193,42 @@ X(BOTTOM_IO_PORT_A)
X(BOTTOM_IO_PORT_B)
X(IOLOGIC_DUMMY)

//
// User Flash
X(INUSEN)
X(DIN)
X(DOUT)
X(XE)
X(YE)
X(SE)
X(PROG)
X(ERASE)
X(NVSTR)
X(XADR0)
X(XADR1)
X(XADR2)
X(XADR3)
X(XADR4)
X(XADR5)
X(XADR6)
X(XADR7)
X(XADR8)
X(YADR)
X(RA)
X(CA)
X(PA)
X(MODE)
X(SEQ)
X(RMODE)
X(WMODE)
X(RBYTESEL)
X(WBYTESEL)
X(FLASH96K)
X(FLASH256K)
X(FLASH608K)
X(FLASH128K)
X(FLASH64K)
X(FLASH64KZ)
X(FLASH96KA)

// wire types
X(GLOBAL_CLK)
Expand Down
12 changes: 11 additions & 1 deletion himbaechel/uarch/gowin/gowin.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ inline bool is_clkdiv2(const CellInfo *cell) { return type_is_clkdiv2(cell->type
// Return true for HCLK Cells
inline bool is_hclk(const CellInfo *cell) { return type_is_clkdiv2(cell->type) || type_is_clkdiv(cell->type); }

// Return true if a cell is a UserFlash
inline bool type_is_userflash(IdString cell_type)
{
return cell_type.in(id_FLASH96K, id_FLASH256K, id_FLASH608K, id_FLASH128K, id_FLASH64K, id_FLASH64K, id_FLASH64KZ,
id_FLASH96KA);
}
inline bool is_userflash(const CellInfo *cell) { return type_is_userflash(cell->type); }

// ==========================================
// extra data in the chip db
// ==========================================
Expand Down Expand Up @@ -155,7 +163,9 @@ enum
BANDGAP_Z = 279,

DQCE_Z = 280, // : 286 reserve for 6 DQCEs
DCS_Z = 286, // : 287 reserve for 2 DCSs
DCS_Z = 286, // : 288 reserve for 2 DCSs

USERFLASH_Z = 288,

// The two least significant bits encode Z for 9-bit adders and
// multipliers, if they are equal to 0, then we get Z of their common
Expand Down
16 changes: 15 additions & 1 deletion himbaechel/uarch/gowin/gowin_arch_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@
BANDGAP_Z = 279

DQCE_Z = 280 # : 286 reserve for 6 DQCEs
DCS_Z = 286 # : 287 reserve for 2 DCSs
DCS_Z = 286 # : 288 reserve for 2 DCSs

USERFLASH_Z = 288

DSP_Z = 509

Expand Down Expand Up @@ -527,6 +529,18 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
bel.flags = BEL_FLAG_GLOBAL
tt.add_bel_pin(bel, "I", wire, PinType.INPUT)
tt.add_bel_pin(bel, "O", wire_out, PinType.OUTPUT)
elif func == 'userflash':
bel = tt.create_bel("USERFLASH", desc['type'], USERFLASH_Z)
portmap = desc['ins']
for port, wire in portmap.items():
if not tt.has_wire(wire):
tt.create_wire(wire, "FLASH_IN")
tt.add_bel_pin(bel, port, wire, PinType.INPUT)
portmap = desc['outs']
for port, wire in portmap.items():
if not tt.has_wire(wire):
tt.create_wire(wire, "FLASH_OUT")
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)

def create_tiletype(create_func, chip: Chip, db: chipdb, x: int, y: int, ttyp: int):
has_extra_func = (y, x) in db.extra_func
Expand Down
90 changes: 90 additions & 0 deletions himbaechel/uarch/gowin/pack.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3006,6 +3006,8 @@ struct GowinPacker
// =========================================
void pack_dqce()
{
log_info("Pack DQCE cells...\n");

// At the placement stage, nothing can be said definitively about DQCE,
// so we make user cells virtual but allocate all available bels by
// creating and placing cells - we will use some of them after, and
Expand Down Expand Up @@ -3039,6 +3041,8 @@ struct GowinPacker
// =========================================
void pack_dcs()
{
log_info("Pack DCS cells...\n");

// At the placement stage, nothing can be said definitively about DCS,
// so we make user cells virtual but allocate all available bels by
// creating and placing cells - we will use some of them after, and
Expand Down Expand Up @@ -3072,6 +3076,89 @@ struct GowinPacker
}
}

// =========================================
// Enable UserFlash
// =========================================
void pack_userflash()
{
log_info("Pack UserFlash cells...\n");

for (auto &cell : ctx->cells) {
auto &ci = *cell.second;
if (!is_userflash(&ci)) {
continue;
}

if (ci.type.in(id_FLASH96K, id_FLASH256K, id_FLASH608K)) {
// enable
ci.addInput(id_INUSEN);
ci.connectPort(id_INUSEN, ctx->nets.at(ctx->id("$PACKER_GND")).get());
}
// rename ports
for (int i = 0; i < 32; ++i) {
ci.renamePort(ctx->idf("DIN[%d]", i), ctx->idf("DIN%d", i));
ci.renamePort(ctx->idf("DOUT[%d]", i), ctx->idf("DOUT%d", i));
}
if (ci.type.in(id_FLASH96K)) {
for (int i = 0; i < 6; ++i) {
ci.renamePort(ctx->idf("RA[%d]", i), ctx->idf("RA%d", i));
ci.renamePort(ctx->idf("CA[%d]", i), ctx->idf("CA%d", i));
ci.renamePort(ctx->idf("PA[%d]", i), ctx->idf("PA%d", i));
}
for (int i = 0; i < 2; ++i) {
ci.renamePort(ctx->idf("MODE[%d]", i), ctx->idf("MODE%d", i));
ci.renamePort(ctx->idf("SEQ[%d]", i), ctx->idf("SEQ%d", i));
ci.renamePort(ctx->idf("RMODE[%d]", i), ctx->idf("RMODE%d", i));
ci.renamePort(ctx->idf("WMODE[%d]", i), ctx->idf("WMODE%d", i));
ci.renamePort(ctx->idf("RBYTESEL[%d]", i), ctx->idf("RBYTESEL%d", i));
ci.renamePort(ctx->idf("WBYTESEL[%d]", i), ctx->idf("WBYTESEL%d", i));
}
} else {
for (int i = 0; i < 9; ++i) {
ci.renamePort(ctx->idf("XADR[%d]", i), ctx->idf("XADR%d", i));
}
for (int i = 0; i < 6; ++i) {
ci.renamePort(ctx->idf("YADR[%d]", i), ctx->idf("YADR%d", i));
}
}
// add invertor
int lut_idx = 0;
auto add_inv = [&](IdString port, PortType port_type) {
if (!port_used(&ci, port)) {
return;
}

CellInfo *lut = ctx->createCell(create_aux_name(ci.name, lut_idx, "_lut$"), id_LUT4);
lut->addInput(id_I0);
lut->addOutput(id_F);
lut->setParam(id_INIT, 0x5555);
++lut_idx;

if (port_type == PORT_IN) {
ci.movePortTo(port, lut, id_I0);
lut->connectPorts(id_F, &ci, port);
} else {
ci.movePortTo(port, lut, id_F);
ci.connectPorts(port, lut, id_I0);
}
};
for (auto pin : ci.ports) {
if (pin.second.type == PORT_OUT) {
add_inv(pin.first, PORT_OUT);
} else {
if (pin.first == id_INUSEN) {
continue;
}
if (ci.type == id_FLASH608K && pin.first.in(id_XADR0, id_XADR1, id_XADR2, id_XADR3, id_XADR4,
id_XADR5, id_XADR6, id_XADR7, id_XADR8)) {
continue;
}
add_inv(pin.first, PORT_IN);
}
}
}
}

void run(void)
{
handle_constants();
Expand Down Expand Up @@ -3124,6 +3211,9 @@ struct GowinPacker
pack_buffered_nets();
ctx->check();

pack_userflash();
ctx->check();

pack_dqce();
ctx->check();

Expand Down

0 comments on commit e7223be

Please sign in to comment.