From 02e40e811823b3165e4fbae15a3bb17554cb8ae2 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Sat, 11 Oct 2025 21:12:35 +1000 Subject: [PATCH] Gowin. Reduce the range of flip-flop types. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UG303-1.0E_Arora Ⅴ Configurable Function Unit (CFU) User Guide.pdf specifies that the only flip-flop types supported in GW5 are DFFSE, DFFRE, DFFPE, and DFFCE. However, the bit streams generated by the vendor IDE also contain DFF flip-flops, which are probably the result of optimisation, so we leave them in the list of permitted items, but add a flag that will allow the generation of completely correct output files, acceptable for further P& R using vendor tools (they will not allow the use of flip-flops other than the four specified in the netlist). In the GW5 SemiDual Port BSRAM series, the primitive does not have RESETA and RESETB ports—they are replaced by the RESET port, so we separate the files for BSRAM generation, especially since in the future we may have to take into account other, as yet unexplored, differences in BSRAM. Signed-off-by: YRabbit --- techlibs/gowin/Makefile.inc | 1 + techlibs/gowin/brams_map_gw5a.v | 399 ++++++++++++++++++++++++++++++++ techlibs/gowin/synth_gowin.cc | 28 ++- 3 files changed, 422 insertions(+), 6 deletions(-) create mode 100644 techlibs/gowin/brams_map_gw5a.v diff --git a/techlibs/gowin/Makefile.inc b/techlibs/gowin/Makefile.inc index 9ec7dce4d..df1b79317 100644 --- a/techlibs/gowin/Makefile.inc +++ b/techlibs/gowin/Makefile.inc @@ -8,6 +8,7 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw2a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_xtra_gw5a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.v)) +$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map_gw5a.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams.txt)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams_map.v)) $(eval $(call add_share_file,share/gowin,techlibs/gowin/lutrams.txt)) diff --git a/techlibs/gowin/brams_map_gw5a.v b/techlibs/gowin/brams_map_gw5a.v new file mode 100644 index 000000000..246146ee5 --- /dev/null +++ b/techlibs/gowin/brams_map_gw5a.v @@ -0,0 +1,399 @@ +`define DEF_FUNCS \ + function [255:0] init_slice_x8; \ + input integer idx; \ + integer i; \ + for (i = 0; i < 32; i = i + 1) begin \ + init_slice_x8[i*8+:8] = INIT[(idx * 32 + i) * 9+:8]; \ + end \ + endfunction \ + function [287:0] init_slice_x9; \ + input integer idx; \ + init_slice_x9 = INIT[idx * 288+:288]; \ + endfunction \ + +`define x8_width(width) (width / 9 * 8 + width % 9) +`define x8_rd_data(data) {1'bx, data[31:24], 1'bx, data[23:16], 1'bx, data[15:8], 1'bx, data[7:0]} +`define x8_wr_data(data) {data[34:27], data[25:18], data[16:9], data[7:0]} +`define addrbe_always(width, addr) (width < 18 ? addr : width == 18 ? {addr[13:4], 4'b0011} : {addr[13:5], 5'b01111}) + + +`define INIT(func) \ + .INIT_RAM_00(func('h00)), \ + .INIT_RAM_01(func('h01)), \ + .INIT_RAM_02(func('h02)), \ + .INIT_RAM_03(func('h03)), \ + .INIT_RAM_04(func('h04)), \ + .INIT_RAM_05(func('h05)), \ + .INIT_RAM_06(func('h06)), \ + .INIT_RAM_07(func('h07)), \ + .INIT_RAM_08(func('h08)), \ + .INIT_RAM_09(func('h09)), \ + .INIT_RAM_0A(func('h0a)), \ + .INIT_RAM_0B(func('h0b)), \ + .INIT_RAM_0C(func('h0c)), \ + .INIT_RAM_0D(func('h0d)), \ + .INIT_RAM_0E(func('h0e)), \ + .INIT_RAM_0F(func('h0f)), \ + .INIT_RAM_10(func('h10)), \ + .INIT_RAM_11(func('h11)), \ + .INIT_RAM_12(func('h12)), \ + .INIT_RAM_13(func('h13)), \ + .INIT_RAM_14(func('h14)), \ + .INIT_RAM_15(func('h15)), \ + .INIT_RAM_16(func('h16)), \ + .INIT_RAM_17(func('h17)), \ + .INIT_RAM_18(func('h18)), \ + .INIT_RAM_19(func('h19)), \ + .INIT_RAM_1A(func('h1a)), \ + .INIT_RAM_1B(func('h1b)), \ + .INIT_RAM_1C(func('h1c)), \ + .INIT_RAM_1D(func('h1d)), \ + .INIT_RAM_1E(func('h1e)), \ + .INIT_RAM_1F(func('h1f)), \ + .INIT_RAM_20(func('h20)), \ + .INIT_RAM_21(func('h21)), \ + .INIT_RAM_22(func('h22)), \ + .INIT_RAM_23(func('h23)), \ + .INIT_RAM_24(func('h24)), \ + .INIT_RAM_25(func('h25)), \ + .INIT_RAM_26(func('h26)), \ + .INIT_RAM_27(func('h27)), \ + .INIT_RAM_28(func('h28)), \ + .INIT_RAM_29(func('h29)), \ + .INIT_RAM_2A(func('h2a)), \ + .INIT_RAM_2B(func('h2b)), \ + .INIT_RAM_2C(func('h2c)), \ + .INIT_RAM_2D(func('h2d)), \ + .INIT_RAM_2E(func('h2e)), \ + .INIT_RAM_2F(func('h2f)), \ + .INIT_RAM_30(func('h30)), \ + .INIT_RAM_31(func('h31)), \ + .INIT_RAM_32(func('h32)), \ + .INIT_RAM_33(func('h33)), \ + .INIT_RAM_34(func('h34)), \ + .INIT_RAM_35(func('h35)), \ + .INIT_RAM_36(func('h36)), \ + .INIT_RAM_37(func('h37)), \ + .INIT_RAM_38(func('h38)), \ + .INIT_RAM_39(func('h39)), \ + .INIT_RAM_3A(func('h3a)), \ + .INIT_RAM_3B(func('h3b)), \ + .INIT_RAM_3C(func('h3c)), \ + .INIT_RAM_3D(func('h3d)), \ + .INIT_RAM_3E(func('h3e)), \ + .INIT_RAM_3F(func('h3f)), + +module $__GOWIN_SP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_A_WIDTH = 36; +parameter PORT_A_OPTION_WRITE_MODE = 0; + +input PORT_A_CLK; +input PORT_A_CLK_EN; +input PORT_A_WR_EN; +input PORT_A_RD_SRST; +input PORT_A_RD_ARST; +input [13:0] PORT_A_ADDR; +input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; + +`DEF_FUNCS + +wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; +wire [13:0] AD = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); + +generate + +if (PORT_A_WIDTH < 9) begin + + wire [31:0] DI = `x8_wr_data(PORT_A_WR_DATA); + wire [31:0] DO; + + assign PORT_A_RD_DATA = `x8_rd_data(DO); + + SP #( + `INIT(init_slice_x8) + .READ_MODE(1'b0), + .WRITE_MODE(PORT_A_OPTION_WRITE_MODE), + .BIT_WIDTH(`x8_width(PORT_A_WIDTH)), + .BLK_SEL(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSEL(3'b000), + .CLK(PORT_A_CLK), + .CE(PORT_A_CLK_EN), + .WRE(PORT_A_WR_EN), + .RESET(RST), + .OCE(1'b1), + .AD(AD), + .DI(DI), + .DO(DO), + ); + +end else begin + + wire [35:0] DI = PORT_A_WR_DATA; + wire [35:0] DO; + + assign PORT_A_RD_DATA = DO; + + SPX9 #( + `INIT(init_slice_x9) + .READ_MODE(1'b0), + .WRITE_MODE(PORT_A_OPTION_WRITE_MODE), + .BIT_WIDTH(PORT_A_WIDTH), + .BLK_SEL(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSEL(3'b000), + .CLK(PORT_A_CLK), + .CE(PORT_A_CLK_EN), + .WRE(PORT_A_WR_EN), + .RESET(RST), + .OCE(1'b1), + .AD(AD), + .DI(DI), + .DO(DO), + ); + +end + +endgenerate + +endmodule + + +module $__GOWIN_DP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_A_WIDTH = 18; +parameter PORT_A_OPTION_WRITE_MODE = 0; + +parameter PORT_B_WIDTH = 18; +parameter PORT_B_OPTION_WRITE_MODE = 0; + +input PORT_A_CLK; +input PORT_A_CLK_EN; +input PORT_A_WR_EN; +input PORT_A_RD_SRST; +input PORT_A_RD_ARST; +input [13:0] PORT_A_ADDR; +input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA; + +input PORT_B_CLK; +input PORT_B_CLK_EN; +input PORT_B_WR_EN; +input PORT_B_RD_SRST; +input PORT_B_RD_ARST; +input [13:0] PORT_B_ADDR; +input [PORT_A_WIDTH-1:0] PORT_B_WR_DATA; +output [PORT_A_WIDTH-1:0] PORT_B_RD_DATA; + +`DEF_FUNCS + +wire RSTA = OPTION_RESET_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST; +wire RSTB = OPTION_RESET_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST; +wire [13:0] ADA = `addrbe_always(PORT_A_WIDTH, PORT_A_ADDR); +wire [13:0] ADB = `addrbe_always(PORT_B_WIDTH, PORT_B_ADDR); + +generate + +if (PORT_A_WIDTH < 9 || PORT_B_WIDTH < 9) begin + + wire [15:0] DIA = `x8_wr_data(PORT_A_WR_DATA); + wire [15:0] DIB = `x8_wr_data(PORT_B_WR_DATA); + wire [15:0] DOA; + wire [15:0] DOB; + + assign PORT_A_RD_DATA = `x8_rd_data(DOA); + assign PORT_B_RD_DATA = `x8_rd_data(DOB); + + DPB #( + `INIT(init_slice_x8) + .READ_MODE0(1'b0), + .READ_MODE1(1'b0), + .WRITE_MODE0(PORT_A_OPTION_WRITE_MODE), + .WRITE_MODE1(PORT_B_OPTION_WRITE_MODE), + .BIT_WIDTH_0(`x8_width(PORT_A_WIDTH)), + .BIT_WIDTH_1(`x8_width(PORT_B_WIDTH)), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_A_CLK), + .CEA(PORT_A_CLK_EN), + .WREA(PORT_A_WR_EN), + .RESETA(RSTA), + .OCEA(1'b1), + .ADA(ADA), + .DIA(DIA), + .DOA(DOA), + + .CLKB(PORT_B_CLK), + .CEB(PORT_B_CLK_EN), + .WREB(PORT_B_WR_EN), + .RESETB(RSTB), + .OCEB(1'b1), + .ADB(ADB), + .DIB(DIB), + .DOB(DOB), + ); + +end else begin + + wire [17:0] DIA = PORT_A_WR_DATA; + wire [17:0] DIB = PORT_B_WR_DATA; + wire [17:0] DOA; + wire [17:0] DOB; + + assign PORT_A_RD_DATA = DOA; + assign PORT_B_RD_DATA = DOB; + + DPX9B #( + `INIT(init_slice_x9) + .READ_MODE0(1'b0), + .READ_MODE1(1'b0), + .WRITE_MODE0(PORT_A_OPTION_WRITE_MODE), + .WRITE_MODE1(PORT_B_OPTION_WRITE_MODE), + .BIT_WIDTH_0(PORT_A_WIDTH), + .BIT_WIDTH_1(PORT_B_WIDTH), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_A_CLK), + .CEA(PORT_A_CLK_EN), + .WREA(PORT_A_WR_EN), + .RESETA(RSTA), + .OCEA(1'b1), + .ADA(ADA), + .DIA(DIA), + .DOA(DOA), + + .CLKB(PORT_B_CLK), + .CEB(PORT_B_CLK_EN), + .WREB(PORT_B_WR_EN), + .RESETB(RSTB), + .OCEB(1'b1), + .ADB(ADB), + .DIB(DIB), + .DOB(DOB), + ); + +end + +endgenerate + +endmodule + + +module $__GOWIN_SDP_ (...); + +parameter INIT = 0; +parameter OPTION_RESET_MODE = "SYNC"; + +parameter PORT_R_WIDTH = 18; +parameter PORT_W_WIDTH = 18; + +input PORT_R_CLK; +input PORT_R_CLK_EN; +input PORT_R_RD_SRST; +input PORT_R_RD_ARST; +input [13:0] PORT_R_ADDR; +output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA; + +input PORT_W_CLK; +input PORT_W_CLK_EN; +input PORT_W_WR_EN; +input [13:0] PORT_W_ADDR; +input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA; + +`DEF_FUNCS + +wire RST = OPTION_RESET_MODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST; +wire [13:0] ADW = `addrbe_always(PORT_W_WIDTH, PORT_W_ADDR); +wire WRE = PORT_W_CLK_EN & PORT_W_WR_EN; + +generate + +if (PORT_W_WIDTH < 9 || PORT_R_WIDTH < 9) begin + + wire [31:0] DI = `x8_wr_data(PORT_W_WR_DATA); + wire [31:0] DO; + + assign PORT_R_RD_DATA = `x8_rd_data(DO); + + SDPB #( + `INIT(init_slice_x8) + .READ_MODE(1'b0), + .BIT_WIDTH_0(`x8_width(PORT_W_WIDTH)), + .BIT_WIDTH_1(`x8_width(PORT_R_WIDTH)), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_W_CLK), + .CEA(WRE), + .ADA(ADW), + .DI(DI), + + .CLKB(PORT_R_CLK), + .CEB(PORT_R_CLK_EN), + .RESET(RST), + .OCE(1'b1), + .ADB(PORT_R_ADDR), + .DO(DO), + ); + +end else begin + + wire [35:0] DI = PORT_W_WR_DATA; + wire [35:0] DO; + + assign PORT_R_RD_DATA = DO; + + SDPX9B #( + `INIT(init_slice_x9) + .READ_MODE(1'b0), + .BIT_WIDTH_0(PORT_W_WIDTH), + .BIT_WIDTH_1(PORT_R_WIDTH), + .BLK_SEL_0(3'b000), + .BLK_SEL_1(3'b000), + .RESET_MODE(OPTION_RESET_MODE), + ) _TECHMAP_REPLACE_ ( + .BLKSELA(3'b000), + .BLKSELB(3'b000), + + .CLKA(PORT_W_CLK), + .CEA(WRE), + .ADA(ADW), + .DI(DI), + + .CLKB(PORT_R_CLK), + .CEB(PORT_R_CLK_EN), + .RESET(RST), + .OCE(1'b1), + .ADB(PORT_R_ADDR), + .DO(DO), + ); + +end + +endgenerate + +endmodule diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 8f3553df6..03766ed36 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -57,6 +57,9 @@ struct SynthGowinPass : public ScriptPass log(" -nodffe\n"); log(" do not use flipflops with CE in output netlist\n"); log("\n"); + log(" -strict-gw5a-dffs\n"); + log(" use only DFFSE/DFFRE/DFFPE/DFFCE flipflops for the GW5A family\n"); + log("\n"); log(" -nobram\n"); log(" do not use BRAM cells in output netlist\n"); log("\n"); @@ -97,7 +100,7 @@ struct SynthGowinPass : public ScriptPass } string top_opt, vout_file, json_file, family; - bool retime, nobram, nolutram, flatten, nodffe, nowidelut, abc9, noiopads, noalu, no_rw_check; + bool retime, nobram, nolutram, flatten, nodffe, strict_gw5a_dffs, nowidelut, abc9, noiopads, noalu, no_rw_check; void clear_flags() override { @@ -109,6 +112,7 @@ struct SynthGowinPass : public ScriptPass flatten = true; nobram = false; nodffe = false; + strict_gw5a_dffs = false; nolutram = false; nowidelut = false; abc9 = true; @@ -165,6 +169,10 @@ struct SynthGowinPass : public ScriptPass nodffe = true; continue; } + if (args[argidx] == "-strict-gw5a-dffs") { + strict_gw5a_dffs = true; + continue; + } if (args[argidx] == "-noflatten") { flatten = false; continue; @@ -248,7 +256,7 @@ struct SynthGowinPass : public ScriptPass args += " -no-auto-distributed"; } run("memory_libmap -lib +/gowin/lutrams.txt -lib +/gowin/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); - run("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map.v"); + run(stringf("techmap -map +/gowin/lutrams_map.v -map +/gowin/brams_map%s.v", family == "gw5a" ? "_gw5a" : "")); } if (check_label("map_ffram")) @@ -276,10 +284,18 @@ struct SynthGowinPass : public ScriptPass if (check_label("map_ffs")) { run("opt_clean"); - if (nodffe) - run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFF_?P?_ r -cell $_DFF_?P?_ r"); - else - run("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_SDFF_?P?_ r -cell $_SDFFE_?P?P_ r -cell $_DFF_?P?_ r -cell $_DFFE_?P?P_ r"); + if (family == "gw5a") { + if (strict_gw5a_dffs) { + run("dfflegalize -cell $_SDFFE_PP?P_ r -cell $_DFFE_PP?P_ r"); + } else { + run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFFE_PP?P_ r -cell $_DFFE_PP?P_ r"); + } + } else { + if (nodffe) + run("dfflegalize -cell $_DFF_?_ 0 -cell $_SDFF_?P?_ r -cell $_DFF_?P?_ r"); + else + run("dfflegalize -cell $_DFF_?_ 0 -cell $_DFFE_?P_ 0 -cell $_SDFF_?P?_ r -cell $_SDFFE_?P?P_ r -cell $_DFF_?P?_ r -cell $_DFFE_?P?P_ r"); + } run("techmap -map +/gowin/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap");