anlogic: support BRAM mapping
authorIcenowy Zheng <icenowy@aosc.io>
Fri, 17 Dec 2021 12:25:32 +0000 (20:25 +0800)
committerIcenowy Zheng <icenowy@aosc.io>
Fri, 17 Dec 2021 12:28:22 +0000 (20:28 +0800)
Anlogic FPGAs all have two kinds of BRAMs, one is 9bit*1K when being
true dual port (or 18bit*512 when simple dual port), the other is
16bit*2K.

Supports mapping of these two kinds of BRAMs. 9Kbit BRAM in SDP mode and
32Kbit BRAM with 8bit width are not support yet.

Signed-off-by: Icenowy Zheng <icenowy@aosc.io>
techlibs/anlogic/.gitignore [new file with mode: 0644]
techlibs/anlogic/Makefile.inc
techlibs/anlogic/brams.txt [new file with mode: 0644]
techlibs/anlogic/brams_init.py [new file with mode: 0644]
techlibs/anlogic/brams_map.v [new file with mode: 0644]
techlibs/anlogic/synth_anlogic.cc
tests/arch/anlogic/blockram.ys [new file with mode: 0644]
tests/arch/anlogic/lutram.ys

diff --git a/techlibs/anlogic/.gitignore b/techlibs/anlogic/.gitignore
new file mode 100644 (file)
index 0000000..d127107
--- /dev/null
@@ -0,0 +1,2 @@
+brams_init.mk
+brams_init_*.vh
index 2d8d65e2e41978e5281bbd7f5a39387ed98d76e0..79519c645d52fcda7c19eacb20716d65d54854a4 100644 (file)
@@ -3,6 +3,22 @@ OBJS += techlibs/anlogic/synth_anlogic.o
 OBJS += techlibs/anlogic/anlogic_eqn.o
 OBJS += techlibs/anlogic/anlogic_fixcarry.o
 
+GENFILES += techlibs/anlogic/brams_init_16.vh
+GENFILES += techlibs/anlogic/brams_init_9.vh
+GENFILES += techlibs/anlogic/brams_init_8.vh
+
+EXTRA_OBJS += techlibs/anlogic/brams_init.mk
+.SECONDARY: techlibs/anlogic/brams_init.mk
+
+techlibs/anlogic/brams_init.mk: techlibs/anlogic/brams_init.py
+       $(Q) mkdir -p techlibs/anlogic
+       $(P) $(PYTHON_EXECUTABLE) $<
+       $(Q) touch $@
+
+techlibs/anlogic/brams_init_16.vh: techlibs/anlogic/brams_init.mk
+techlibs/anlogic/brams_init_9.vh: techlibs/anlogic/brams_init.mk
+techlibs/anlogic/brams_init_8.vh: techlibs/anlogic/brams_init.mk
+
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_map.v))
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/arith_map.v))
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/cells_sim.v))
@@ -10,3 +26,9 @@ $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/eagle_bb.v))
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams.txt))
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutrams_map.v))
 $(eval $(call add_share_file,share/anlogic,techlibs/anlogic/lutram_init_16x4.vh))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/brams.txt))
