From 21d98de743bc9ba347e05169e906116552df2305 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Wed, 11 Sep 2024 18:47:44 +1000 Subject: [PATCH] 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 --- himbaechel/uarch/gowin/constids.inc | 3 + himbaechel/uarch/gowin/gowin.h | 6 ++ himbaechel/uarch/gowin/gowin_arch_gen.py | 15 +++ himbaechel/uarch/gowin/pack.cc | 118 ++++++++++++++++++++++- 4 files changed, 140 insertions(+), 2 deletions(-) diff --git a/himbaechel/uarch/gowin/constids.inc b/himbaechel/uarch/gowin/constids.inc index 62a40360..1855c92f 100644 --- a/himbaechel/uarch/gowin/constids.inc +++ b/himbaechel/uarch/gowin/constids.inc @@ -1287,3 +1287,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 81c825f4..979122e5 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 // ========================================== @@ -167,6 +171,8 @@ enum USERFLASH_Z = 288, + 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 425d9171..694eb4fd 100644 --- a/himbaechel/uarch/gowin/gowin_arch_gen.py +++ b/himbaechel/uarch/gowin/gowin_arch_gen.py @@ -54,6 +54,8 @@ DCS_Z = 286 # : 288 reserve for 2 DCSs USERFLASH_Z = 288 +EMCU_Z = 300 + DSP_Z = 509 DSP_0_Z = 511 # DSP macro 0 @@ -540,6 +542,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 b7b64a48..9a5c2abc 100644 --- a/himbaechel/uarch/gowin/pack.cc +++ b/himbaechel/uarch/gowin/pack.cc @@ -3079,7 +3079,7 @@ struct GowinPacker // ========================================= // Enable UserFlash // ========================================= - void pack_userflash() + void pack_userflash(bool have_emcu) { log_info("Pack UserFlash cells...\n"); std::vector> new_cells; @@ -3122,6 +3122,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) { @@ -3166,6 +3171,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(); @@ -3218,7 +3332,7 @@ struct GowinPacker pack_buffered_nets(); ctx->check(); - pack_userflash(); + pack_emcu_and_flash(); ctx->check(); pack_dqce();