From 50bd8d09b07d8e62959ae299177310c2e7f9e4e9 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 12 Sep 2024 17:53:39 +1000 Subject: [PATCH] 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 * Gowin. Fix merge. Signed-off-by: YRabbit --------- Signed-off-by: YRabbit --- himbaechel/uarch/gowin/constids.inc | 3 + himbaechel/uarch/gowin/gowin.h | 7 +- himbaechel/uarch/gowin/gowin_arch_gen.py | 15 +++ himbaechel/uarch/gowin/pack.cc | 122 ++++++++++++++++++++++- 4 files changed, 142 insertions(+), 5 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index e8e6874a6d..f15496b714 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -1289,3 +1289,6 @@ X(RESETN) //HCLK Parameters X(DIV_MODE) X(GSREN) + +// EMCU +X(EMCU) diff --git a/himbaechel/uarch/gowin/gowin.h b/himbaechel/uarch/gowin/gowin.h index deb70eecf9..1588b27b91 100644 --- a/himbaechel/uarch/gowin/gowin.h +++ b/himbaechel/uarch/gowin/gowin.h @@ -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. diff --git a/himbaechel/uarch/gowin/gowin_arch_gen.py b/himbaechel/uarch/gowin/gowin_arch_gen.py index d8aa303eae..7daed96354 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -56,6 +56,8 @@ 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 diff --git a/himbaechel/uarch/gowin/pack.cc b/himbaechel/uarch/gowin/pack.cc index 8d03b3a00a..78389d7fd7 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -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> 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> 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();