+$(eval $(call add_share_file,share/anlogic,techlibs/anlogic/brams_map.v))
+
+$(eval $(call add_gen_share_file,share/anlogic,techlibs/anlogic/brams_init_16.vh))
+$(eval $(call add_gen_share_file,share/anlogic,techlibs/anlogic/brams_init_9.vh))
+$(eval $(call add_gen_share_file,share/anlogic,techlibs/anlogic/brams_init_8.vh))
diff --git a/techlibs/anlogic/brams.txt b/techlibs/anlogic/brams.txt
new file mode 100644 (file)
index 0000000..817d7d6
--- /dev/null
@@ -0,0 +1,45 @@
+bram $__ANLOGIC_BRAM9K_TDP
+  init 1
+  abits  13 @a13d1
+  dbits  1  @a13d1
+  abits  12 @a12d2
+  dbits  2  @a12d2
+  abits  11 @a11d4
+  dbits  4  @a11d4
+  abits  10 @a10d8
+  dbits  8  @a10d8
+  abits  10 @a10d9
+  dbits  9  @a10d9
+  groups 2
+  ports  1 1
+  wrmode 0 1
+  enable 1 1
+  transp 2 0
+  clocks 2 3
+  clkpol 2 3
+endbram
+
+bram $__ANLOGIC_BRAM32K
+  init 1
+  abits  11
+  dbits  16
+  groups 2
+  ports  1 1
+  wrmode 0 1
+  enable 1 2
+  transp 0 0
+  clocks 2 3
+  clkpol 2 3
+endbram
+
+match $__ANLOGIC_BRAM32K
+  min efficiency 30
+  shuffle_enable B
+  make_transp
+  or_next_if_better
+endmatch
+
+match $__ANLOGIC_BRAM9K_TDP
+  min efficiency 5
+  make_transp
+endmatch
diff --git a/techlibs/anlogic/brams_init.py b/techlibs/anlogic/brams_init.py
new file mode 100644 (file)
index 0000000..8dda0d3
--- /dev/null
@@ -0,0 +1,21 @@
+#!/usr/bin/env python3
+
+with open("techlibs/anlogic/brams_init_9.vh", "w") as f:
+    for i in range(4):
+        init_snippets = [" INIT[%3d*9+8]" % (k+256*i,) for k in range(255, -1, -1)]
+        for k in range(4, 256, 4):
+            init_snippets[k] = "\n           " + init_snippets[k]
+        print(".INITP_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
+    for i in range(32):
+        init_snippets = [" INIT[%3d*9 +: 8]" % (k+32*i,) for k in range(31, -1, -1)]
+        for k in range(4, 32, 4):
+            init_snippets[k] = "\n          " + init_snippets[k]
+        print(".INIT_%02X({%s})," % (i, ",".join(init_snippets)), file=f)
+
+with open("techlibs/anlogic/brams_init_8.vh", "w") as f:
+    for i in range(32):
+        print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
+
+with open("techlibs/anlogic/brams_init_16.vh", "w") as f:
+    for i in range(128):
+        print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
diff --git a/techlibs/anlogic/brams_map.v b/techlibs/anlogic/brams_map.v
new file mode 100644 (file)
index 0000000..ee02b6d
--- /dev/null
@@ -0,0 +1,162 @@
+module \$__ANLOGIC_BRAM9K_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+       parameter CFG_ABITS = 10;
+       parameter CFG_DBITS = 9;
+
+       parameter CLKPOL2 = 1;
+       parameter CLKPOL3 = 1;
+       parameter [9215:0] INIT = 9216'bx;
+       parameter TRANSP2 = 0;
+
+       input CLK2;
+       input CLK3;
+
+       input [CFG_ABITS-1:0] A1ADDR;
+       output [CFG_DBITS-1:0] A1DATA;
+       input A1EN;
+
+       input [CFG_ABITS-1:0] B1ADDR;
+       input [CFG_DBITS-1:0] B1DATA;
+       input B1EN;
+
+       localparam CLKAMUX = CLKPOL2 ? "SIG" : "INV";
+       localparam CLKBMUX = CLKPOL3 ? "SIG" : "INV";
+
+       localparam WRITEMODE_B = TRANSP2 ? "WRITETHROUGH" : "READBEFOREWRITE";
+
+       localparam DATA_WIDTH = CFG_DBITS == 1 ? "1" :
+                               (CFG_DBITS == 2 ? "2" :
+                                (CFG_DBITS <= 4 ? "4" : "9"));
+
+       localparam APADBITS = $clog2(CFG_DBITS == 9 ? 8 : CFG_DBITS);
+
+       wire [12:0] addra;
+       wire [12:0] addrb;
+
+       assign addra[12:APADBITS] = A1ADDR;
+       assign addrb[12:APADBITS] = B1ADDR;
+
+       wire [8:0] doa;
+       wire [8:0] dib;
+
+       assign A1DATA[CFG_DBITS-1:0] = doa;
+       assign dib[CFG_DBITS-1:0] = B1DATA;
+
+       generate if (CFG_DBITS == 9) begin
+               EG_PHY_BRAM #(
+                       .MODE("DP8K"),
+                       .DATA_WIDTH_A(DATA_WIDTH),
+                       .DATA_WIDTH_B(DATA_WIDTH),
+                       .READBACK("OFF"),
+                       .REGMODE_A("NOREG"),
+                       .REGMODE_B("NOREG"),
+                       .WRITEMODE_A("READBEFOREWRITE"),
+                       .WRITEMODE_B(WRITEMODE_B),
+                       .RESETMODE("ASYNC"),
+                       .CEAMUX("SIG"), .CEBMUX("SIG"),
+                       .OCEAMUX("1"), .OCEBMUX("1"),
+                       .RSTAMUX("0"), .RSTBMUX("0"),
+                       .CLKAMUX(CLKAMUX),
+                       .CLKBMUX(CLKBMUX),
+                       .WEAMUX("0"), .WEBMUX("SIG"),
+                       .CSA0("1"), .CSA1("1"),
+                       .CSA2("1"), .CSB0("1"),
+                       .CSB1("1"), .CSB2("1"),
+                       `include "brams_init_9.vh"
+               ) _TECHMAP_REPLACE_ (
+                       .doa(doa), .dib(dib),
+                       .addra(addra), .addrb(addrb),
+                       .clka(CLK2), .clkb(CLK3),
+                       .cea(A1EN), .ceb(B1EN),
+                       .ocea(1'b1), .oceb(1'b1),
+                       .rsta(1'b0), .rstb(1'b0),
+                       .wea(1'b0), .web(B1EN),
+                       .csa(3'b111), .csb(3'b111)
+               );
+       end else begin
+               EG_PHY_BRAM #(
+                       .MODE("DP8K"),
+                       .DATA_WIDTH_A(DATA_WIDTH),
+                       .DATA_WIDTH_B(DATA_WIDTH),
+                       .READBACK("OFF"),
+                       .REGMODE_A("NOREG"),
+                       .REGMODE_B("NOREG"),
+                       .WRITEMODE_A("READBEFOREWRITE"),
+                       .WRITEMODE_B(WRITEMODE_B),
+                       .RESETMODE("ASYNC"),
+                       .CEAMUX("SIG"), .CEBMUX("SIG"),
+                       .OCEAMUX("1"), .OCEBMUX("1"),
+                       .RSTAMUX("0"), .RSTBMUX("0"),
+                       .CLKAMUX(CLKAMUX),
+                       .CLKBMUX(CLKBMUX),
+                       .WEAMUX("0"), .WEBMUX("SIG"),
+                       .CSA0("1"), .CSA1("1"),
+                       .CSA2("1"), .CSB0("1"),
+                       .CSB1("1"), .CSB2("1"),
+                       `include "brams_init_8.vh"
+               ) _TECHMAP_REPLACE_ (
+                       .doa(doa), .dib(dib),
+                       .addra(addra), .addrb(addrb),
+                       .clka(CLK2), .clkb(CLK3),
+                       .cea(A1EN), .ceb(B1EN),
+                       .ocea(1'b1), .oceb(1'b1),
+                       .rsta(1'b0), .rstb(1'b0),
+                       .wea(1'b0), .web(B1EN),
+                       .csa(3'b111), .csb(3'b111)
+               );
+       end endgenerate
+endmodule
+
+module \$__ANLOGIC_BRAM32K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
+       parameter CFG_ABITS = 11;
+       parameter CFG_DBITS = 16;
+
+       parameter CLKPOL2 = 1;
+       parameter CLKPOL3 = 1;
+       parameter [32767:0] INIT = 32768'bx;
+
+       input CLK2;
+       input CLK3;
+
+       input [CFG_ABITS-1:0] A1ADDR;
+       output [CFG_DBITS-1:0] A1DATA;
+       input A1EN;
+
+       input [CFG_ABITS-1:0] B1ADDR;
+       input [CFG_DBITS-1:0] B1DATA;
+       input [1:0] B1EN;
+
+       localparam CLKAMUX = CLKPOL2 ? "SIG" : "INV";
+       localparam CLKBMUX = CLKPOL3 ? "SIG" : "INV";
+
+       wire byteweb = B1EN[1] ^ B1EN[0];
+       wire byteb = B1EN[1];
+
+       EG_PHY_BRAM32K #(
+               .MODE("DP16K"),
+               .DATA_WIDTH_A("16"),
+               .DATA_WIDTH_B("16"),
+               .REGMODE_A("NOREG"),
+               .REGMODE_B("NOREG"),
+               .WRITEMODE_A("NORMAL"),
+               .WRITEMODE_B("NORMAL"),
+               .SRMODE("ASYNC"),
+               .CSAMUX("SIG"), .CSBMUX("SIG"),
+               .OCEAMUX("1"), .OCEBMUX("1"),
+               .RSTAMUX("0"), .RSTBMUX("0"),
+               .CLKAMUX(CLKAMUX),
+               .CLKBMUX(CLKBMUX),
+               .WEAMUX("0"), .WEBMUX("SIG"),
+               .READBACK("OFF"),
+               `include "brams_init_16.vh"
+       ) _TECHMAP_REPLACE_ (
+               .doa(A1DATA), .dib(B1DATA),
+               .addra(A1ADDR), .addrb(B1ADDR),
+               .bytea(1'b0), .byteb(byteb),
+               .bytewea(1'b0), .byteweb(byteweb),
+               .csa(A1EN), .csb(|B1EN),
+               .wea(1'b0), .web(|B1EN),
+               .clka(CLK2), .clkb(CLK3),
+               .rsta(1'b0), .rstb(1'b0),
+               .ocea(1'b1), .oceb(1'b1)
+       );
+endmodule
index 039cae00e736468506b4b879fce37fded74b96e9..5da14c26b84ef783c201038454c8ae4996e1b3a0 100644 (file)
@@ -63,6 +63,9 @@ struct SynthAnlogicPass : public ScriptPass
                log("    -nolutram\n");
                log("        do not use EG_LOGIC_DRAM16X4 cells in output netlist\n");
                log("\n");
+               log("    -nobram\n");
+               log("        do not use EG_PHY_BRAM or EG_PHY_BRAM32K cells in output netlist\n");
+               log("\n");
                log("\n");
                log("The following commands are executed by this synthesis command:\n");
                help_script();
@@ -70,7 +73,7 @@ struct SynthAnlogicPass : public ScriptPass
        }
 
        string top_opt, edif_file, json_file;
-       bool flatten, retime, nolutram;
+       bool flatten, retime, nolutram, nobram;
 
        void clear_flags() override
        {
@@ -80,6 +83,7 @@ struct SynthAnlogicPass : public ScriptPass
                flatten = true;
                retime = false;
                nolutram = false;
+               nobram = false;
        }
 
        void execute(std::vector<std::string> args, RTLIL::Design *design) override
@@ -118,6 +122,10 @@ struct SynthAnlogicPass : public ScriptPass
                                nolutram = true;
                                continue;
                        }
+                       if (args[argidx] == "-nobram") {
+                               nobram = true;
+                               continue;
+                       }
                        if (args[argidx] == "-retime") {
                                retime = true;
                                continue;
@@ -158,6 +166,14 @@ struct SynthAnlogicPass : public ScriptPass
                        run("synth -run coarse");
                }
 
+               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
+               {
+                       run("memory_bram -rules +/anlogic/brams.txt");
+                       run("techmap -map +/anlogic/brams_map.v");
+                       run("setundef -zero -params t:EG_PHY_BRAM");
+                       run("setundef -zero -params t:EG_PHY_BRAM32K");
+               }
+
                if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
                {
                        run("memory_bram -rules +/anlogic/lutrams.txt");
diff --git a/tests/arch/anlogic/blockram.ys b/tests/arch/anlogic/blockram.ys
new file mode 100644 (file)
index 0000000..da23409
--- /dev/null
@@ -0,0 +1,13 @@
+read_verilog ../common/blockram.v
+hierarchy -top sync_ram_sp
+proc
+memory -nomap
+equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
+memory
+opt -full
+
+design -load postopt
+cd sync_ram_sp
+
+select -assert-count 1 t:EG_PHY_BRAM
+select -assert-none t:EG_PHY_BRAM %% t:* %D
index 6dbdbdac3e8edc57d83c588f40256988b08316fd..fe6135c73ac6052def66aa9cb8493dbaa50222cd 100644 (file)
@@ -2,7 +2,7 @@ read_verilog ../common/lutram.v
 hierarchy -top lutram_1w1r
 proc
 memory -nomap
-equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic
+equiv_opt -run :prove -map +/anlogic/cells_sim.v synth_anlogic -nobram
 memory
 opt -full