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. Implement the UserFlash primitive #1357

Merged
merged 2 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

creating a cell while also iterating over the cells map is not permitted - usually the best thing to do is build up a vector of user flash cells and then iterate over that to do the actual task of packing with creating cells, etc

Copy link
Contributor Author

@yrabbit yrabbit Sep 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake.

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