Gowin. Implement the UserFlash primitive (#1357)
* Gowin. Implement the UserFlash primitive 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 <rabbit@yrabbit.cyou> * Gowin. Fix cell creation Signed-off-by: YRabbit <rabbit@yrabbit.cyou> --------- Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
2dc712130c
commit
4cf7afedf7
@ -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)
|
||||
|
@ -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
|
||||
// ==========================================
|
||||
@ -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
|
||||
|
@ -50,7 +50,9 @@ GND_Z = 278
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
@ -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
|
||||
@ -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
|
||||
@ -3072,6 +3076,96 @@ struct GowinPacker
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// Enable UserFlash
|
||||
// =========================================
|
||||
void pack_userflash()
|
||||
{
|
||||
log_info("Pack UserFlash cells...\n");
|
||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
std::unique_ptr<CellInfo> lut_cell =
|
||||
gwu.create_cell(create_aux_name(ci.name, lut_idx, "_lut$"), id_LUT4);
|
||||
new_cells.push_back(std::move(lut_cell));
|
||||
CellInfo *lut = new_cells.back().get();
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto &ncell : new_cells) {
|
||||
ctx->cells[ncell->name] = std::move(ncell);
|
||||
}
|
||||
}
|
||||
|
||||
void run(void)
|
||||
{
|
||||
handle_constants();
|
||||
@ -3124,6 +3218,9 @@ struct GowinPacker
|
||||
pack_buffered_nets();
|
||||
ctx->check();
|
||||
|
||||
pack_userflash();
|
||||
ctx->check();
|
||||
|
||||
pack_dqce();
|
||||
ctx->check();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user