Gowin. Implement the EMCU primitive. (#1366)
* Gowin. Implement the EMCU primitive. Add support for the GW1NSR-4C's embedded Cortex-M3 processor. Since it uses flash in its own way, we disable additional flash processing for this case. Signed-off-by: YRabbit <rabbit@yrabbit.cyou> * Gowin. Fix merge. Signed-off-by: YRabbit <rabbit@yrabbit.cyou> --------- Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
ff7b8535bc
commit
50bd8d09b0
@ -1289,3 +1289,6 @@ X(RESETN)
|
||||
//HCLK Parameters
|
||||
X(DIV_MODE)
|
||||
X(GSREN)
|
||||
|
||||
// EMCU
|
||||
X(EMCU)
|
||||
|
@ -81,6 +81,10 @@ inline bool type_is_userflash(IdString cell_type)
|
||||
}
|
||||
inline bool is_userflash(const CellInfo *cell) { return type_is_userflash(cell->type); }
|
||||
|
||||
// Return true if a cell is a EMCU
|
||||
inline bool type_is_emcu(IdString cell_type) { return cell_type == id_EMCU; }
|
||||
inline bool is_emcu(const CellInfo *cell) { return type_is_emcu(cell->type); }
|
||||
|
||||
// ==========================================
|
||||
// extra data in the chip db
|
||||
// ==========================================
|
||||
@ -173,13 +177,14 @@ enum
|
||||
VSS_Z = 278,
|
||||
BANDGAP_Z = 279,
|
||||
|
||||
|
||||
DQCE_Z = 280, // : 286 reserve for 6 DQCEs
|
||||
DCS_Z = 286, // : 288 reserve for 2 DCSs
|
||||
DHCEN_Z = 288, // : 298
|
||||
|
||||
USERFLASH_Z = 298,
|
||||
|
||||
EMCU_Z = 300,
|
||||
|
||||
// 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
|
||||
// 18-bit equivalent.
|
||||
|
@ -56,6 +56,8 @@ DHCEN_Z = 288 # : 298
|
||||
USERFLASH_Z = 298
|
||||
|
||||
|
||||
EMCU_Z = 300
|
||||
|
||||
DSP_Z = 509
|
||||
|
||||
DSP_0_Z = 511 # DSP macro 0
|
||||
@ -585,6 +587,19 @@ def create_extra_funcs(tt: TileType, db: chipdb, x: int, y: int):
|
||||
if not tt.has_wire(wire):
|
||||
tt.create_wire(wire, "FLASH_OUT")
|
||||
tt.add_bel_pin(bel, port, wire, PinType.OUTPUT)
|
||||
elif func == 'emcu':
|
||||
bel = tt.create_bel("EMCU", "EMCU", EMCU_Z)
|
||||
portmap = desc['ins']
|
||||
for port, wire in portmap.items():
|
||||
print(port, wire)
|
||||
if not tt.has_wire(wire):
|
||||
tt.create_wire(wire, "EMCU_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, "EMCU_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
|
||||
|
@ -3094,7 +3094,7 @@ struct GowinPacker
|
||||
if (grab_bels) {
|
||||
// sane message if new primitives are used with old bases
|
||||
auto buckets = ctx->getBelBuckets();
|
||||
NPNR_ASSERT_MSG(std::find(buckets.begin(), buckets.end(), id_DHCEN) != buckets.end(),
|
||||
NPNR_ASSERT_MSG(std::find(buckets.begin(), buckets.end(), id_DHCEN) != buckets.end(),
|
||||
"There are no DHCEN bels to use.");
|
||||
int i = 0;
|
||||
for (auto &bel : ctx->getBelsInBucket(ctx->getBelBucketForCellType(id_DHCEN))) {
|
||||
@ -3109,7 +3109,7 @@ struct GowinPacker
|
||||
// =========================================
|
||||
// Enable UserFlash
|
||||
// =========================================
|
||||
void pack_userflash()
|
||||
void pack_userflash(bool have_emcu)
|
||||
{
|
||||
log_info("Pack UserFlash cells...\n");
|
||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||
@ -3152,6 +3152,11 @@ struct GowinPacker
|
||||
ci.renamePort(ctx->idf("YADR[%d]", i), ctx->idf("YADR%d", i));
|
||||
}
|
||||
}
|
||||
|
||||
if (have_emcu) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add invertor
|
||||
int lut_idx = 0;
|
||||
auto add_inv = [&](IdString port, PortType port_type) {
|
||||
@ -3196,6 +3201,115 @@ struct GowinPacker
|
||||
}
|
||||
}
|
||||
|
||||
// =========================================
|
||||
// Create EMCU
|
||||
// =========================================
|
||||
void pack_emcu_and_flash()
|
||||
{
|
||||
log_info("Pack EMCU and UserFlash cells...\n");
|
||||
std::vector<std::unique_ptr<CellInfo>> new_cells;
|
||||
|
||||
bool have_emcu = false;
|
||||
for (auto &cell : ctx->cells) {
|
||||
auto &ci = *cell.second;
|
||||
if (!is_emcu(&ci)) {
|
||||
continue;
|
||||
}
|
||||
have_emcu = true;
|
||||
|
||||
// rename ports
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
ci.renamePort(ctx->idf("TARGFLASH0HTRANS[%d]", i), ctx->idf("TARGFLASH0HTRANS%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HTRANS[%d]", i), ctx->idf("TARGEXP0HTRANS%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0MEMATTR[%d]", i), ctx->idf("TARGEXP0MEMATTR%d", i));
|
||||
// ins
|
||||
ci.renamePort(ctx->idf("INITEXP0HTRANS[%d]", i), ctx->idf("INITEXP0HTRANS%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0MEMATTR[%d]", i), ctx->idf("INITEXP0MEMATTR%d", i));
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
ci.renamePort(ctx->idf("TARGEXP0HSIZE[%d]", i), ctx->idf("TARGEXP0HSIZE%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HBURST[%d]", i), ctx->idf("TARGEXP0HBURST%d", i));
|
||||
ci.renamePort(ctx->idf("APBTARGEXP2PPROT[%d]", i), ctx->idf("APBTARGEXP2PPROT%d", i));
|
||||
// ins
|
||||
ci.renamePort(ctx->idf("TARGEXP0HRUSER[%d]", i), ctx->idf("TARGEXP0HRUSER%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HSIZE[%d]", i), ctx->idf("INITEXP0HSIZE%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HBURST[%d]", i), ctx->idf("INITEXP0HBURST%d", i));
|
||||
}
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
ci.renamePort(ctx->idf("SRAM0WREN[%d]", i), ctx->idf("SRAM0WREN%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HPROT[%d]", i), ctx->idf("TARGEXP0HPROT%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HMASTER[%d]", i), ctx->idf("TARGEXP0HMASTER%d", i));
|
||||
ci.renamePort(ctx->idf("APBTARGEXP2PSTRB[%d]", i), ctx->idf("APBTARGEXP2PSTRB%d", i));
|
||||
ci.renamePort(ctx->idf("TPIUTRACEDATA[%d]", i), ctx->idf("TPIUTRACEDATA%d", i));
|
||||
// ins
|
||||
ci.renamePort(ctx->idf("INITEXP0HPROT[%d]", i), ctx->idf("INITEXP0HPROT%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HMASTER[%d]", i), ctx->idf("INITEXP0HMASTER%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HWUSER[%d]", i), ctx->idf("INITEXP0HWUSER%d", i));
|
||||
}
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i < 13) {
|
||||
if (i < 12) {
|
||||
if (i < 5) {
|
||||
ci.renamePort(ctx->idf("GPINT[%d]", i), ctx->idf("GPINT%d", i));
|
||||
}
|
||||
ci.renamePort(ctx->idf("APBTARGEXP2PADDR[%d]", i), ctx->idf("APBTARGEXP2PADDR%d", i));
|
||||
}
|
||||
ci.renamePort(ctx->idf("SRAM0ADDR[%d]", i), ctx->idf("SRAM0ADDR%d", i));
|
||||
}
|
||||
ci.renamePort(ctx->idf("IOEXPOUTPUTO[%d]", i), ctx->idf("IOEXPOUTPUTO%d", i));
|
||||
ci.renamePort(ctx->idf("IOEXPOUTPUTENO[%d]", i), ctx->idf("IOEXPOUTPUTENO%d", i));
|
||||
// ins
|
||||
ci.renamePort(ctx->idf("IOEXPINPUTI[%d]", i), ctx->idf("IOEXPINPUTI%d", i));
|
||||
}
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (i < 29) {
|
||||
ci.renamePort(ctx->idf("TARGFLASH0HADDR[%d]", i), ctx->idf("TARGFLASH0HADDR%d", i));
|
||||
}
|
||||
ci.renamePort(ctx->idf("SRAM0WDATA[%d]", i), ctx->idf("SRAM0WDATA%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HADDR[%d]", i), ctx->idf("TARGEXP0HADDR%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HWDATA[%d]", i), ctx->idf("TARGEXP0HWDATA%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HRDATA[%d]", i), ctx->idf("INITEXP0HRDATA%d", i));
|
||||
ci.renamePort(ctx->idf("APBTARGEXP2PWDATA[%d]", i), ctx->idf("APBTARGEXP2PWDATA%d", i));
|
||||
// ins
|
||||
ci.renamePort(ctx->idf("SRAM0RDATA[%d]", i), ctx->idf("SRAM0RDATA%d", i));
|
||||
ci.renamePort(ctx->idf("TARGEXP0HRDATA[%d]", i), ctx->idf("TARGEXP0HRDATA%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HADDR[%d]", i), ctx->idf("INITEXP0HADDR%d", i));
|
||||
ci.renamePort(ctx->idf("INITEXP0HWDATA[%d]", i), ctx->idf("INITEXP0HWDATA%d", i));
|
||||
ci.renamePort(ctx->idf("APBTARGEXP2PRDATA[%d]", i), ctx->idf("APBTARGEXP2PRDATA%d", i));
|
||||
}
|
||||
// The flash data bus is connected directly to the CPU so just disconnect these networks
|
||||
// also other non-switched networks
|
||||
ci.disconnectPort(ctx->id("DAPNTDOEN"));
|
||||
ci.disconnectPort(ctx->id("DAPNTRST"));
|
||||
ci.disconnectPort(ctx->id("DAPTDO"));
|
||||
ci.disconnectPort(ctx->id("DAPTDI"));
|
||||
ci.disconnectPort(ctx->id("TARGFLASH0HREADYMUX"));
|
||||
ci.disconnectPort(ctx->id("TARGEXP0HAUSER"));
|
||||
ci.disconnectPort(ctx->id("TARGFLASH0EXRESP"));
|
||||
ci.disconnectPort(ctx->id("PORESETN"));
|
||||
ci.disconnectPort(ctx->id("SYSRESETN"));
|
||||
ci.disconnectPort(ctx->id("DAPSWDITMS"));
|
||||
ci.disconnectPort(ctx->id("DAPSWCLKTCK"));
|
||||
ci.disconnectPort(ctx->id("TPIUTRACECLK"));
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (i < 4) {
|
||||
if (i < 3) {
|
||||
ci.disconnectPort(ctx->idf("TARGFLASH0HSIZE[%d]", i));
|
||||
ci.disconnectPort(ctx->idf("TARGFLASH0HBURST[%d]", i));
|
||||
ci.disconnectPort(ctx->idf("TARGFLASH0HRUSER[%d]", i));
|
||||
ci.disconnectPort(ctx->idf("INITEXP0HRUSER[%d]", i));
|
||||
}
|
||||
// ci.disconnectPort(ctx->idf("TARGFLASH0HPROT[%d]", i));
|
||||
ci.disconnectPort(ctx->idf("TARGEXP0HWUSER[%d]", i));
|
||||
ci.disconnectPort(ctx->idf("MTXREMAP[%d]", i));
|
||||
}
|
||||
// ins
|
||||
ci.disconnectPort(ctx->idf("TARGFLASH0HRDATA[%d]", i));
|
||||
}
|
||||
}
|
||||
pack_userflash(have_emcu);
|
||||
}
|
||||
|
||||
void run(void)
|
||||
{
|
||||
handle_constants();
|
||||
@ -3248,10 +3362,10 @@ struct GowinPacker
|
||||
pack_buffered_nets();
|
||||
ctx->check();
|
||||
|
||||
pack_dhcens();
|
||||
pack_emcu_and_flash();
|
||||
ctx->check();
|
||||
|
||||
pack_userflash();
|
||||
pack_dhcens();
|
||||
ctx->check();
|
||||
|
||||
pack_dqce();
|
||||
|
Loading…
Reference in New Issue
Block a user