Merge branch 'divfloor-in-write_smt2' into smtlib2-expr-support smtlib2-expr-support-old
authorJacob Lifshay <programmerjake@gmail.com>
Wed, 25 May 2022 01:01:52 +0000 (18:01 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Wed, 25 May 2022 01:09:08 +0000 (18:09 -0700)
the smtlib2 support in nmigen needs $divfloor support in its tests:
https://gitlab.com/nmigen/nmigen/-/merge_requests/7

159 files changed:
CHANGELOG
Makefile
backends/smt2/smt2.cc
frontends/verific/verific.cc
frontends/verific/verific.h
frontends/verific/verificsva.cc
kernel/constids.inc
kernel/ff.cc
kernel/ff.h
kernel/mem.h
kernel/yosys.cc
passes/cmds/select.cc
passes/memory/Makefile.inc
passes/memory/memlib.cc [new file with mode: 0644]
passes/memory/memlib.h [new file with mode: 0644]
passes/memory/memlib.md [new file with mode: 0644]
passes/memory/memory.cc
passes/memory/memory_bmux2rom.cc [new file with mode: 0644]
passes/memory/memory_libmap.cc [new file with mode: 0644]
passes/opt/Makefile.inc
passes/opt/opt_ffinv.cc [new file with mode: 0644]
passes/proc/Makefile.inc
passes/proc/proc.cc
passes/proc/proc_rom.cc [new file with mode: 0644]
passes/techmap/abc9_ops.cc
techlibs/anlogic/.gitignore [deleted file]
techlibs/anlogic/Makefile.inc
techlibs/anlogic/brams.txt
techlibs/anlogic/brams_init.py [deleted file]
techlibs/anlogic/brams_map.v
techlibs/anlogic/lutram_init_16x4.vh [deleted file]
techlibs/anlogic/lutrams.txt
techlibs/anlogic/lutrams_map.v
techlibs/anlogic/synth_anlogic.cc
techlibs/ecp5/.gitignore [deleted file]
techlibs/ecp5/Makefile.inc
techlibs/ecp5/brams.txt
techlibs/ecp5/brams_connect.py [deleted file]
techlibs/ecp5/brams_init.py [deleted file]
techlibs/ecp5/brams_map.v
techlibs/ecp5/lutrams.txt
techlibs/ecp5/lutrams_map.v
techlibs/ecp5/synth_ecp5.cc
techlibs/efinix/brams.txt
techlibs/efinix/brams_map.v
techlibs/efinix/synth_efinix.cc
techlibs/gatemate/brams.txt
techlibs/gatemate/brams_map.v
techlibs/gatemate/synth_gatemate.cc
techlibs/gowin/.gitignore [deleted file]
techlibs/gowin/Makefile.inc
techlibs/gowin/brams.txt
techlibs/gowin/brams_init.py [deleted file]
techlibs/gowin/brams_init3.vh [deleted file]
techlibs/gowin/brams_map.v
techlibs/gowin/lutrams.txt
techlibs/gowin/lutrams_map.v
techlibs/gowin/synth_gowin.cc
techlibs/ice40/.gitignore [deleted file]
techlibs/ice40/Makefile.inc
techlibs/ice40/brams.txt
techlibs/ice40/brams_init.py [deleted file]
techlibs/ice40/brams_map.v
techlibs/ice40/spram.txt [new file with mode: 0644]
techlibs/ice40/spram_map.v [new file with mode: 0644]
techlibs/ice40/synth_ice40.cc
techlibs/machxo2/Makefile.inc
techlibs/machxo2/brams.txt [new file with mode: 0644]
techlibs/machxo2/brams_map.v [new file with mode: 0644]
techlibs/machxo2/cells_sim.v
techlibs/machxo2/lutrams.txt [new file with mode: 0644]
techlibs/machxo2/lutrams_map.v [new file with mode: 0644]
techlibs/machxo2/synth_machxo2.cc
techlibs/nexus/Makefile.inc
techlibs/nexus/brams.txt
techlibs/nexus/brams_init.vh [deleted file]
techlibs/nexus/brams_map.v
techlibs/nexus/lrams.txt
techlibs/nexus/lrams_init.vh [deleted file]
techlibs/nexus/lrams_map.v
techlibs/nexus/lutrams.txt
techlibs/nexus/lutrams_map.v
techlibs/nexus/synth_nexus.cc
techlibs/xilinx/.gitignore [deleted file]
techlibs/xilinx/Makefile.inc
techlibs/xilinx/brams_defs.vh [new file with mode: 0644]
techlibs/xilinx/brams_init.py [deleted file]
techlibs/xilinx/brams_xc2v.txt [new file with mode: 0644]
techlibs/xilinx/brams_xc2v_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xc3sda.txt [new file with mode: 0644]
techlibs/xilinx/brams_xc3sda_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xc4v.txt [new file with mode: 0644]
techlibs/xilinx/brams_xc4v_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xc5v_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xc6v_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xcu_map.v [new file with mode: 0644]
techlibs/xilinx/brams_xcv.txt [new file with mode: 0644]
techlibs/xilinx/brams_xcv_map.v [new file with mode: 0644]
techlibs/xilinx/lut4_lutrams.txt [deleted file]
techlibs/xilinx/lut6_lutrams.txt [deleted file]
techlibs/xilinx/lutrams_map.v [deleted file]
techlibs/xilinx/lutrams_xc5v.txt [new file with mode: 0644]
techlibs/xilinx/lutrams_xc5v_map.v [new file with mode: 0644]
techlibs/xilinx/lutrams_xcu.txt [new file with mode: 0644]
techlibs/xilinx/lutrams_xcv.txt [new file with mode: 0644]
techlibs/xilinx/lutrams_xcv_map.v [new file with mode: 0644]
techlibs/xilinx/synth_xilinx.cc
techlibs/xilinx/urams.txt [new file with mode: 0644]
techlibs/xilinx/urams_map.v [new file with mode: 0644]
techlibs/xilinx/xc2v_brams.txt [deleted file]
techlibs/xilinx/xc2v_brams_map.v [deleted file]
techlibs/xilinx/xc3sa_brams.txt [deleted file]
techlibs/xilinx/xc3sda_brams.txt [deleted file]
techlibs/xilinx/xc6s_brams.txt [deleted file]
techlibs/xilinx/xc6s_brams_map.v [deleted file]
techlibs/xilinx/xc7_brams_map.v [deleted file]
techlibs/xilinx/xc7_xcu_brams.txt [deleted file]
techlibs/xilinx/xcu_brams_map.v [deleted file]
techlibs/xilinx/xcup_urams.txt [deleted file]
techlibs/xilinx/xcup_urams_map.v [deleted file]
tests/arch/ecp5/memories.ys
tests/arch/efinix/lutram.ys
tests/arch/ice40/memories.ys
tests/arch/nexus/blockram.ys
tests/arch/xilinx/attributes_test.ys
tests/arch/xilinx/blockram.ys
tests/arch/xilinx/lutram.ys
tests/memlib/.gitignore [new file with mode: 0644]
tests/memlib/generate.py [new file with mode: 0644]
tests/memlib/memlib_block_sdp.txt [new file with mode: 0644]
tests/memlib/memlib_block_sdp.v [new file with mode: 0644]
tests/memlib/memlib_block_sdp_1clk.txt [new file with mode: 0644]
tests/memlib/memlib_block_sdp_1clk.v [new file with mode: 0644]
tests/memlib/memlib_block_sp.txt [new file with mode: 0644]
tests/memlib/memlib_block_sp.v [new file with mode: 0644]
tests/memlib/memlib_block_tdp.txt [new file with mode: 0644]
tests/memlib/memlib_block_tdp.v [new file with mode: 0644]
tests/memlib/memlib_lut.txt [new file with mode: 0644]
tests/memlib/memlib_lut.v [new file with mode: 0644]
tests/memlib/memlib_wide_read.txt [new file with mode: 0644]
tests/memlib/memlib_wide_read.v [new file with mode: 0644]
tests/memlib/memlib_wide_sdp.txt [new file with mode: 0644]
tests/memlib/memlib_wide_sdp.v [new file with mode: 0644]
tests/memlib/memlib_wide_sp.txt [new file with mode: 0644]
tests/memlib/memlib_wide_sp.v [new file with mode: 0644]
tests/memlib/memlib_wide_write.txt [new file with mode: 0644]
tests/memlib/memlib_wide_write.v [new file with mode: 0644]
tests/memlib/run-test.sh [new file with mode: 0755]
tests/opt/memory_bmux2rom.ys [new file with mode: 0644]
tests/proc/proc_rom.ys [new file with mode: 0644]
tests/sva/.gitignore
tests/sva/Makefile
tests/sva/nested_clk_else.sv [new file with mode: 0644]
tests/sva/runtest.sh
tests/sva/sva_value_change_changed.sv [new file with mode: 0644]
tests/sva/sva_value_change_changed_wide.sv [new file with mode: 0644]
tests/sva/sva_value_change_rose.sv [new file with mode: 0644]
tests/sva/sva_value_change_sim.sv [new file with mode: 0644]
tests/sva/sva_value_change_sim.ys [new file with mode: 0644]

index c3e4312aa8d5e6d1b310def162ca530dcbe4b844..4004c534b8e1e75e330f17ee3d87f704a5fab854 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,9 @@
 List of major changes and improvements between releases
 =======================================================
 
+Yosys 0.17 .. Yosys 0.17-dev
+--------------------------
+
 Yosys 0.16 .. Yosys 0.17
 --------------------------
  * New commands and options
index 17d5d7e8083961d1ca7a29b845b81f3d08ce0a96..34aeb9dc4aa4a04ec32c2338772fc4c21ea276a9 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -129,12 +129,12 @@ LDFLAGS += -rdynamic
 LDLIBS += -lrt
 endif
 
-YOSYS_VER := 0.17
-GIT_REV := $(shell git -C $(YOSYS_SRC) rev-parse --short HEAD 2> /dev/null || echo UNKNOWN)
+YOSYS_VER := 0.17+41
+GIT_REV := $(shell git ls-remote $(YOSYS_SRC) HEAD -q | $(AWK) 'BEGIN {R = "UNKNOWN"}; ($$2 == "HEAD") {R = substr($$1, 1, 9); exit} END {print R}')
 OBJS = kernel/version_$(GIT_REV).o
 
 bumpversion:
-#      sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline b63e0a0.. | wc -l`/;" Makefile
+       sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 6f9602b.. | wc -l`/;" Makefile
 
 # set 'ABCREV = default' to use abc/ as it is
 #
@@ -808,6 +808,7 @@ test: $(TARGETS) $(EXTRA_TARGETS)
        +cd tests/fsm && bash run-test.sh $(SEEDOPT)
        +cd tests/techmap && bash run-test.sh
        +cd tests/memories && bash run-test.sh $(ABCOPT) $(SEEDOPT)
+       +cd tests/memlib && bash run-test.sh $(SEEDOPT)
        +cd tests/bram && bash run-test.sh $(SEEDOPT)
        +cd tests/various && bash run-test.sh
        +cd tests/select && bash run-test.sh
index ed7e1795166d35b725f0aa8f5f3bd6f0dc28ddee..4865db27761f8291c4bf375787cbedcf2502cb19 100644 (file)
@@ -671,6 +671,27 @@ struct Smt2Worker
                                        return export_bvop(cell, "(bvurem A B)", 'd');
                                }
                        }
+                       // "div" = flooring division
+                       if (cell->type == ID($divfloor)) {
+                               if (cell->getParam(ID::A_SIGNED).as_bool()) {
+                                       // bvsdiv is truncating division, so we can't use it here.
+                                       int width = max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B)));
+                                       width = max(width, GetSize(cell->getPort(ID::Y)));
+                                       auto expr = stringf("(let ("
+                                                           "(a_neg (bvslt A #b%0*d)) "
+                                                           "(b_neg (bvslt B #b%0*d))) "
+                                                           "(let ((abs_a (ite a_neg (bvneg A) A)) "
+                                                           "(abs_b (ite b_neg (bvneg B) B))) "
+                                                           "(let ((u (bvudiv abs_a abs_b)) "
+                                                           "(adj (ite (= #b%0*d (bvurem abs_a abs_b)) #b%0*d #b%0*d))) "
+                                                           "(ite (= a_neg b_neg) u "
+                                                           "(bvneg (bvadd u adj))))))",
+                                                           width, 0, width, 0, width, 0, width, 0, width, 1);
+                                       return export_bvop(cell, expr, 'd');
+                               } else {
+                                       return export_bvop(cell, "(bvudiv A B)", 'd');
+                               }
+                       }
 
                        if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool)) &&
                                        2*GetSize(cell->getPort(ID::A).chunks()) < GetSize(cell->getPort(ID::A))) {
index d19d837ffcca33316b8271ffb1d664c32ad06f36..328593099376b1004e3980503b020c0c53f5e594 100644 (file)
@@ -1527,23 +1527,45 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
 
                        log_assert(inst->Input1Size() == inst->OutputSize());
 
-                       SigSpec sig_d, sig_q, sig_o;
-                       sig_q = module->addWire(new_verific_id(inst), inst->Input1Size());
+                       unsigned width = inst->Input1Size();
 
-                       for (int i = int(inst->Input1Size())-1; i >= 0; i--){
+                       SigSpec sig_d, sig_dx, sig_qx, sig_o, sig_ox;
+                       sig_dx = module->addWire(new_verific_id(inst), width * 2);
+                       sig_qx = module->addWire(new_verific_id(inst), width * 2);
+                       sig_ox = module->addWire(new_verific_id(inst), width * 2);
+
+                       for (int i = int(width)-1; i >= 0; i--){
                                sig_d.append(net_map_at(inst->GetInput1Bit(i)));
                                sig_o.append(net_map_at(inst->GetOutputBit(i)));
                        }
 
                        if (verific_verbose) {
+                               for (unsigned i = 0; i < width; i++) {
+                                       log("    NEX with A=%s, B=0, Y=%s.\n",
+                                                       log_signal(sig_d[i]), log_signal(sig_dx[i]));
+                                       log("    EQX with A=%s, B=1, Y=%s.\n",
+                                                       log_signal(sig_d[i]), log_signal(sig_dx[i + width]));
+                               }
                                log("    %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
-                                               log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+                                               log_signal(sig_dx), log_signal(sig_qx), log_signal(clocking.clock_sig));
                                log("    XNOR with A=%s, B=%s, Y=%s.\n",
-                                               log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
+                                               log_signal(sig_dx), log_signal(sig_qx), log_signal(sig_ox));
+                               log("    AND with A=%s, B=%s, Y=%s.\n",
+                                               log_signal(sig_ox.extract(0, width)), log_signal(sig_ox.extract(width, width)), log_signal(sig_o));
+                       }
+
+                       for (unsigned i = 0; i < width; i++) {
+                               module->addNex(new_verific_id(inst), sig_d[i], State::S0, sig_dx[i]);
+                               module->addEqx(new_verific_id(inst), sig_d[i], State::S1, sig_dx[i + width]);
                        }
 
-                       clocking.addDff(new_verific_id(inst), sig_d, sig_q);
-                       module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
+                       Const qx_init = Const(State::S1, width);
+                       qx_init.bits.resize(2 * width, State::S0);
+
+                       clocking.addDff(new_verific_id(inst), sig_dx, sig_qx, qx_init);
+                       module->addXnor(new_verific_id(inst), sig_dx, sig_qx, sig_ox);
+
+                       module->addAnd(new_verific_id(inst), sig_ox.extract(0, width), sig_ox.extract(width, width), sig_o);
 
                        if (!mode_keep)
                                continue;
@@ -1557,17 +1579,25 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
 
                        SigSpec sig_d = net_map_at(inst->GetInput1());
                        SigSpec sig_o = net_map_at(inst->GetOutput());
-                       SigSpec sig_q = module->addWire(new_verific_id(inst));
+                       SigSpec sig_dx = module->addWire(new_verific_id(inst), 2);
+                       SigSpec sig_qx = module->addWire(new_verific_id(inst), 2);
 
                        if (verific_verbose) {
+                               log("    NEX with A=%s, B=0, Y=%s.\n",
+                                               log_signal(sig_d), log_signal(sig_dx[0]));
+                               log("    EQX with A=%s, B=1, Y=%s.\n",
+                                               log_signal(sig_d), log_signal(sig_dx[1]));
                                log("    %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
-                                               log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
-                               log("    XNOR with A=%s, B=%s, Y=%s.\n",
-                                               log_signal(sig_d), log_signal(sig_q), log_signal(sig_o));
+                                               log_signal(sig_dx), log_signal(sig_qx), log_signal(clocking.clock_sig));
+                               log("    EQ with A=%s, B=%s, Y=%s.\n",
+                                               log_signal(sig_dx), log_signal(sig_qx), log_signal(sig_o));
                        }
 
-                       clocking.addDff(new_verific_id(inst), sig_d, sig_q);
-                       module->addXnor(new_verific_id(inst), sig_d, sig_q, sig_o);
+                       module->addNex(new_verific_id(inst), sig_d, State::S0, sig_dx[0]);
+                       module->addEqx(new_verific_id(inst), sig_d, State::S1, sig_dx[1]);
+
+                       clocking.addDff(new_verific_id(inst), sig_dx, sig_qx, Const(1, 2));
+                       module->addEq(new_verific_id(inst), sig_dx, sig_qx, sig_o);
 
                        if (!mode_keep)
                                continue;
@@ -1601,13 +1631,20 @@ void VerificImporter::import_netlist(RTLIL::Design *design, Netlist *nl, std::ma
                        SigBit sig_d = net_map_at(inst->GetInput1());
                        SigBit sig_o = net_map_at(inst->GetOutput());
                        SigBit sig_q = module->addWire(new_verific_id(inst));
+                       SigBit sig_d_no_x = module->addWire(new_verific_id(inst));
 
-                       if (verific_verbose)
+                       if (verific_verbose) {
+                               log("    EQX with A=%s, B=%d, Y=%s.\n",
+                                               log_signal(sig_d), inst->Type() == PRIM_SVA_ROSE, log_signal(sig_d_no_x));
                                log("    %sedge FF with D=%s, Q=%s, C=%s.\n", clocking.posedge ? "pos" : "neg",
-                                               log_signal(sig_d), log_signal(sig_q), log_signal(clocking.clock_sig));
+                                               log_signal(sig_d_no_x), log_signal(sig_q), log_signal(clocking.clock_sig));
+                               log("    EQ with A={%s, %s}, B={0, 1}, Y=%s.\n",
+                                               log_signal(sig_q), log_signal(sig_d_no_x), log_signal(sig_o));
+                       }
 
-                       clocking.addDff(new_verific_id(inst), sig_d, sig_q);
-                       module->addEq(new_verific_id(inst), {sig_q, sig_d}, Const(inst->Type() == PRIM_SVA_ROSE ? 1 : 2, 2), sig_o);
+                       module->addEqx(new_verific_id(inst), sig_d, inst->Type() == PRIM_SVA_ROSE ? State::S1 : State::S0, sig_d_no_x);
+                       clocking.addDff(new_verific_id(inst), sig_d_no_x, sig_q, State::S0);
+                       module->addEq(new_verific_id(inst), {sig_q, sig_d_no_x}, Const(1, 2), sig_o);
 
                        if (!mode_keep)
                                continue;
@@ -1873,15 +1910,19 @@ VerificClocking::VerificClocking(VerificImporter *importer, Net *net, bool sva_a
                if (inst_mux == nullptr || inst_mux->Type() != PRIM_MUX)
                        break;
 
-               if (!inst_mux->GetInput1()->IsPwr())
+               bool pwr1 = inst_mux->GetInput1()->IsPwr();
+               bool pwr2 = inst_mux->GetInput2()->IsPwr();
+
+               if (!pwr1 && !pwr2)
                        break;
 
-               Net *sva_net = inst_mux->GetInput2();
+               Net *sva_net = pwr1 ? inst_mux->GetInput2() : inst_mux->GetInput1();
                if (!verific_is_sva_net(importer, sva_net))
                        break;
 
                body_net = sva_net;
                cond_net = inst_mux->GetControl();
+               cond_pol = pwr1;
        } while (0);
 
        clock_net = net;
@@ -2305,31 +2346,36 @@ struct VerificPass : public Pass {
                log("\n");
                log("\n");
 #endif
-               log("    verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|-sv2012|-sv|-formal] <command-file>\n");
+               log("    verific {-f|-F} [-vlog95|-vlog2k|-sv2005|-sv2009|\n");
+               log("                     -sv2012|-sv|-formal] <command-file>\n");
                log("\n");
                log("Load and execute the specified command file.\n");
                log("Override verilog parsing mode can be set.\n");
                log("The macros YOSYS, SYNTHESIS/FORMAL, and VERIFIC are defined implicitly.\n");
                log("\n");
-               log("Command file parser supports following commands:\n");
-               log("    +define    - defines macro\n");
-               log("    -u         - upper case all identifier (makes Verilog parser case insensitive)\n");
-               log("    -v         - register library name (file)\n");
-               log("    -y         - register library name (directory)\n");
-               log("    +incdir    - specify include dir\n");
-               log("    +libext    - specify library extension\n");
-               log("    +liborder  - add library in ordered list\n");
-               log("    +librescan - unresolved modules will be always searched starting with the first\n");
-               log("                 library specified by -y/-v options.\n");
-               log("    -f/-file   - nested -f option\n");
-               log("    -F         - nested -F option\n");
-               log("\n");
-               log("    parse mode:\n");
+               log("Command file parser supports following commands in file:\n");
+               log("    +define+<MACRO>=<VALUE> - defines macro\n");
+               log("    -u                      - upper case all identifier (makes Verilog parser\n");
+               log("                              case insensitive)\n");
+               log("    -v <filepath>           - register library name (file)\n");
+               log("    -y <filepath>           - register library name (directory)\n");
+               log("    +incdir+<filepath>      - specify include dir\n");
+               log("    +libext+<filepath>      - specify library extension\n");
+               log("    +liborder+<id>          - add library in ordered list\n");
+               log("    +librescan              - unresolved modules will be always searched\n");
+               log("                              starting with the first library specified\n");
+               log("                              by -y/-v options.\n");
+               log("    -f/-file <filepath>     - nested -f option\n");
+               log("    -F <filepath>           - nested -F option (relative path)\n");
+               log("    parse files:\n");
+               log("        <filepath>\n");
+               log("        +systemverilogext+<filepath>\n");
+               log("        +verilog1995ext+<filepath>\n");
+               log("        +verilog2001ext+<filepath>\n");
+               log("\n");
+               log("    analysis mode:\n");
                log("        -ams\n");
-               log("        +systemverilogext\n");
                log("        +v2k\n");
-               log("        +verilog1995ext\n");
-               log("        +verilog2001ext\n");
                log("        -sverilog\n");
                log("\n");
                log("\n");
@@ -2466,8 +2512,8 @@ struct VerificPass : public Pass {
                log("        Parameter can also contain comma separated list of file locations.\n");
                log("\n");
                log("    -blfile <file>\n");
-               log("        Do not run application on locations specified in file, they can represent filename\n");
-               log("        or filename and location in file.\n");
+               log("        Do not run application on locations specified in file, they can\n");
+               log("        represent filename or filename and location in file.\n");
                log("\n");
                log("Applications:\n");
                log("\n");
@@ -2676,7 +2722,7 @@ struct VerificPass : public Pass {
 
                if (GetSize(args) > argidx && (args[argidx] == "-f" || args[argidx] == "-F"))
                {
-                       unsigned verilog_mode = veri_file::VERILOG_95; // default recommended by Verific
+                       unsigned verilog_mode = veri_file::UNDEFINED;
                        bool is_formal = false;
                        const char* filename = nullptr;
 
@@ -2723,7 +2769,7 @@ struct VerificPass : public Pass {
                        veri_file::DefineMacro("VERIFIC");
                        veri_file::DefineMacro(is_formal ? "FORMAL" : "SYNTHESIS");
 
-                       if (!veri_file::AnalyzeMultipleFiles(file_names, verilog_mode, work.c_str(), veri_file::MFCU)) {
+                       if (!veri_file::AnalyzeMultipleFiles(file_names, analysis_mode, work.c_str(), veri_file::MFCU)) {
                                verific_error_msg.clear();
                                log_cmd_error("Reading Verilog/SystemVerilog sources failed.\n");
                        }
index 416b26396c84952ec0f8f7ec382bb409c609d121..695c04f3bcba3ae5451008ef8d7c196f91ff73fe 100644 (file)
@@ -44,6 +44,7 @@ struct VerificClocking {
        SigBit disable_sig = State::S0;
        bool posedge = true;
        bool gclk = false;
+       bool cond_pol = true;
 
        VerificClocking() { }
        VerificClocking(VerificImporter *importer, Verific::Net *net, bool sva_at_only = false);
index 1bbdcf0167f061005b674b02735e0886e8064c92..12bac2a3d058b7b586b25fe7577842051a98a09a 100644 (file)
@@ -1522,10 +1522,13 @@ struct VerificSvaImporter
                if (inst == nullptr)
                        return false;
 
-               if (clocking.cond_net != nullptr)
+               if (clocking.cond_net != nullptr) {
                        trig = importer->net_map_at(clocking.cond_net);
-               else
+                       if (!clocking.cond_pol)
+                               trig = module->Not(NEW_ID, trig);
+               } else {
                        trig = State::S1;
+               }
 
                if (inst->Type() == PRIM_SVA_S_EVENTUALLY || inst->Type() == PRIM_SVA_EVENTUALLY)
                {
@@ -1587,8 +1590,11 @@ struct VerificSvaImporter
 
                SigBit trig = State::S1;
 
-               if (clocking.cond_net != nullptr)
+               if (clocking.cond_net != nullptr) {
                        trig = importer->net_map_at(clocking.cond_net);
+                       if (!clocking.cond_pol)
+                               trig = module->Not(NEW_ID, trig);
+               }
 
                if (inst == nullptr)
                {
index d6202663d0e8a1f58b99dd141f3e41505e37e4e3..bab2bc6a95296992372ce64db85bee36a9ec79e4 100644 (file)
@@ -29,10 +29,12 @@ X(A_SIGNED)
 X(A_WIDTH)
 X(B)
 X(BI)
+X(BITS_USED)
 X(blackbox)
 X(B_SIGNED)
 X(bugpoint_keep)
 X(B_WIDTH)
+X(BYTE)
 X(C)
 X(cells_not_processed)
 X(CE_OVER_SRST)
@@ -117,6 +119,8 @@ X(keep_hierarchy)
 X(L)
 X(lib_whitebox)
 X(localparam)
+X(logic_block)
+X(lram)
 X(LUT)
 X(lut_keep)
 X(M)
@@ -146,6 +150,9 @@ X(PRIORITY_MASK)
 X(Q)
 X(qwp_position)
 X(R)
+X(ram_block)
+X(ram_style)
+X(ramstyle)
 X(RD_ADDR)
 X(RD_ARST)
 X(RD_ARST_VALUE)
@@ -165,6 +172,9 @@ X(RD_TRANSPARENT)
 X(RD_WIDE_CONTINUATION)
 X(reg)
 X(reprocess_after)
+X(rom_block)
+X(rom_style)
+X(romstyle)
 X(S)
 X(SET)
 X(SET_POLARITY)
@@ -187,6 +197,8 @@ X(STATE_NUM_LOG2)
 X(STATE_RST)
 X(STATE_TABLE)
 X(submod)
+X(syn_ramstyle)
+X(syn_romstyle)
 X(S_WIDTH)
 X(T)
 X(TABLE)
index c43482bd242e2c127114f68627a9f9292901600a..b0f1a924f406561de39e881bdad48421ec0e37e7 100644 (file)
@@ -669,14 +669,12 @@ namespace {
        }
 }
 
-void FfData::flip_bits(const pool<int> &bits) {
+void FfData::flip_rst_bits(const pool<int> &bits) {
        if (!bits.size())
                return;
 
        remove_init();
 
-       Wire *new_q = module->addWire(NEW_ID, width);
-
        for (auto bit: bits) {
                if (has_arst)
                        val_arst[bit] = invert(val_arst[bit]);
@@ -684,6 +682,15 @@ void FfData::flip_bits(const pool<int> &bits) {
                        val_srst[bit] = invert(val_srst[bit]);
                val_init[bit] = invert(val_init[bit]);
        }
+}
+
+void FfData::flip_bits(const pool<int> &bits) {
+       if (!bits.size())
+               return;
+
+       flip_rst_bits(bits);
+
+       Wire *new_q = module->addWire(NEW_ID, width);
 
        if (has_sr && cell) {
                log_warning("Flipping D/Q/init and inserting priority fixup to legalize %s.%s [%s].\n", log_id(module->name), log_id(cell->name), log_id(cell->type));
index 5a629d5dd6c18d7aaebf2ada572f87ad81d15514..41721b4a117a1d6b79c646679697eca538c1f8a8 100644 (file)
@@ -209,6 +209,8 @@ struct FfData {
        // inputs and output, flip the corresponding init/reset bits, swap clr/set
        // inputs with proper priority fix.
        void flip_bits(const pool<int> &bits);
+
+       void flip_rst_bits(const pool<int> &bits);
 };
 
 YOSYS_NAMESPACE_END
index ae87b1285f79b555003232bdd01bb0960b831694..8c484274ccff86df09f413a7a3ef5cd663b8f9fe 100644 (file)
@@ -46,7 +46,7 @@ struct MemRd : RTLIL::AttrObject {
        std::vector<bool> collision_x_mask;
        SigSpec clk, en, arst, srst, addr, data;
 
-       MemRd() : removed(false), cell(nullptr) {}
+       MemRd() : removed(false), cell(nullptr), wide_log2(0), clk_enable(false), clk_polarity(true), ce_over_srst(false), clk(State::Sx), en(State::S1), arst(State::S0), srst(State::S0) {}
 
        // Returns the address of given subword index accessed by this port.
        SigSpec sub_addr(int sub) {
index 09909696be1df467585471e1fd021565220088ab..4e1a3ca7e2d883175e8d778629f297352c2d7d63 100644 (file)
@@ -733,6 +733,8 @@ extern Tcl_Interp *yosys_get_tcl_interp()
 {
        if (yosys_tcl_interp == NULL) {
                yosys_tcl_interp = Tcl_CreateInterp();
+               if (Tcl_Init(yosys_tcl_interp)!=TCL_OK)
+                       log_warning("Tcl_Init() call failed - %s\n",Tcl_ErrnoMsg(Tcl_GetErrno()));
                Tcl_CreateCommand(yosys_tcl_interp, "yosys", tcl_yosys_cmd, NULL, NULL);
        }
        return yosys_tcl_interp;
index bb7b78cfed5cce6b36f8e618b00d24b8415dc17f..d609c8d0fef3accf7a6cc4814bdd50cc4341258f 100644 (file)
@@ -944,12 +944,14 @@ static void select_stmt(RTLIL::Design *design, std::string arg, bool disable_emp
        }
 }
 
-static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel)
+static std::string describe_selection_for_assert(RTLIL::Design *design, RTLIL::Selection *sel, bool whole_modules = false)
 {
        std::string desc = "Selection contains:\n";
        for (auto mod : design->modules())
        {
                if (sel->selected_module(mod->name)) {
+                       if (whole_modules && sel->selected_whole_module(mod->name))
+                                       desc += stringf("%s\n", id2cstr(mod->name));
                        for (auto wire : mod->wires())
                                if (sel->selected_member(mod->name, wire->name))
                                        desc += stringf("%s/%s\n", id2cstr(mod->name), id2cstr(wire->name));
@@ -1051,17 +1053,17 @@ struct SelectPass : public Pass {
                log("\n");
                log("    -unset <name>\n");
                log("        do not modify the current selection. instead remove a previously saved\n");
-               log("        selection under the given name (see @<name> below).");
+               log("        selection under the given name (see @<name> below).\n");
                log("\n");
                log("    -assert-none\n");
                log("        do not modify the current selection. instead assert that the given\n");
-               log("        selection is empty. i.e. produce an error if any object matching the\n");
-               log("        selection is found.\n");
+               log("        selection is empty. i.e. produce an error if any object or module\n");
+               log("        matching the selection is found.\n");
                log("\n");
                log("    -assert-any\n");
                log("        do not modify the current selection. instead assert that the given\n");
-               log("        selection is non-empty. i.e. produce an error if no object matching\n");
-               log("        the selection is found.\n");
+               log("        selection is non-empty. i.e. produce an error if no object or module\n");
+               log("        matching the selection is found.\n");
                log("\n");
                log("    -assert-count N\n");
                log("        do not modify the current selection. instead assert that the given\n");
@@ -1488,7 +1490,7 @@ struct SelectPass : public Pass {
                        {
                                RTLIL::Selection *sel = &work_stack.back();
                                sel->optimize(design);
-                               std::string desc = describe_selection_for_assert(design, sel);
+                               std::string desc = describe_selection_for_assert(design, sel, true);
                                log_error("Assertion failed: selection is not empty:%s\n%s", sel_str.c_str(), desc.c_str());
                        }
                        return;
@@ -1503,7 +1505,7 @@ struct SelectPass : public Pass {
                        {
                                RTLIL::Selection *sel = &work_stack.back();
                                sel->optimize(design);
-                               std::string desc = describe_selection_for_assert(design, sel);
+                               std::string desc = describe_selection_for_assert(design, sel, true);
                                log_error("Assertion failed: selection is empty:%s\n%s", sel_str.c_str(), desc.c_str());
                        }
                        return;
index 5a2c4ecfc1ea9393f0df5cb2e84f29581d5ba9be..d9dca52df9122f3c9942ce692783fbcefaa252bf 100644 (file)
@@ -9,4 +9,7 @@ OBJS += passes/memory/memory_map.o
 OBJS += passes/memory/memory_memx.o
 OBJS += passes/memory/memory_nordff.o
 OBJS += passes/memory/memory_narrow.o
+OBJS += passes/memory/memory_libmap.o
+OBJS += passes/memory/memory_bmux2rom.o
 
+OBJS += passes/memory/memlib.o
diff --git a/passes/memory/memlib.cc b/passes/memory/memlib.cc
new file mode 100644 (file)
index 0000000..8a7adc9
--- /dev/null
@@ -0,0 +1,1101 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2021  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "memlib.h"
+
+#include <ctype.h>
+
+USING_YOSYS_NAMESPACE
+
+using namespace MemLibrary;
+
+PRIVATE_NAMESPACE_BEGIN
+
+typedef dict<std::string, Const> Options;
+
+struct ClockDef {
+       ClkPolKind kind;
+       std::string name;
+};
+
+struct RawWrTransDef {
+       WrTransTargetKind target_kind;
+       std::string target_group;
+       WrTransKind kind;
+};
+
+struct PortWidthDef {
+       bool tied;
+       std::vector<int> wr_widths;
+       std::vector<int> rd_widths;
+};
+
+struct SrstDef {
+       ResetValKind val;
+       SrstKind kind;
+       bool block_wr;
+};
+
+struct Empty {};
+
+template<typename T> struct Capability {
+       T val;
+       Options opts, portopts;
+
+       Capability(T val, Options opts, Options portopts) : val(val), opts(opts), portopts(portopts) {}
+};
+
+template<typename T> using Caps = std::vector<Capability<T>>;
+
+struct PortGroupDef {
+       PortKind kind;
+       dict<std::string, pool<Const>> portopts;
+       std::vector<std::string> names;
+       Caps<Empty> forbid;
+       Caps<ClockDef> clock;
+       Caps<Empty> clken;
+       Caps<Empty> wrbe_separate;
+       Caps<PortWidthDef> width;
+       Caps<Empty> rden;
+       Caps<RdWrKind> rdwr;
+       Caps<ResetValKind> rdinit;
+       Caps<ResetValKind> rdarst;
+       Caps<SrstDef> rdsrst;
+       Caps<std::string> wrprio;
+       Caps<RawWrTransDef> wrtrans;
+       Caps<Empty> optional;
+       Caps<Empty> optional_rw;
+};
+
+struct WidthsDef {
+       std::vector<int> widths;
+       WidthMode mode;
+};
+
+struct ResourceDef {
+       std::string name;
+       int count;
+};
+
+struct RamDef {
+       IdString id;
+       dict<std::string, pool<Const>> opts;
+       RamKind kind;
+       Caps<Empty> forbid;
+       Caps<Empty> prune_rom;
+       Caps<PortGroupDef> ports;
+       Caps<int> abits;
+       Caps<WidthsDef> widths;
+       Caps<ResourceDef> resource;
+       Caps<double> cost;
+       Caps<double> widthscale;
+       Caps<int> byte;
+       Caps<MemoryInitKind> init;
+       Caps<std::string> style;
+};
+
+struct Parser {
+       std::string filename;
+       std::ifstream infile;
+       int line_number = 0;
+       Library &lib;
+       const pool<std::string> &defines;
+       pool<std::string> &defines_unused;
+       std::vector<std::string> tokens;
+       int token_idx = 0;
+       bool eof = false;
+
+       std::vector<std::pair<std::string, Const>> option_stack;
+       std::vector<std::pair<std::string, Const>> portoption_stack;
+       RamDef ram;
+       PortGroupDef port;
+       bool active = true;
+
+       Parser(std::string filename, Library &lib, const pool<std::string> &defines, pool<std::string> &defines_unused) : filename(filename), lib(lib), defines(defines), defines_unused(defines_unused) {
+               // Note: this rewrites the filename we're opening, but not
+               // the one we're storing â€” this is actually correct, so that
+               // we keep the original filename for diagnostics.
+               rewrite_filename(filename);
+               infile.open(filename);
+               if (infile.fail()) {
+                       log_error("failed to open %s\n", filename.c_str());
+               }
+               parse();
+               infile.close();
+       }
+
+       std::string peek_token() {
+               if (eof)
+                       return "";
+
+               if (token_idx < GetSize(tokens))
+                       return tokens[token_idx];
+
+               tokens.clear();
+               token_idx = 0;
+
+               std::string line;
+               while (std::getline(infile, line)) {
+                       line_number++;
+                       for (string tok = next_token(line); !tok.empty(); tok = next_token(line)) {
+                               if (tok[0] == '#')
+                                       break;
+                               if (tok[tok.size()-1] == ';') {
+                                       tokens.push_back(tok.substr(0, tok.size()-1));
+                                       tokens.push_back(";");
+                               } else {
+                                       tokens.push_back(tok);
+                               }
+                       }
+                       if (!tokens.empty())
+                               return tokens[token_idx];
+               }
+
+               eof = true;
+               return "";
+       }
+
+       std::string get_token() {
+               std::string res = peek_token();
+               if (!eof)
+                       token_idx++;
+               return res;
+       }
+
+       void eat_token(std::string expected) {
+               std::string token = get_token();
+               if (token != expected) {
+                       log_error("%s:%d: expected `%s`, got `%s`.\n", filename.c_str(), line_number, expected.c_str(), token.c_str());
+               }
+       }
+
+       IdString get_id() {
+               std::string token = get_token();
+               if (token.empty() || (token[0] != '$' && token[0] != '\\')) {
+                       log_error("%s:%d: expected id string, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+               return IdString(token);
+       }
+
+       std::string get_name() {
+               std::string res = get_token();
+               bool valid = true;
+               // Basic sanity check.
+               if (res.empty() || (!isalpha(res[0]) && res[0] != '_'))
+                       valid = false;
+               for (char c: res)
+                       if (!isalnum(c) && c != '_')
+                               valid = false;
+               if (!valid)
+                       log_error("%s:%d: expected name, got `%s`.\n", filename.c_str(), line_number, res.c_str());
+               return res;
+       }
+
+       std::string get_string() {
+               std::string token = get_token();
+               if (token.size() < 2 || token[0] != '"' || token[token.size()-1] != '"') {
+                       log_error("%s:%d: expected string, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+               return token.substr(1, token.size()-2);
+       }
+
+       bool peek_string() {
+               std::string token = peek_token();
+               return !token.empty() && token[0] == '"';
+       }
+
+       int get_int() {
+               std::string token = get_token();
+               char *endptr;
+               long res = strtol(token.c_str(), &endptr, 0);
+               if (token.empty() || *endptr || res > INT_MAX) {
+                       log_error("%s:%d: expected int, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+               return res;
+       }
+
+       double get_double() {
+               std::string token = get_token();
+               char *endptr;
+               double res = strtod(token.c_str(), &endptr);
+               if (token.empty() || *endptr) {
+                       log_error("%s:%d: expected float, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+               return res;
+       }
+
+       bool peek_int() {
+               std::string token = peek_token();
+               return !token.empty() && isdigit(token[0]);
+       }
+
+       void get_semi() {
+               std::string token = get_token();
+               if (token != ";") {
+                       log_error("%s:%d: expected `;`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+       }
+
+       Const get_value() {
+               std::string token = peek_token();
+               if (!token.empty() && token[0] == '"') {
+                       std::string s = get_string();
+                       return Const(s);
+               } else {
+                       return Const(get_int());
+               }
+       }
+
+       bool enter_ifdef(bool polarity) {
+               bool res = active;
+               std::string name = get_name();
+               defines_unused.erase(name);
+               if (active) {
+                       if (defines.count(name)) {
+                               active = polarity;
+                       } else {
+                               active = !polarity;
+                       }
+               }
+               return res;
+       }
+
+       void enter_else(bool save) {
+               get_token();
+               active = !active && save;
+       }
+
+       void enter_option() {
+               std::string name = get_string();
+               Const val = get_value();
+               if (active) {
+                       ram.opts[name].insert(val);
+               }
+               option_stack.push_back({name, val});
+       }
+
+       void exit_option() {
+               option_stack.pop_back();
+       }
+
+       Options get_options() {
+               Options res;
+               for (auto it: option_stack)
+                       res[it.first] = it.second;
+               return res;
+       }
+
+       void enter_portoption() {
+               std::string name = get_string();
+               Const val = get_value();
+               if (active) {
+                       port.portopts[name].insert(val);
+               }
+               portoption_stack.push_back({name, val});
+       }
+
+       void exit_portoption() {
+               portoption_stack.pop_back();
+       }
+
+       Options get_portoptions() {
+               Options res;
+               for (auto it: portoption_stack)
+                       res[it.first] = it.second;
+               return res;
+       }
+
+       template<typename T> void add_cap(Caps<T> &caps, T val) {
+               if (active)
+                       caps.push_back(Capability<T>(val, get_options(), get_portoptions()));
+       }
+
+       void parse_port_block() {
+               if (peek_token() == "{") {
+                       get_token();
+                       while (peek_token() != "}")
+                               parse_port_item();
+                       get_token();
+               } else {
+                       parse_port_item();
+               }
+       }
+
+       void parse_ram_block() {
+               if (peek_token() == "{") {
+                       get_token();
+                       while (peek_token() != "}")
+                               parse_ram_item();
+                       get_token();
+               } else {
+                       parse_ram_item();
+               }
+       }
+
+       void parse_top_block() {
+               if (peek_token() == "{") {
+                       get_token();
+                       while (peek_token() != "}")
+                               parse_top_item();
+                       get_token();
+               } else {
+                       parse_top_item();
+               }
+       }
+
+       void parse_port_item() {
+               std::string token = get_token();
+               if (token == "ifdef") {
+                       bool save = enter_ifdef(true);
+                       parse_port_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_port_block();
+                       }
+                       active = save;
+               } else if (token == "ifndef") {
+                       bool save = enter_ifdef(false);
+                       parse_port_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_port_block();
+                       }
+                       active = save;
+               } else if (token == "option") {
+                       enter_option();
+                       parse_port_block();
+                       exit_option();
+               } else if (token == "portoption") {
+                       enter_portoption();
+                       parse_port_block();
+                       exit_portoption();
+               } else if (token == "clock") {
+                       if (port.kind == PortKind::Ar) {
+                               log_error("%s:%d: `clock` not allowed in async read port.\n", filename.c_str(), line_number);
+                       }
+                       ClockDef def;
+                       token = get_token();
+                       if (token == "anyedge") {
+                               def.kind = ClkPolKind::Anyedge;
+                       } else if (token == "posedge") {
+                               def.kind = ClkPolKind::Posedge;
+                       } else if (token == "negedge") {
+                               def.kind = ClkPolKind::Negedge;
+                       } else {
+                               log_error("%s:%d: expected `posedge`, `negedge`, or `anyedge`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       if (peek_string()) {
+                               def.name = get_string();
+                       }
+                       get_semi();
+                       add_cap(port.clock, def);
+               } else if (token == "clken") {
+                       if (port.kind == PortKind::Ar) {
+                               log_error("%s:%d: `clken` not allowed in async read port.\n", filename.c_str(), line_number);
+                       }
+                       get_semi();
+                       add_cap(port.clken, {});
+               } else if (token == "wrbe_separate") {
+                       if (port.kind == PortKind::Ar || port.kind == PortKind::Sr) {
+                               log_error("%s:%d: `wrbe_separate` not allowed in read port.\n", filename.c_str(), line_number);
+                       }
+                       get_semi();
+                       add_cap(port.wrbe_separate, {});
+               } else if (token == "width") {
+                       PortWidthDef def;
+                       token = peek_token();
+                       bool is_rw = port.kind == PortKind::Srsw || port.kind == PortKind::Arsw;
+                       if (token == "tied") {
+                               get_token();
+                               if (!is_rw)
+                                       log_error("%s:%d: `tied` only makes sense for read+write ports.\n", filename.c_str(), line_number);
+                               while (peek_int())
+                                       def.wr_widths.push_back(get_int());
+                               def.tied = true;
+                       } else if (token == "mix") {
+                               get_token();
+                               if (!is_rw)
+                                       log_error("%s:%d: `mix` only makes sense for read+write ports.\n", filename.c_str(), line_number);
+                               while (peek_int())
+                                       def.wr_widths.push_back(get_int());
+                               def.rd_widths = def.wr_widths;
+                               def.tied = false;
+                       } else if (token == "rd") {
+                               get_token();
+                               if (!is_rw)
+                                       log_error("%s:%d: `rd` only makes sense for read+write ports.\n", filename.c_str(), line_number);
+                               do {
+                                       def.rd_widths.push_back(get_int());
+                               } while (peek_int());
+                               eat_token("wr");
+                               do {
+                                       def.wr_widths.push_back(get_int());
+                               } while (peek_int());
+                               def.tied = false;
+                       } else if (token == "wr") {
+                               get_token();
+                               if (!is_rw)
+                                       log_error("%s:%d: `wr` only makes sense for read+write ports.\n", filename.c_str(), line_number);
+                               do {
+                                       def.wr_widths.push_back(get_int());
+                               } while (peek_int());
+                               eat_token("rd");
+                               do {
+                                       def.rd_widths.push_back(get_int());
+                               } while (peek_int());
+                               def.tied = false;
+                       } else {
+                               do {
+                                       def.wr_widths.push_back(get_int());
+                               } while (peek_int());
+                               def.tied = true;
+                       }
+                       get_semi();
+                       add_cap(port.width, def);
+               } else if (token == "rden") {
+                       if (port.kind != PortKind::Sr && port.kind != PortKind::Srsw)
+                               log_error("%s:%d: `rden` only allowed on sync read ports.\n", filename.c_str(), line_number);
+                       get_semi();
+                       add_cap(port.rden, {});
+               } else if (token == "rdwr") {
+                       if (port.kind != PortKind::Srsw)
+                               log_error("%s:%d: `rdwr` only allowed on sync read+write ports.\n", filename.c_str(), line_number);
+                       RdWrKind kind;
+                       token = get_token();
+                       if (token == "undefined") {
+                               kind = RdWrKind::Undefined;
+                       } else if (token == "no_change") {
+                               kind = RdWrKind::NoChange;
+                       } else if (token == "new") {
+                               kind = RdWrKind::New;
+                       } else if (token == "old") {
+                               kind = RdWrKind::Old;
+                       } else if (token == "new_only") {
+                               kind = RdWrKind::NewOnly;
+                       } else {
+                               log_error("%s:%d: expected `undefined`, `new`, `old`, `new_only`, or `no_change`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(port.rdwr, kind);
+               } else if (token == "rdinit") {
+                       if (port.kind != PortKind::Sr && port.kind != PortKind::Srsw)
+                               log_error("%s:%d: `%s` only allowed on sync read ports.\n", filename.c_str(), line_number, token.c_str());
+                       ResetValKind kind;
+                       token = get_token();
+                       if (token == "none") {
+                               kind = ResetValKind::None;
+                       } else if (token == "zero") {
+                               kind = ResetValKind::Zero;
+                       } else if (token == "any") {
+                               kind = ResetValKind::Any;
+                       } else if (token == "no_undef") {
+                               kind = ResetValKind::NoUndef;
+                       } else {
+                               log_error("%s:%d: expected `none`, `zero`, `any`, or `no_undef`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(port.rdinit, kind);
+               } else if (token == "rdarst") {
+                       if (port.kind != PortKind::Sr && port.kind != PortKind::Srsw)
+                               log_error("%s:%d: `%s` only allowed on sync read ports.\n", filename.c_str(), line_number, token.c_str());
+                       ResetValKind kind;
+                       token = get_token();
+                       if (token == "none") {
+                               kind = ResetValKind::None;
+                       } else if (token == "zero") {
+                               kind = ResetValKind::Zero;
+                       } else if (token == "any") {
+                               kind = ResetValKind::Any;
+                       } else if (token == "no_undef") {
+                               kind = ResetValKind::NoUndef;
+                       } else if (token == "init") {
+                               kind = ResetValKind::Init;
+                       } else {
+                               log_error("%s:%d: expected `none`, `zero`, `any`, `no_undef`, or `init`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(port.rdarst, kind);
+               } else if (token == "rdsrst") {
+                       if (port.kind != PortKind::Sr && port.kind != PortKind::Srsw)
+                               log_error("%s:%d: `%s` only allowed on sync read ports.\n", filename.c_str(), line_number, token.c_str());
+                       SrstDef def;
+                       token = get_token();
+                       if (token == "none") {
+                               def.val = ResetValKind::None;
+                       } else if (token == "zero") {
+                               def.val = ResetValKind::Zero;
+                       } else if (token == "any") {
+                               def.val = ResetValKind::Any;
+                       } else if (token == "no_undef") {
+                               def.val = ResetValKind::NoUndef;
+                       } else if (token == "init") {
+                               def.val = ResetValKind::Init;
+                       } else {
+                               log_error("%s:%d: expected `none`, `zero`, `any`, `no_undef`, or `init`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       if (def.val == ResetValKind::None) {
+                               def.kind = SrstKind::None;
+                       } else {
+                               token = get_token();
+                               if (token == "ungated") {
+                                       def.kind = SrstKind::Ungated;
+                               } else if (token == "gated_clken") {
+                                       def.kind = SrstKind::GatedClkEn;
+                               } else if (token == "gated_rden") {
+                                       def.kind = SrstKind::GatedRdEn;
+                               } else {
+                                       log_error("%s:%d: expected `ungated`, `gated_clken` or `gated_rden`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                               }
+                       }
+                       def.block_wr = false;
+                       if (peek_token() == "block_wr") {
+                               get_token();
+                               def.block_wr = true;
+                       }
+                       get_semi();
+                       add_cap(port.rdsrst, def);
+               } else if (token == "wrprio") {
+                       if (port.kind == PortKind::Ar || port.kind == PortKind::Sr)
+                               log_error("%s:%d: `wrprio` only allowed on write ports.\n", filename.c_str(), line_number);
+                       do {
+                               add_cap(port.wrprio, get_string());
+                       } while (peek_string());
+                       get_semi();
+               } else if (token == "wrtrans") {
+                       if (port.kind == PortKind::Ar || port.kind == PortKind::Sr)
+                               log_error("%s:%d: `wrtrans` only allowed on write ports.\n", filename.c_str(), line_number);
+                       token = peek_token();
+                       RawWrTransDef def;
+                       if (token == "all") {
+                               def.target_kind = WrTransTargetKind::All;
+                               get_token();
+                       } else {
+                               def.target_kind = WrTransTargetKind::Group;
+                               def.target_group = get_string();
+                       }
+                       token = get_token();
+                       if (token == "new") {
+                               def.kind = WrTransKind::New;
+                       } else if (token == "old") {
+                               def.kind = WrTransKind::Old;
+                       } else {
+                               log_error("%s:%d: expected `new` or `old`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(port.wrtrans, def);
+               } else if (token == "forbid") {
+                       get_semi();
+                       add_cap(port.forbid, {});
+               } else if (token == "optional") {
+                       get_semi();
+                       add_cap(port.optional, {});
+               } else if (token == "optional_rw") {
+                       get_semi();
+                       add_cap(port.optional_rw, {});
+               } else if (token == "") {
+                       log_error("%s:%d: unexpected EOF while parsing port item.\n", filename.c_str(), line_number);
+               } else {
+                       log_error("%s:%d: unknown port-level item `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+       }
+
+       void parse_ram_item() {
+               std::string token = get_token();
+               if (token == "ifdef") {
+                       bool save = enter_ifdef(true);
+                       parse_ram_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_ram_block();
+                       }
+                       active = save;
+               } else if (token == "ifndef") {
+                       bool save = enter_ifdef(false);
+                       parse_ram_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_ram_block();
+                       }
+                       active = save;
+               } else if (token == "option") {
+                       enter_option();
+                       parse_ram_block();
+                       exit_option();
+               } else if (token == "prune_rom") {
+                       get_semi();
+                       add_cap(ram.prune_rom, {});
+               } else if (token == "forbid") {
+                       get_semi();
+                       add_cap(ram.forbid, {});
+               } else if (token == "abits") {
+                       int val = get_int();
+                       if (val < 0)
+                               log_error("%s:%d: abits %d nagative.\n", filename.c_str(), line_number, val);
+                       get_semi();
+                       add_cap(ram.abits, val);
+               } else if (token == "width") {
+                       WidthsDef def;
+                       int w = get_int();
+                       if (w <= 0)
+                               log_error("%s:%d: width %d not positive.\n", filename.c_str(), line_number, w);
+                       def.widths.push_back(w);
+                       def.mode = WidthMode::Single;
+                       get_semi();
+                       add_cap(ram.widths, def);
+               } else if (token == "widths") {
+                       WidthsDef def;
+                       int last = 0;
+                       do {
+                               int w = get_int();
+                               if (w <= 0)
+                                       log_error("%s:%d: width %d not positive.\n", filename.c_str(), line_number, w);
+                               if (w < last * 2)
+                                       log_error("%s:%d: width %d smaller than %d required for progression.\n", filename.c_str(), line_number, w, last * 2);
+                               last = w;
+                               def.widths.push_back(w);
+                       } while(peek_int());
+                       token = get_token();
+                       if (token == "global") {
+                               def.mode = WidthMode::Global;
+                       } else if (token == "per_port") {
+                               def.mode = WidthMode::PerPort;
+                       } else {
+                               log_error("%s:%d: expected `global`, or `per_port`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(ram.widths, def);
+               } else if (token == "resource") {
+                       ResourceDef def;
+                       def.name = get_string();
+                       if (peek_int())
+                               def.count = get_int();
+                       else
+                               def.count = 1;
+                       get_semi();
+                       add_cap(ram.resource, def);
+               } else if (token == "cost") {
+                       add_cap(ram.cost, get_double());
+                       get_semi();
+               } else if (token == "widthscale") {
+                       if (peek_int()) {
+                               add_cap(ram.widthscale, get_double());
+                       } else {
+                               add_cap(ram.widthscale, 0.0);
+                       }
+                       get_semi();
+               } else if (token == "byte") {
+                       int val = get_int();
+                       if (val <= 0)
+                               log_error("%s:%d: byte width %d not positive.\n", filename.c_str(), line_number, val);
+                       add_cap(ram.byte, val);
+                       get_semi();
+               } else if (token == "init") {
+                       MemoryInitKind kind;
+                       token = get_token();
+                       if (token == "zero") {
+                               kind = MemoryInitKind::Zero;
+                       } else if (token == "any") {
+                               kind = MemoryInitKind::Any;
+                       } else if (token == "no_undef") {
+                               kind = MemoryInitKind::NoUndef;
+                       } else if (token == "none") {
+                               kind = MemoryInitKind::None;
+                       } else {
+                               log_error("%s:%d: expected `zero`, `any`, `none`, or `no_undef`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       get_semi();
+                       add_cap(ram.init, kind);
+               } else if (token == "style") {
+                       do {
+                               std::string val = get_string();
+                               for (auto &c: val)
+                                       c = std::tolower(c);
+                               add_cap(ram.style, val);
+                       } while (peek_string());
+                       get_semi();
+               } else if (token == "port") {
+                       port = PortGroupDef();
+                       token = get_token();
+                       if (token == "ar") {
+                               port.kind = PortKind::Ar;
+                       } else if (token == "sr") {
+                               port.kind = PortKind::Sr;
+                       } else if (token == "sw") {
+                               port.kind = PortKind::Sw;
+                       } else if (token == "arsw") {
+                               port.kind = PortKind::Arsw;
+                       } else if (token == "srsw") {
+                               port.kind = PortKind::Srsw;
+                       } else {
+                               log_error("%s:%d: expected `ar`, `sr`, `sw`, `arsw`, or `srsw`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       do {
+                               port.names.push_back(get_string());
+                       } while (peek_string());
+                       parse_port_block();
+                       if (active)
+                               add_cap(ram.ports, port);
+               } else if (token == "") {
+                       log_error("%s:%d: unexpected EOF while parsing ram item.\n", filename.c_str(), line_number);
+               } else {
+                       log_error("%s:%d: unknown ram-level item `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+       }
+
+       void parse_top_item() {
+               std::string token = get_token();
+               if (token == "ifdef") {
+                       bool save = enter_ifdef(true);
+                       parse_top_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_top_block();
+                       }
+                       active = save;
+               } else if (token == "ifndef") {
+                       bool save = enter_ifdef(false);
+                       parse_top_block();
+                       if (peek_token() == "else") {
+                               enter_else(save);
+                               parse_top_block();
+                       }
+                       active = save;
+               } else if (token == "ram") {
+                       int orig_line = line_number;
+                       ram = RamDef();
+                       token = get_token();
+                       if (token == "distributed") {
+                               ram.kind = RamKind::Distributed;
+                       } else if (token == "block") {
+                               ram.kind = RamKind::Block;
+                       } else if (token == "huge") {
+                               ram.kind = RamKind::Huge;
+                       } else {
+                               log_error("%s:%d: expected `distributed`, `block`, or `huge`, got `%s`.\n", filename.c_str(), line_number, token.c_str());
+                       }
+                       ram.id = get_id();
+                       parse_ram_block();
+                       if (active) {
+                               compile_ram(orig_line);
+                       }
+               } else if (token == "") {
+                       log_error("%s:%d: unexpected EOF while parsing top item.\n", filename.c_str(), line_number);
+               } else {
+                       log_error("%s:%d: unknown top-level item `%s`.\n", filename.c_str(), line_number, token.c_str());
+               }
+       }
+
+       bool opts_ok(const Options &def, const Options &var) {
+               for (auto &it: def)
+                       if (var.at(it.first) != it.second)
+                               return false;
+               return true;
+       }
+
+       template<typename T> const T *find_single_cap(const Caps<T> &caps, const Options &opts, const Options &portopts, const char *name) {
+               const T *res = nullptr;
+               for (auto &cap: caps) {
+                       if (!opts_ok(cap.opts, opts))
+                               continue;
+                       if (!opts_ok(cap.portopts, portopts))
+                               continue;
+                       if (res)
+                               log_error("%s:%d: duplicate %s cap.\n", filename.c_str(), line_number, name);
+                       res = &cap.val;
+               }
+               return res;
+       }
+
+       std::vector<Options> make_opt_combinations(const dict<std::string, pool<Const>> &opts) {
+               std::vector<Options> res;
+               res.push_back(Options());
+               for (auto &it: opts) {
+                       std::vector<Options> new_res;
+                       for (auto &val: it.second) {
+                               for (Options o: res) {
+                                       o[it.first] = val;
+                                       new_res.push_back(o);
+                               }
+                       }
+                       res = new_res;
+               }
+               return res;
+       }
+
+       void compile_portgroup(Ram &cram, PortGroupDef &pdef, dict<std::string, int> &clk_ids, const dict<std::string, int> &port_ids, int orig_line) {
+               PortGroup grp;
+               grp.optional = find_single_cap(pdef.optional, cram.options, Options(), "optional");
+               grp.optional_rw = find_single_cap(pdef.optional_rw, cram.options, Options(), "optional_rw");
+               grp.names = pdef.names;
+               for (auto portopts: make_opt_combinations(pdef.portopts)) {
+                       bool forbidden = false;
+                       for (auto &fdef: ram.forbid) {
+                               if (opts_ok(fdef.opts, cram.options) && opts_ok(fdef.portopts, portopts)) {
+                                       forbidden = true;
+                               }
+                       }
+                       if (forbidden)
+                               continue;
+                       PortVariant var;
+                       var.options = portopts;
+                       var.kind = pdef.kind;
+                       if (pdef.kind != PortKind::Ar) {
+                               const ClockDef *cdef = find_single_cap(pdef.clock, cram.options, portopts, "clock");
+                               if (!cdef)
+                                       log_error("%s:%d: missing clock capability.\n", filename.c_str(), orig_line);
+                               var.clk_pol = cdef->kind;
+                               if (cdef->name.empty()) {
+                                       var.clk_shared = -1;
+                               } else {
+                                       auto it = clk_ids.find(cdef->name);
+                                       bool anyedge = cdef->kind == ClkPolKind::Anyedge;
+                                       if (it == clk_ids.end()) {
+                                               clk_ids[cdef->name] = var.clk_shared = GetSize(cram.shared_clocks);
+                                               RamClock clk;
+                                               clk.name = cdef->name;
+                                               clk.anyedge = anyedge;
+                                               cram.shared_clocks.push_back(clk);
+                                       } else {
+                                               var.clk_shared = it->second;
+                                               if (cram.shared_clocks[var.clk_shared].anyedge != anyedge) {
+                                                       log_error("%s:%d: named clock \"%s\" used with both posedge/negedge and anyedge clocks.\n", filename.c_str(), orig_line, cdef->name.c_str());
+                                               }
+                                       }
+                               }
+                               var.clk_en = find_single_cap(pdef.clken, cram.options, portopts, "clken");
+                       }
+                       const PortWidthDef *wdef = find_single_cap(pdef.width, cram.options, portopts, "width");
+                       if (wdef) {
+                               if (cram.width_mode != WidthMode::PerPort)
+                                       log_error("%s:%d: per-port width doesn't make sense for tied dbits.\n", filename.c_str(), orig_line);
+                               compile_widths(var, cram.dbits, *wdef);
+                       } else {
+                               var.width_tied = true;
+                               var.min_wr_wide_log2 = 0;
+                               var.min_rd_wide_log2 = 0;
+                               var.max_wr_wide_log2 = GetSize(cram.dbits) - 1;
+                               var.max_rd_wide_log2 = GetSize(cram.dbits) - 1;
+                       }
+                       if (pdef.kind == PortKind::Srsw || pdef.kind == PortKind::Sr) {
+                               const RdWrKind *rdwr = find_single_cap(pdef.rdwr, cram.options, portopts, "rdwr");
+                               var.rdwr = rdwr ? *rdwr : RdWrKind::Undefined;
+                               var.rd_en = find_single_cap(pdef.rden, cram.options, portopts, "rden");
+                               const ResetValKind *iv = find_single_cap(pdef.rdinit, cram.options, portopts, "rdinit");
+                               var.rdinitval = iv ? *iv : ResetValKind::None;
+                               const ResetValKind *arv = find_single_cap(pdef.rdarst, cram.options, portopts, "rdarst");
+                               var.rdarstval = arv ? *arv : ResetValKind::None;
+                               const SrstDef *srv = find_single_cap(pdef.rdsrst, cram.options, portopts, "rdsrst");
+                               if (srv) {
+                                       var.rdsrstval = srv->val;
+                                       var.rdsrstmode = srv->kind;
+                                       var.rdsrst_block_wr = srv->block_wr;
+                                       if (srv->kind == SrstKind::GatedClkEn && !var.clk_en)
+                                               log_error("%s:%d: `gated_clken` used without `clken`.\n", filename.c_str(), orig_line);
+                                       if (srv->kind == SrstKind::GatedRdEn && !var.rd_en)
+                                               log_error("%s:%d: `gated_rden` used without `rden`.\n", filename.c_str(), orig_line);
+                               } else {
+                                       var.rdsrstval = ResetValKind::None;
+                                       var.rdsrstmode = SrstKind::None;
+                                       var.rdsrst_block_wr = false;
+                               }
+                               if (var.rdarstval == ResetValKind::Init || var.rdsrstval == ResetValKind::Init) {
+                                       if (var.rdinitval != ResetValKind::Any && var.rdinitval != ResetValKind::NoUndef) {
+                                               log_error("%s:%d: reset value `init` has to be paired with `any` or `no_undef` initial value.\n", filename.c_str(), orig_line);
+                                       }
+                               }
+                       }
+                       var.wrbe_separate = find_single_cap(pdef.wrbe_separate, cram.options, portopts, "wrbe_separate");
+                       if (var.wrbe_separate && cram.byte == 0) {
+                               log_error("%s:%d: `wrbe_separate` used without `byte`.\n", filename.c_str(), orig_line);
+                       }
+                       for (auto &def: pdef.wrprio) {
+                               if (!opts_ok(def.opts, cram.options))
+                                       continue;
+                               if (!opts_ok(def.portopts, portopts))
+                                       continue;
+                               var.wrprio.push_back(port_ids.at(def.val));
+                       }
+                       for (auto &def: pdef.wrtrans) {
+                               if (!opts_ok(def.opts, cram.options))
+                                       continue;
+                               if (!opts_ok(def.portopts, portopts))
+                                       continue;
+                               WrTransDef tdef;
+                               tdef.target_kind = def.val.target_kind;
+                               if (def.val.target_kind == WrTransTargetKind::Group)
+                                       tdef.target_group = port_ids.at(def.val.target_group);
+                               tdef.kind = def.val.kind;
+                               var.wrtrans.push_back(tdef);
+                       }
+                       grp.variants.push_back(var);
+               }
+               if (grp.variants.empty()) {
+                       log_error("%s:%d: all port option combinations are forbidden.\n", filename.c_str(), orig_line);
+               }
+               cram.port_groups.push_back(grp);
+       }
+
+       void compile_ram(int orig_line) {
+               if (ram.abits.empty())
+                       log_error("%s:%d: `dims` capability should be specified.\n", filename.c_str(), orig_line);
+               if (ram.widths.empty())
+                       log_error("%s:%d: `widths` capability should be specified.\n", filename.c_str(), orig_line);
+               if (ram.ports.empty())
+                       log_error("%s:%d: at least one port group should be specified.\n", filename.c_str(), orig_line);
+               for (auto opts: make_opt_combinations(ram.opts)) {
+                       bool forbidden = false;
+                       for (auto &fdef: ram.forbid) {
+                               if (opts_ok(fdef.opts, opts)) {
+                                       forbidden = true;
+                               }
+                       }
+                       if (forbidden)
+                               continue;
+                       Ram cram;
+                       cram.id = ram.id;
+                       cram.kind = ram.kind;
+                       cram.options = opts;
+                       cram.prune_rom = find_single_cap(ram.prune_rom, opts, Options(), "prune_rom");
+                       const int *abits = find_single_cap(ram.abits, opts, Options(), "abits");
+                       if (!abits)
+                               continue;
+                       cram.abits = *abits;
+                       const WidthsDef *widths = find_single_cap(ram.widths, opts, Options(), "widths");
+                       if (!widths)
+                               continue;
+                       cram.dbits = widths->widths;
+                       cram.width_mode = widths->mode;
+                       const ResourceDef *resource = find_single_cap(ram.resource, opts, Options(), "resource");
+                       if (resource) {
+                               cram.resource_name = resource->name;
+                               cram.resource_count = resource->count;
+                       } else {
+                               cram.resource_count = 1;
+                       }
+                       cram.cost = 0;
+                       for (auto &cap: ram.cost) {
+                               if (opts_ok(cap.opts, opts))
+                                       cram.cost += cap.val;
+                       }
+                       const double *widthscale = find_single_cap(ram.widthscale, opts, Options(), "widthscale");
+                       if (widthscale)
+                               cram.widthscale = *widthscale ? *widthscale : cram.cost;
+                       else
+                               cram.widthscale = 0;
+                       const int *byte = find_single_cap(ram.byte, opts, Options(), "byte");
+                       cram.byte = byte ? *byte : 0;
+                       if (GetSize(cram.dbits) - 1 > cram.abits)
+                               log_error("%s:%d: abits %d too small for dbits progression.\n", filename.c_str(), line_number, cram.abits);
+                       validate_byte(widths->widths, cram.byte);
+                       const MemoryInitKind *ik = find_single_cap(ram.init, opts, Options(), "init");
+                       cram.init = ik ? *ik : MemoryInitKind::None;
+                       for (auto &sdef: ram.style)
+                               if (opts_ok(sdef.opts, opts))
+                                       cram.style.push_back(sdef.val);
+                       dict<std::string, int> port_ids;
+                       int ctr = 0;
+                       for (auto &pdef: ram.ports) {
+                               if (!opts_ok(pdef.opts, opts))
+                                       continue;
+                               for (auto &name: pdef.val.names)
+                                       port_ids[name] = ctr;
+                               ctr++;
+                       }
+                       dict<std::string, int> clk_ids;
+                       for (auto &pdef: ram.ports) {
+                               if (!opts_ok(pdef.opts, opts))
+                                       continue;
+                               compile_portgroup(cram, pdef.val, clk_ids, port_ids, orig_line);
+                       }
+                       lib.rams.push_back(cram);
+               }
+       }
+
+       void validate_byte(const std::vector<int> &widths, int byte) {
+               if (byte == 0)
+                       return;
+               if (byte >= widths.back())
+                       return;
+               if (widths[0] % byte == 0) {
+                       for (int j = 1; j < GetSize(widths); j++)
+                               if (widths[j] % byte != 0)
+                                       log_error("%s:%d: width progression past byte width %d is not divisible.\n", filename.c_str(), line_number, byte);
+                       return;
+               }
+               for (int i = 0; i < GetSize(widths); i++) {
+                       if (widths[i] == byte) {
+                               for (int j = i + 1; j < GetSize(widths); j++)
+                                       if (widths[j] % byte != 0)
+                                               log_error("%s:%d: width progression past byte width %d is not divisible.\n", filename.c_str(), line_number, byte);
+                               return;
+                       }
+               }
+               log_error("%s:%d: byte width %d invalid for dbits.\n", filename.c_str(), line_number, byte);
+       }
+
+       void compile_widths(PortVariant &var, const std::vector<int> &widths, const PortWidthDef &width) {
+               var.width_tied = width.tied;
+               auto wr_widths = compile_widthdef(widths, width.wr_widths);
+               var.min_wr_wide_log2 = wr_widths.first;
+               var.max_wr_wide_log2 = wr_widths.second;
+               if (width.tied) {
+                       var.min_rd_wide_log2 = wr_widths.first;
+                       var.max_rd_wide_log2 = wr_widths.second;
+               } else {
+                       auto rd_widths = compile_widthdef(widths, width.rd_widths);
+                       var.min_rd_wide_log2 = rd_widths.first;
+                       var.max_rd_wide_log2 = rd_widths.second;
+               }
+       }
+
+       std::pair<int, int> compile_widthdef(const std::vector<int> &dbits, const std::vector<int> &widths) {
+               if (widths.empty())
+                       return {0, GetSize(dbits) - 1};
+               for (int i = 0; i < GetSize(dbits); i++) {
+                       if (dbits[i] == widths[0]) {
+                               for (int j = 0; j < GetSize(widths); j++) {
+                                       if (i+j >= GetSize(dbits) || dbits[i+j] != widths[j]) {
+                                               log_error("%s:%d: port width %d doesn't match dbits progression.\n", filename.c_str(), line_number, widths[j]);
+                                       }
+                               }
+                               return {i, i + GetSize(widths) - 1};
+                       }
+               }
+               log_error("%s:%d: port width %d invalid for dbits.\n", filename.c_str(), line_number, widths[0]);
+       }
+
+       void parse() {
+               while (peek_token() != "")
+                       parse_top_item();
+       }
+};
+
+PRIVATE_NAMESPACE_END
+
+Library MemLibrary::parse_library(const std::vector<std::string> &filenames, const pool<std::string> &defines) {
+       Library res;
+       pool<std::string> defines_unused = defines;
+       for (auto &file: filenames) {
+               Parser(file, res, defines, defines_unused);
+       }
+       for (auto def: defines_unused) {
+               log_warning("define %s not used in the library.\n", def.c_str());
+       }
+       return res;
+}
diff --git a/passes/memory/memlib.h b/passes/memory/memlib.h
new file mode 100644 (file)
index 0000000..c3f7728
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2021  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#ifndef MEMLIB_H
+#define MEMLIB_H
+
+#include <string>
+#include <vector>
+
+#include "kernel/yosys.h"
+
+YOSYS_NAMESPACE_BEGIN
+
+namespace MemLibrary {
+
+enum class RamKind {
+       Auto,
+       Logic,
+       NotLogic,
+       Distributed,
+       Block,
+       Huge,
+};
+
+enum class WidthMode {
+       Single,
+       Global,
+       PerPort,
+};
+
+enum class MemoryInitKind {
+       None,
+       Zero,
+       Any,
+       NoUndef,
+};
+
+enum class PortKind {
+       Sr,
+       Ar,
+       Sw,
+       Srsw,
+       Arsw,
+};
+
+enum class ClkPolKind {
+       Anyedge,
+       Posedge,
+       Negedge,
+};
+
+enum class RdWrKind {
+       Undefined,
+       NoChange,
+       New,
+       Old,
+       NewOnly,
+};
+
+enum class ResetValKind {
+       None,
+       Zero,
+       Any,
+       NoUndef,
+       Init,
+};
+
+enum class SrstKind {
+       None,
+       Ungated,
+       GatedClkEn,
+       GatedRdEn,
+};
+
+enum class WrTransTargetKind {
+       All,
+       Group,
+};
+
+enum class WrTransKind {
+       New,
+       Old,
+};
+
+struct WrTransDef {
+       WrTransTargetKind target_kind;
+       int target_group;
+       WrTransKind kind;
+};
+
+struct PortVariant {
+       dict<std::string, Const> options;
+       PortKind kind;
+       int clk_shared;
+       ClkPolKind clk_pol;
+       bool clk_en;
+       bool width_tied;
+       int min_wr_wide_log2;
+       int max_wr_wide_log2;
+       int min_rd_wide_log2;
+       int max_rd_wide_log2;
+       bool rd_en;
+       RdWrKind rdwr;
+       ResetValKind rdinitval;
+       ResetValKind rdarstval;
+       ResetValKind rdsrstval;
+       SrstKind rdsrstmode;
+       bool rdsrst_block_wr;
+       bool wrbe_separate;
+       std::vector<int> wrprio;
+       std::vector<WrTransDef> wrtrans;
+};
+
+struct PortGroup {
+       bool optional;
+       bool optional_rw;
+       std::vector<std::string> names;
+       std::vector<PortVariant> variants;
+};
+
+struct RamClock {
+       std::string name;
+       bool anyedge;
+};
+
+struct Ram {
+       IdString id;
+       RamKind kind;
+       dict<std::string, Const> options;
+       std::vector<PortGroup> port_groups;
+       bool prune_rom;
+       int abits;
+       std::vector<int> dbits;
+       WidthMode width_mode;
+       std::string resource_name;
+       int resource_count;
+       double cost;
+       double widthscale;
+       int byte;
+       MemoryInitKind init;
+       std::vector<std::string> style;
+       std::vector<RamClock> shared_clocks;
+};
+
+struct Library {
+       std::vector<Ram> rams;
+};
+
+Library parse_library(const std::vector<std::string> &filenames, const pool<std::string> &defines);
+
+}
+
+YOSYS_NAMESPACE_END
+
+#endif
diff --git a/passes/memory/memlib.md b/passes/memory/memlib.md
new file mode 100644 (file)
index 0000000..fdc2d4b
--- /dev/null
@@ -0,0 +1,505 @@
+# The `memory_libmap` pass
+
+The `memory_libmap` pass is used to map memories to hardware primitives.  To work,
+it needs a description of available target memories in a custom format.
+
+
+## Basic structure
+
+A basic library could look like this:
+
+    # A distributed-class RAM called $__RAM16X4SDP_
+    ram distributed $__RAM16X4SDP_ {
+        # Has 4 address bits (ie. 16 rows).
+        abits 4;
+        # Has 4 data bits.
+        width 4;
+        # Cost for the selection heuristic.
+        cost 4;
+        # Can be initialized to any value on startup.
+        init any;
+        # Has a synchronous write port called "W"...
+        port sw "W" {
+            # ... with a positive edge clock.
+            clock posedge;
+        }
+        # Has an asynchronous read port called "R".
+        port ar "R" {
+        }
+    }
+
+    # A block-class RAM called $__RAMB9K_
+    ram block $__RAMB9K_ {
+        # Has 13 address bits in the base (most narrow) data width.
+        abits 13;
+        # The available widths are:
+        # - 1 (13 address bits)
+        # - 2 (12 address bits)
+        # - 4 (11 address bits)
+        # - 9 (10 address bits)
+        # - 18 (9 address bits)
+        # The width selection is per-port.
+        widths 1 2 4 9 18 per_port;
+        # Has a write enable signal with 1 bit for every 9 data bits.
+        byte 9;
+        cost 64;
+        init any;
+        # Has two synchronous read+write ports, called "A" and "B".
+        port srsw "A" "B" {
+            clock posedge;
+            # Has a clock enable signal (gates both read and write).
+            clken;
+            # Has three per-port selectable options for handling read+write behavior:
+            portoption "RDWR" "NO_CHANGE" {
+                # When port is writing, reading is not done (output register keeps
+                # its value).
+                rdwr no_change;
+            }
+            portoption "RDWR" "OLD" {
+                # When port is writing, the data read is the old value (before the
+                # write).
+                rdwr old;
+            }
+            portoption "RDWR" "NEW" {
+                # When port is writing, the data read is the new value.
+                rdwr new;
+            }
+        }
+    }
+
+The pass will automatically select between the two available cells and
+the logic fallback (mapping the whole memory to LUTs+FFs) based on required
+capabilities and cost function.  The selected memories will be transformed
+to intermediate `$__RAM16X4SDP_` and `$__RAMB9K_` cells that need to be mapped
+to actual hardware cells by a `techmap` pass, while memories selected for logic
+fallback will be left unmapped and will be later mopped up by `memory_map` pass.
+
+## RAM definition blocks
+
+The syntax for a RAM definition is:
+
+    ram <kind: distributed|block|huge> <name> {
+        <ram properties>
+        <ports>
+    }
+
+The `<name>` is used as the type of the mapped cell that will be passed to `techmap`.
+The memory kind is one of `distributed`, `block`, or `huge`.  It describes the general
+class of the memory and can be matched on by manual selection attributes.
+
+The available ram properties are:
+
+- `abits <address bits>;`
+- `width <width>;`
+- `widths <width 1> <width 2> ... <width n> <global|per_port>;`
+- `byte <width>;`
+- `cost <cost>;`
+- `widthscale [<factor>];`
+- `resource <name> <count>;`
+- `init <none|zero|any|no_undef>;`
+- `style "<name 1>" "<name 2>" "<name 3>" ...;`
+- `prune_rom;`
+
+### RAM dimensions
+
+The memory dimensions are described by `abits` and `width` or `widths` properties.
+
+For a simple memory cell with a fixed width, use `abits` and `width` like this:
+
+    abits 4;
+    width 4;
+
+This will result in a `2**abits Ã— width` memory cell.
+
+Multiple-width memories are also possible, and use the `widths` property instead.
+The rules for multiple-width memories are:
+
+- the widths are given in `widths` property in increasing order
+- the value in the `abits` property corresponds to the most narrow width
+- every width in the list needs to be greater than or equal to twice
+  the previous width (ie. `1 2 4 9 18` is valid, `1 2 4 7 14` is not)
+- it is assumed that, for every width in progression, the word in memory
+  is made of two smaller words, plus optionally some extra bits (eg. in the above
+  list, the 9-bit word is made of two 4-bit words and 1 extra bit), and thus
+  each sequential width in the list corresponds to one fewer usable address bit
+- all addresses connected to memory ports are always `abits` bits wide, with const
+  zero wired to the unused bits corresponding to wide ports
+
+When multiple widths are specified, they can be `per_port` or `global`.
+For the `global` version, the pass has to pick one width for the whole cell,
+and it is set on the resulting cell as the `WIDTH` parameter.  For the `per_port`
+version, the selection is made on per-port basis, and passed using `PORT_*_WIDTH`
+parameters.  When the mode is `per_port`, the width selection can be fine-tuned
+with the port `width` property.
+
+Specifying dimensions is mandatory.
+
+
+### Byte width
+
+If the memory cell has per-byte write enables, the `byte` property can be used
+to define the byte size (ie. how many data bits correspond to one write enable
+bit).
+
+The property is optional.  If not used, it is assumed that there is a single
+write enable signal for each writable port.
+
+The rules for this property are as follows:
+
+- for every available width, the width needs to be a multiple of the byte size,
+  or the byte size needs to be larger than the width
+- if the byte size is larger than the width, the byte enable signel is assumed
+  to be one bit wide and cover the whole port
+- otherwise, the byte enable signal has one bit for every `byte` bits of the
+  data port
+
+The exact kind of byte enable signal is determined by the presence or absence
+of the per-port `wrbe_separate` property.
+
+
+### Cost properties
+
+The `cost` property is used to estimate the cost of using a given mapping.
+This is the cost of using one cell, and will be scaled as appropriate if
+the mapping requires multiple cells.
+
+If the `widthscale` property is specified, the mapping is assumed to be flexible,
+with cost scaling with the percentage of data width actually used.  The value
+of the `widthscale` property is how much of the cost is scalable as such.
+If the value is omitted, all of the cost is assumed to scale.
+Eg. for the following properties:
+
+    width 14;
+    cost 8;
+    widthscale 7;
+
+The cost of a given cell will be assumed to be `(8 - 7) + 7 * (used_bits / 14)`.
+
+If `widthscale` is used, The pass will attach a `BITS_USED` parameter to mapped
+calls, with a bitmask of which data bits of the memory are actually in use.
+The parameter width will be the widest width in the `widths` property, and
+the bit correspondence is defined accordingly.
+
+The `cost` property is mandatory.
+
+
+### `init` property
+
+This property describes the state of the memory at initialization time.  Can have
+one of the following values:
+
+- `none`: the memory contents are unpredictable, memories requiring any sort
+  of initialization will not be mapped to this cell
+- `zero`: the memory contents are zero, memories can be mapped to this cell iff
+  their initialization value is entirely zero or undef
+- `any`: the memory contents can be arbitrarily selected, and the initialization
+  will be passes as the `INIT` parameter to the mapped cell
+- `no_undef`: like `any`, but only 0 and 1 bit values are supported (the pass will
+  convert any x bits to 0)
+
+The `INIT` parameter is always constructed as a concatenation of words corresponding
+to the widest available `widths` setting, so that all available memory cell bits
+are covered.
+
+This property is optional and assumed to be `none` when not present.
+
+
+### `style` property
+
+Provides a name (or names) for this definition that can be passed to the `ram_style`
+or similar attribute to manually select it.  Optional and can be used multiple times.
+
+
+### `prune_rom` property
+
+Specifying this property disqualifies the definition from consideration for source
+memories that have no write ports (ie. ROMs).  Use this on definitions that have
+an obviously superior read-only alternative (eg. LUTRAMs) to make the pass skip
+them over quickly.
+
+
+## Port definition blocks
+
+The syntax for a port group definition is:
+
+    port <ar|sr|sw|arsw|srsw> "NAME 1" "NAME 2" ... {
+        <port properties>
+    }
+
+A port group definition defines a group of ports with identical properties.
+There are as many ports in a group as there are names given.
+
+Ports come in 5 kinds:
+
+- `ar`: asynchronous read port
+- `sr`: synchronous read port
+- `sw`: synchronous write port
+- `arsw`: simultanous synchronous write + asynchronous read with common address (commonly found in LUT RAMs)
+- `srsw`: synchronous write + synchronous read with common address
+
+The port properties available are:
+
+- `width <tied|mix>;`
+- `width <width 1> <width 2> ...;`
+- `width <tied|mix> <width 1> <width 2> ...;`
+- `width rd <width 1> <width 2> ... wr <width 1> <width 2> ...;`
+- `clock <posedge|negedge|anyedge> ["SHARED_NAME"];`
+- `clken;`
+- `rden;`
+- `wrbe_separate;`
+- `rdwr <undefined|no_change|new|old|new_only>;`
+- `rdinit <none|zero|any|no_undef>;`
+- `rdarst <none|zero|any|no_undef|init>;`
+- `rdsrst <none|zero|any|no_undef|init> <ungated|gatec_clken|gated_rden> [block_wr];`
+- `wrprio "NAME" "NAME" ...;`
+- `wrtrans <"NAME"|all> <old|new>;`
+- `optional;`
+- `optional_rw;`
+
+The base signals connected to the mapped cell for ports are:
+
+- `PORT_<name>_ADDR`: the address
+- `PORT_<name>_WR_DATA`: the write data (for `sw`/`arsw`/`srsw` ports only)
+- `PORT_<name>_RD_DATA`: the read data (for `ar`/`sr`/`arsw`/`srsw` ports only)
+- `PORT_<name>_WR_EN`: the write enable or enables (for `sw`/`arsw`/`srsw` ports only)
+
+The address is always `abits` wide.  If a non-narrowest width is used, the appropriate low
+bits will be tied to 0.
+
+
+### Port `width` prooperty
+
+If the RAM has `per_port` widths, the available width selection can be further described
+on per-port basis, by using one of the following properties:
+
+- `width tied;`: any width from the master `widths` list is acceptable, and
+  (for read+write ports) the read and write width has to be the same
+- `width tied <width 1> <width 2> ...;`: like above, but limits the width
+  selection to the given list; the list has to be a contiguous sublist of the
+  master `widths` list
+- `width <width 1> <width 2> ...;`: alias for the above, to be used for read-only
+  or write-only ports
+- `width mix;`: any width from the master `widths` list is acceptable, and
+  read width can be different than write width (only usable for read+write ports)
+- `width mix <width 1> <width 2> ...;`: like above, but limits the width
+  selection to the given list; the list has to be a contiguous sublist of the
+  master `widths` list
+- `width rd <width 1> <width 2> ... wr <width 1> <width 2> ...;`: like above,
+  but the limitted selection can be different for read and write widths
+
+If `per_port` widths are in use and this property is not specified, `width tied;` is assumed.
+
+The parameters attached to the cell in `per_port` widths mode are:
+
+- `PORT_<name>_WIDTH`: the selected width (for `tied` ports)
+- `PORT_<name>_RD_WIDTH`: the selected read width (for `mix` ports)
+- `PORT_<name>_WR_WIDTH`: the selected write width (for `mix` ports)
+
+
+### `clock` property
+
+The `clock` property is used with synchronous ports (and synchronous ports only).
+It is mandatory for them and describes the clock polarity and clock sharing.
+`anyedge` means that both polarities are supported.
+
+If a shared clock name is provided, the port is assumed to have a shared clock signal
+with all other ports using the same shared name.  Otherwise, the port is assumed to
+have its own clock signal.
+
+The port clock is always provided on the memory cell as `PORT_<name>_CLK` signal
+(even if it is also shared).  Shared clocks are also provided as `CLK_<shared_name>`
+signals.
+
+For `anyedge` clocks, the cell gets a `PORT_<name>_CLKPOL` parameter that is set
+to 1 for `posedge` clocks and 0 for `negedge` clocks.  If the clock is shared,
+the same information will also be provided as `CLK_<shared_name>_POL` parameter.
+
+
+### `clken` and `rden`
+
+The `clken` property, if present, means that the port has a clock enable signal
+gating both reads and writes.  Such signal will be provided to the mapped cell
+as `PORT_<name>_CLK_EN`.  It is only applicable to synchronous ports.
+
+The `rden` property, if present, means that the port has a read clock enable signal.
+Such signal will be provided to the mapped cell as `PORT_<name>_RD_EN`.  It is only
+applicable to synchronous read ports (`sr` and `srsw`).
+
+For `sr` ports, both of these options are effectively equivalent.
+
+
+### `wrbe_separate` and the write enables
+
+The `wrbe_separate` property specifies that the write byte enables are provided
+as a separate signal from the main write enable.  It can only be used when the
+RAM-level `byte` property is also specified.
+
+The rules are as follows:
+
+If no `byte` is specified:
+
+- `wrbe_separate` is not allowed
+- `PORT_<name>_WR_EN` signal is single bit
+
+If `byte` is specified, but `wrbe_separate` is not:
+
+- `PORT_<name>_WR_EN` signal has one bit for every data byte
+- `PORT_<name>_WR_EN_WIDTH` parameter is the width of the above (only present for multiple-width cells)
+
+If `byte` is specified and `wrbe_separate` is present:
+
+- `PORT_<name>_WR_EN` signal is single bit
+- `PORT_<name>_WR_BE` signal has one bit for every data byte
+- `PORT_<name>_WR_BE_WIDTH` parameter is the width of the above (only present for multiple-width cells)
+- a given byte is written iff all of `CLK_EN` (if present), `WR_EN`, and the corresponding `WR_BE` bit are one
+
+This property can only be used on write ports.
+
+
+### `rdwr` property
+
+This property is allowed only on `srsw` ports and describes read-write interactions.
+
+The possible values are:
+
+- `no_change`: if write is being performed (any bit of `WR_EN` is set),
+  reading is not performed and the `RD_DATA` keeps its old value
+- `undefined`: all `RD_DATA` bits corresponding to enabled `WR_DATA` bits
+  have undefined value, remaining bits read from memory
+- `old`: all `RD_DATA` bits get the previous value in memory
+- `new`: all `RD_DATA` bits get the new value in memory (transparent write)
+- `new_only`: all `RD_DATA` bits corresponding to enabled `WR_DATA` bits
+  get the new value, all others are undefined
+
+If this property is not found on an `srsw` port, `undefined` is assumed.
+
+
+### Read data initial value and resets
+
+The `rdinit`, `rdarst`, and `rdsrst` are applicable only to synchronous read
+ports.
+
+`rdinit` describes the initial value of the read port data, and can be set to
+one of the following:
+
+- `none`: initial data is indeterminate
+- `zero`: initial data is all-0
+- `any`: initial data is arbitrarily configurable, and the selected value
+  will be attached to the cell as `PORT_<name>_RD_INIT_VALUE` parameter
+- `no_undef`: like `any`, but only 0 and 1 bits are allowed
+
+`rdarst` and `rdsrst` describe the asynchronous and synchronous reset capabilities.
+The values are similar to `rdinit`:
+
+- `none`: no reset
+- `zero`: reset to all-0 data
+- `any`: reset to arbitrary value, the selected value
+  will be attached to the cell as `PORT_<name>_RD_ARST_VALUE` or
+  `PORT_<name>_RD_SRST_VALUE` parameter
+- `no_undef`: like `any`, but only 0 and 1 bits are allowed
+- `init`: reset to the initial value, as specified by `rdinit` (which must be `any`
+  or `no_undef` itself)
+
+If the capability is anything other than `none`, the reset signal
+will be provided as `PORT_<name>_RD_ARST` or `PORT_<name>_RD_SRST`.
+
+For `rdsrst`, the priority must be additionally specified, as one of:
+
+- `ungated`: `RD_SRST` has priority over both `CLK_EN` and `RD_EN` (if present)
+- `gated_clken`: `CLK_EN` has priority over `RD_SRST`; `RD_SRST` has priority over `RD_EN` if present
+- `gated_rden`: `RD_EN` and `CLK_EN` (if present) both have priority over `RD_SRST`
+
+Also, `rdsrst` can optionally have `block_wr` specified, which means that sync reset
+cannot be performed in the same cycle as a write.
+
+If not provided, `none` is assumed for all three properties.
+
+
+### Write priority
+
+The `wrprio` property is only allowed on write ports and defines a priority relationship
+between port â€” when `wrprio "B";` is used in definition of port `"A"`, and both ports
+simultanously write to the same memory cell, the value written by port `"A"` will have
+precedence.
+
+This property is optional, and can be used multiple times as necessary.  If no relationship
+is described for a pair of write ports, no priority will be assumed.
+
+
+### Write transparency
+
+The `wrtrans` property is only allowed on write ports and defines behavior when
+another synchronous read port reads from the memory cell at the same time as the
+given port writes it.  The values are:
+
+- `old`: the read port will get the old value of the cell
+- `new`: the read port will get the new value of the cell
+
+This property is optional, and can be used multiple times as necessary.  If no relationship
+is described for a pair of ports, the value read is assumed to be indeterminate.
+
+Note that this property is not used to describe the read value on the port itself for `srsw`
+ports â€” for that purpose, the `rdwr` property is used instead.
+
+
+### Optional ports
+
+The `optional;` property will make the pass attach a `PORT_<name>_USED` parameter
+with a boolean value specifying whether a given port was meaningfully used in
+mapping a given cell.  Likewise, `optional_rw;` will attach `PORT_<name>_RD_USED`
+and `PORT_<name>_WR_USED` the specify whether the read / write part in particular
+was used.  These can be useful if the mapping has some meaningful optimization
+to apply for unused ports, but doesn't otherwise influence the selection process.
+
+
+## Options
+
+For highly configurable cells, multiple variants may be described in one cell description.
+All properties and port definitions within a RAM or port definition can be put inside
+an `option` block as follows:
+
+    option "NAME" <value> {
+        <properties, ports, ...>
+    }
+
+The value and name of an option are arbitrary, and the selected option value
+will be provided to the cell as `OPTION_<name>` parameter.  Values can be
+strings or integers.
+
+
+Likewise, for per-port options, a `portoption` block can be used:
+
+    portoption "NAME" <value> {
+        <properties, ...>
+    }
+
+These options will be provided as `PORT_<pname>_OPTION_<oname>` parameters.
+
+The library parser will simply expand the RAM definition for every possible combination
+of option values mentioned in the RAM body, and likewise for port definitions.
+This can lead to a combinatorial explosion.
+
+If some option values cannot be used together, a `forbid` pseudo-property can be used
+to discard a given combination, eg:
+
+    option "ABC" 1 {
+        portoption "DEF" "GHI" {
+            forbid;
+        }
+    }
+
+will disallow combining the RAM option `ABC = 2` with port option `DEF = "GHI"`.
+
+
+## Ifdefs
+
+To allow reusing a library for multiple FPGA families with slighly differing
+capabilities, `ifdef` (and `ifndef`) blocks are provided:
+
+    ifdef IS_FANCY_FPGA_WITH_CONFIGURABLE_ASYNC_RESET {
+        rdarst any;
+    } else {
+        rdarst zero;
+    }
+
+Such blocks can be enabled by passing the `-D` option to the pass.
index bac547c1a4fc02ef8585778b551f8fa181088c04..e34cc927e5383fb2fe6c1835be92b9770292341f 100644 (file)
@@ -31,13 +31,14 @@ struct MemoryPass : public Pass {
        {
                //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
                log("\n");
-               log("    memory [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-bram <bram_rules>] [selection]\n");
+               log("    memory [-norom] [-nomap] [-nordff] [-nowiden] [-nosat] [-memx] [-bram <bram_rules>] [selection]\n");
                log("\n");
                log("This pass calls all the other memory_* passes in a useful order:\n");
                log("\n");
                log("    opt_mem\n");
                log("    opt_mem_priority\n");
                log("    opt_mem_feedback\n");
+               log("    memory_bmux2rom                     (skipped if called with -norom)\n");
                log("    memory_dff                          (skipped if called with -nordff or -memx)\n");
                log("    opt_clean\n");
                log("    memory_share [-nowiden] [-nosat]\n");
@@ -54,6 +55,7 @@ struct MemoryPass : public Pass {
        }
        void execute(std::vector<std::string> args, RTLIL::Design *design) override
        {
+               bool flag_norom = false;
                bool flag_nomap = false;
                bool flag_nordff = false;
                bool flag_memx = false;
@@ -65,6 +67,10 @@ struct MemoryPass : public Pass {
 
                size_t argidx;
                for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-norom") {
+                               flag_norom = true;
+                               continue;
+                       }
                        if (args[argidx] == "-nomap") {
                                flag_nomap = true;
                                continue;
@@ -97,6 +103,8 @@ struct MemoryPass : public Pass {
                Pass::call(design, "opt_mem");
                Pass::call(design, "opt_mem_priority");
                Pass::call(design, "opt_mem_feedback");
+               if (!flag_norom)
+                       Pass::call(design, "memory_bmux2rom");
                if (!flag_nordff)
                        Pass::call(design, "memory_dff");
                Pass::call(design, "opt_clean");
diff --git a/passes/memory/memory_bmux2rom.cc b/passes/memory/memory_bmux2rom.cc
new file mode 100644 (file)
index 0000000..a3fc5a7
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2022  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/mem.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct MemoryBmux2RomPass : public Pass {
+       MemoryBmux2RomPass() : Pass("memory_bmux2rom", "convert muxes to ROMs") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    memory_bmux2rom [options] [selection]\n");
+               log("\n");
+               log("This pass converts $bmux cells with constant A input to ROMs.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               log_header(design, "Executing MEMORY_BMUX2ROM pass (converting muxes to ROMs).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               for (auto module : design->selected_modules()) {
+                       for (auto cell : module->selected_cells()) {
+                               if (cell->type != ID($bmux))
+                                       continue;
+
+                               SigSpec sig_a = cell->getPort(ID::A);
+                               if (!sig_a.is_fully_const())
+                                       continue;
+
+                               int abits = cell->getParam(ID::S_WIDTH).as_int();
+                               int width = cell->getParam(ID::WIDTH).as_int();
+                               if (abits < 3)
+                                       continue;
+
+                               // Ok, let's do it.
+                               Mem mem(module, NEW_ID, width, 0, 1 << abits);
+                               mem.attributes = cell->attributes;
+
+                               MemInit init;
+                               init.addr = 0;
+                               init.data = sig_a.as_const();
+                               init.en = Const(State::S1, width);
+                               mem.inits.push_back(std::move(init));
+
+                               MemRd rd;
+                               rd.addr = cell->getPort(ID::S);
+                               rd.data = cell->getPort(ID::Y);
+                               rd.init_value = Const(State::Sx, width);
+                               rd.arst_value = Const(State::Sx, width);
+                               rd.srst_value = Const(State::Sx, width);
+                               mem.rd_ports.push_back(std::move(rd));
+
+                               mem.emit();
+                               module->remove(cell);
+                       }
+               }
+       }
+} MemoryBmux2RomPass;
+
+PRIVATE_NAMESPACE_END
diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc
new file mode 100644 (file)
index 0000000..ab7bb7b
--- /dev/null
@@ -0,0 +1,2093 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2021  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "memlib.h"
+
+#include <ctype.h>
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/mem.h"
+#include "kernel/qcsat.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+using namespace MemLibrary;
+
+#define FACTOR_MUX 0.5
+#define FACTOR_DEMUX 0.5
+#define FACTOR_EMU 2
+
+struct PassOptions {
+       bool no_auto_distributed;
+       bool no_auto_block;
+       bool no_auto_huge;
+       double logic_cost_rom;
+       double logic_cost_ram;
+};
+
+struct WrPortConfig {
+       // Index of the read port this port is merged with, or -1 if none.
+       int rd_port;
+       // Index of the PortGroup in the Ram.
+       int port_group;
+       int port_variant;
+       const PortVariant *def;
+       // Emulate priority logic for this list of (source) write port indices.
+       std::vector<int> emu_prio;
+       // If true, this port needs to end up with uniform byte enables to work correctly.
+       bool force_uniform;
+
+       WrPortConfig() : rd_port(-1), force_uniform(false) {}
+};
+
+struct RdPortConfig {
+       // Index of the write port this port is merged with, or -1 if none.
+       int wr_port;
+       // Index of the PortGroup in the Ram.
+       int port_group;
+       int port_variant;
+       const PortVariant *def;
+       // If true, this is a sync port mapped into async mem, make an output
+       // register.  Mutually exclusive with the following options.
+       bool emu_sync;
+       // Emulate the EN / ARST / SRST / init value circuitry.
+       bool emu_en;
+       bool emu_arst;
+       bool emu_srst;
+       bool emu_init;
+       // Emulate EN-SRST priority.
+       bool emu_srst_en_prio;
+       // If true, use clk_en as rd_en.
+       bool rd_en_to_clk_en;
+       // Emulate transparency logic for this list of (source) write port indices.
+       std::vector<int> emu_trans;
+
+       RdPortConfig() : wr_port(-1), emu_sync(false), emu_en(false), emu_arst(false), emu_srst(false), emu_init(false), emu_srst_en_prio(false), rd_en_to_clk_en(false) {}
+};
+
+// The named clock and clock polarity assignments.
+struct SharedClockConfig {
+       bool used;
+       SigBit clk;
+       // For anyedge clocks.
+       bool polarity;
+       // For non-anyedge clocks.
+       bool invert;
+};
+
+struct MemConfig {
+       // Reference to the library ram definition
+       const Ram *def;
+       // Port assignments, indexed by Mem port index.
+       std::vector<WrPortConfig> wr_ports;
+       std::vector<RdPortConfig> rd_ports;
+       std::vector<SharedClockConfig> shared_clocks;
+       // Emulate read-first write-read behavior using soft logic.
+       bool emu_read_first;
+       // This many low bits of (target) address are always-0 on all ports.
+       int base_width_log2;
+       int unit_width_log2;
+       std::vector<int> swizzle;
+       int hard_wide_mask;
+       int emu_wide_mask;
+       // How many times the base memory block will need to be duplicated to get more
+       // data bits.
+       int repl_d;
+       // How many times the whole memory array will need to be duplicated to cover
+       // all read ports required.
+       int repl_port;
+       // Emulation score â€” how much circuitry we need to add for priority / transparency /
+       // reset / initial value emulation.
+       int score_emu;
+       // Mux score â€” how much circuitry we need to add to manually decode whatever address
+       // bits are not decoded by the memory array itself, for reads.
+       int score_mux;
+       // Demux score â€” how much circuitry we need to add to manually decode whatever address
+       // bits are not decoded by the memory array itself, for writes.
+       int score_demux;
+       double cost;
+       MemConfig() : emu_read_first(false) {}
+};
+
+typedef std::vector<MemConfig> MemConfigs;
+
+struct MapWorker {
+       Module *module;
+       ModWalker modwalker;
+       SigMap sigmap;
+       SigMap sigmap_xmux;
+       FfInitVals initvals;
+
+       MapWorker(Module *module) : module(module), modwalker(module->design, module), sigmap(module), sigmap_xmux(module), initvals(&sigmap, module) {
+               for (auto cell : module->cells())
+               {
+                       if (cell->type == ID($mux))
+                       {
+                               RTLIL::SigSpec sig_a = sigmap_xmux(cell->getPort(ID::A));
+                               RTLIL::SigSpec sig_b = sigmap_xmux(cell->getPort(ID::B));
+
+                               if (sig_a.is_fully_undef())
+                                       sigmap_xmux.add(cell->getPort(ID::Y), sig_b);
+                               else if (sig_b.is_fully_undef())
+                                       sigmap_xmux.add(cell->getPort(ID::Y), sig_a);
+                       }
+               }
+       }
+};
+
+struct SwizzleBit {
+       bool valid;
+       int mux_idx;
+       int addr;
+       int bit;
+};
+
+struct Swizzle {
+       int addr_shift;
+       int addr_start;
+       int addr_end;
+       std::vector<int> addr_mux_bits;
+       std::vector<std::vector<SwizzleBit>> bits;
+};
+
+struct MemMapping {
+       MapWorker &worker;
+       QuickConeSat qcsat;
+       Mem &mem;
+       const Library &lib;
+       const PassOptions &opts;
+       std::vector<MemConfig> cfgs;
+       bool logic_ok;
+       double logic_cost;
+       RamKind kind;
+       std::string style;
+       dict<int, int> wr_en_cache;
+       dict<std::pair<int, int>, bool> wr_implies_rd_cache;
+       dict<std::pair<int, int>, bool> wr_excludes_rd_cache;
+       dict<std::pair<int, int>, bool> wr_excludes_srst_cache;
+
+       MemMapping(MapWorker &worker, Mem &mem, const Library &lib, const PassOptions &opts) : worker(worker), qcsat(worker.modwalker), mem(mem), lib(lib), opts(opts) {
+               determine_style();
+               logic_ok = determine_logic_ok();
+               if (GetSize(mem.wr_ports) == 0)
+                       logic_cost = mem.width * mem.size * opts.logic_cost_rom;
+               else
+                       logic_cost = mem.width * mem.size * opts.logic_cost_ram;
+               if (kind == RamKind::Logic)
+                       return;
+               for (int i = 0; i < GetSize(lib.rams); i++) {
+                       auto &rdef = lib.rams[i];
+                       if (!check_ram_kind(rdef))
+                               continue;
+                       if (!check_ram_style(rdef))
+                               continue;
+                       if (!check_init(rdef))
+                               continue;
+                       if (rdef.prune_rom && mem.wr_ports.empty())
+                               continue;
+                       MemConfig cfg;
+                       cfg.def = &rdef;
+                       for (auto &cdef: rdef.shared_clocks) {
+                               (void)cdef;
+                               SharedClockConfig clk;
+                               clk.used = false;
+                               cfg.shared_clocks.push_back(clk);
+                       }
+                       cfgs.push_back(cfg);
+               }
+               assign_wr_ports();
+               assign_rd_ports();
+               handle_trans();
+               // If we got this far, the memory is mappable.  The following two can require emulating
+               // some functionality, but cannot cause the mapping to fail.
+               handle_priority();
+               handle_rd_rst();
+               score_emu_ports();
+               // Now it is just a matter of picking geometry.
+               handle_geom();
+               dump_configs(0);
+               prune_post_geom();
+               dump_configs(1);
+       }
+
+       bool addr_compatible(int wpidx, int rpidx) {
+               auto &wport = mem.wr_ports[wpidx];
+               auto &rport = mem.rd_ports[rpidx];
+               int max_wide_log2 = std::max(rport.wide_log2, wport.wide_log2);
+               SigSpec raddr = rport.addr.extract_end(max_wide_log2);
+               SigSpec waddr = wport.addr.extract_end(max_wide_log2);
+               int abits = std::max(GetSize(raddr), GetSize(waddr));
+               raddr.extend_u0(abits);
+               waddr.extend_u0(abits);
+               return worker.sigmap_xmux(raddr) == worker.sigmap_xmux(waddr);
+       }
+
+       int get_wr_en(int wpidx) {
+               auto it = wr_en_cache.find(wpidx);
+               if (it != wr_en_cache.end())
+                       return it->second;
+               int res = qcsat.ez->expression(qcsat.ez->OpOr, qcsat.importSig(mem.wr_ports[wpidx].en));
+               wr_en_cache.insert({wpidx, res});
+               return res;
+       }
+
+       bool get_wr_implies_rd(int wpidx, int rpidx) {
+               auto key = std::make_pair(wpidx, rpidx);
+               auto it = wr_implies_rd_cache.find(key);
+               if (it != wr_implies_rd_cache.end())
+                       return it->second;
+               int wr_en = get_wr_en(wpidx);
+               int rd_en = qcsat.importSigBit(mem.rd_ports[rpidx].en[0]);
+               qcsat.prepare();
+               bool res = !qcsat.ez->solve(wr_en, qcsat.ez->NOT(rd_en));
+               wr_implies_rd_cache.insert({key, res});
+               return res;
+       }
+
+       bool get_wr_excludes_rd(int wpidx, int rpidx) {
+               auto key = std::make_pair(wpidx, rpidx);
+               auto it = wr_excludes_rd_cache.find(key);
+               if (it != wr_excludes_rd_cache.end())
+                       return it->second;
+               int wr_en = get_wr_en(wpidx);
+               int rd_en = qcsat.importSigBit(mem.rd_ports[rpidx].en[0]);
+               qcsat.prepare();
+               bool res = !qcsat.ez->solve(wr_en, rd_en);
+               wr_excludes_rd_cache.insert({key, res});
+               return res;
+       }
+
+       bool get_wr_excludes_srst(int wpidx, int rpidx) {
+               auto key = std::make_pair(wpidx, rpidx);
+               auto it = wr_excludes_srst_cache.find(key);
+               if (it != wr_excludes_srst_cache.end())
+                       return it->second;
+               int wr_en = get_wr_en(wpidx);
+               int srst = qcsat.importSigBit(mem.rd_ports[rpidx].srst);
+               if (mem.rd_ports[rpidx].ce_over_srst) {
+                       int rd_en = qcsat.importSigBit(mem.rd_ports[rpidx].en[0]);
+                       srst = qcsat.ez->AND(srst, rd_en);
+               }
+               qcsat.prepare();
+               bool res = !qcsat.ez->solve(wr_en, srst);
+               wr_excludes_srst_cache.insert({key, res});
+               return res;
+       }
+
+       void dump_configs(int stage);
+       void dump_config(MemConfig &cfg);
+       void determine_style();
+       bool determine_logic_ok();
+       bool check_ram_kind(const Ram &ram);
+       bool check_ram_style(const Ram &ram);
+       bool check_init(const Ram &ram);
+       void assign_wr_ports();
+       void assign_rd_ports();
+       void handle_trans();
+       void handle_priority();
+       void handle_rd_rst();
+       void score_emu_ports();
+       void handle_geom();
+       void prune_post_geom();
+       void emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, const PortVariant &pdef, const char *name, int wpidx, int rpidx, const std::vector<int> &hw_addr_swizzle);
+       void emit(const MemConfig &cfg);
+};
+
+void MemMapping::dump_configs(int stage) {
+       const char *stage_name;
+       switch (stage) {
+               case 0:
+                       stage_name = "post-geometry";
+                       break;
+               case 1:
+                       stage_name = "after post-geometry prune";
+                       break;
+               default:
+                       abort();
+       }
+       log_debug("Memory %s.%s mapping candidates (%s):\n", log_id(mem.module->name), log_id(mem.memid), stage_name);
+       if (logic_ok) {
+               log_debug("- logic fallback\n");
+               log_debug("  - cost: %f\n", logic_cost);
+       }
+       for (auto &cfg: cfgs) {
+               dump_config(cfg);
+       }
+}
+
+void MemMapping::dump_config(MemConfig &cfg) {
+       log_debug("- %s:\n", log_id(cfg.def->id));
+       for (auto &it: cfg.def->options)
+               log_debug("  - option %s %s\n", it.first.c_str(), log_const(it.second));
+       log_debug("  - emulation score: %d\n", cfg.score_emu);
+       log_debug("  - replicates (for ports): %d\n", cfg.repl_port);
+       log_debug("  - replicates (for data): %d\n", cfg.repl_d);
+       log_debug("  - mux score: %d\n", cfg.score_mux);
+       log_debug("  - demux score: %d\n", cfg.score_demux);
+       log_debug("  - cost: %f\n", cfg.cost);
+       std::stringstream os;
+       for (int x: cfg.def->dbits)
+               os << " " << x;
+       std::string dbits_s = os.str();
+       log_debug("  - abits %d dbits%s\n", cfg.def->abits, dbits_s.c_str());
+       if (cfg.def->byte != 0)
+               log_debug("  - byte width %d\n", cfg.def->byte);
+       log_debug("  - chosen base width %d\n", cfg.def->dbits[cfg.base_width_log2]);
+       os.str("");
+       for (int x: cfg.swizzle)
+               if (x == -1)
+                       os << " -";
+               else
+                       os << " " << x;
+       std::string swizzle_s = os.str();
+       log_debug("  - swizzle%s\n", swizzle_s.c_str());
+       os.str("");
+       for (int i = 0; (1 << i) <= cfg.hard_wide_mask; i++)
+               if (cfg.hard_wide_mask & 1 << i)
+                       os << " " << i;
+       std::string wide_s = os.str();
+       if (cfg.hard_wide_mask)
+               log_debug("  - hard wide bits%s\n", wide_s.c_str());
+       if (cfg.emu_read_first)
+               log_debug("  - emulate read-first behavior\n");
+       for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+               auto &pcfg = cfg.wr_ports[i];
+               if (pcfg.rd_port == -1)
+                       log_debug("  - write port %d: port group %s\n", i, cfg.def->port_groups[pcfg.port_group].names[0].c_str());
+               else
+                       log_debug("  - write port %d: port group %s (shared with read port %d)\n", i, cfg.def->port_groups[pcfg.port_group].names[0].c_str(), pcfg.rd_port);
+
+               for (auto &it: pcfg.def->options)
+                       log_debug("    - option %s %s\n", it.first.c_str(), log_const(it.second));
+               if (cfg.def->width_mode == WidthMode::PerPort) {
+                       std::stringstream os;
+                       for (int i = pcfg.def->min_wr_wide_log2; i <= pcfg.def->max_wr_wide_log2; i++)
+                               os << " " << cfg.def->dbits[i];
+                       std::string widths_s = os.str();
+                       const char *note = "";
+                       if (pcfg.rd_port != -1)
+                               note = pcfg.def->width_tied ? " (tied)" : " (independent)";
+                       log_debug("    - widths%s%s\n", widths_s.c_str(), note);
+               }
+               for (auto i: pcfg.emu_prio)
+                       log_debug("    - emulate priority over write port %d\n", i);
+       }
+       for (int i = 0; i < GetSize(mem.rd_ports); i++) {
+               auto &pcfg = cfg.rd_ports[i];
+               if (pcfg.wr_port == -1)
+                       log_debug("  - read port %d: port group %s\n", i, cfg.def->port_groups[pcfg.port_group].names[0].c_str());
+               else
+                       log_debug("  - read port %d: port group %s (shared with write port %d)\n", i, cfg.def->port_groups[pcfg.port_group].names[0].c_str(), pcfg.wr_port);
+               for (auto &it: pcfg.def->options)
+                       log_debug("    - option %s %s\n", it.first.c_str(), log_const(it.second));
+               if (cfg.def->width_mode == WidthMode::PerPort) {
+                       std::stringstream os;
+                       for (int i = pcfg.def->min_rd_wide_log2; i <= pcfg.def->max_rd_wide_log2; i++)
+                               os << " " << cfg.def->dbits[i];
+                       std::string widths_s = os.str();
+                       const char *note = "";
+                       if (pcfg.wr_port != -1)
+                               note = pcfg.def->width_tied ? " (tied)" : " (independent)";
+                       log_debug("    - widths%s%s\n", widths_s.c_str(), note);
+               }
+               if (pcfg.emu_sync)
+                       log_debug("    - emulate data register\n");
+               if (pcfg.emu_en)
+                       log_debug("    - emulate clock enable\n");
+               if (pcfg.emu_arst)
+                       log_debug("    - emulate async reset\n");
+               if (pcfg.emu_srst)
+                       log_debug("    - emulate sync reset\n");
+               if (pcfg.emu_init)
+                       log_debug("    - emulate init value\n");
+               if (pcfg.emu_srst_en_prio)
+                       log_debug("    - emulate sync reset / enable priority\n");
+               for (auto i: pcfg.emu_trans)
+                       log_debug("    - emulate transparency with write port %d\n", i);
+       }
+}
+
+// Go through memory attributes to determine user-requested mapping style.
+void MemMapping::determine_style() {
+       kind = RamKind::Auto;
+       style = "";
+       if (mem.get_bool_attribute(ID::lram)) {
+               kind = RamKind::Huge;
+               return;
+       }
+       for (auto attr: {ID::ram_block, ID::rom_block, ID::ram_style, ID::rom_style, ID::ramstyle, ID::romstyle, ID::syn_ramstyle, ID::syn_romstyle}) {
+               if (mem.has_attribute(attr)) {
+                       Const val = mem.attributes.at(attr);
+                       if (val == 1) {
+                               kind = RamKind::NotLogic;
+                               return;
+                       }
+                       std::string val_s = val.decode_string();
+                       for (auto &c: val_s)
+                               c = std::tolower(c);
+                       if (val_s == "auto") {
+                               // Nothing.
+                       } else if (val_s == "logic" || val_s == "registers") {
+                               kind = RamKind::Logic;
+                       } else if (val_s == "distributed") {
+                               kind = RamKind::Distributed;
+                       } else if (val_s == "block" || val_s == "block_ram" || val_s == "ebr") {
+                               kind = RamKind::Block;
+                       } else if (val_s == "huge" || val_s == "ultra") {
+                               kind = RamKind::Huge;
+                       } else {
+                               kind = RamKind::NotLogic;
+                               style = val_s;
+                       }
+                       return;
+               }
+       }
+       if (mem.get_bool_attribute(ID::logic_block))
+               kind = RamKind::Logic;
+}
+
+// Determine whether the memory can be mapped entirely to soft logic.
+bool MemMapping::determine_logic_ok() {
+       if (kind != RamKind::Auto && kind != RamKind::Logic)
+               return false;
+       // Memory is mappable entirely to soft logic iff all its write ports are in the same clock domain.
+       if (mem.wr_ports.empty())
+               return true;
+       for (auto &port: mem.wr_ports) {
+               if (!port.clk_enable)
+                       return false;
+               if (port.clk != mem.wr_ports[0].clk)
+                       return false;
+               if (port.clk_polarity != mem.wr_ports[0].clk_polarity)
+                       return false;
+       }
+       return true;
+}
+
+// Apply RAM kind restrictions (logic/distributed/block/huge), if any.
+bool MemMapping::check_ram_kind(const Ram &ram) {
+       if (style != "")
+               return true;
+       if (ram.kind == kind)
+               return true;
+       if (kind == RamKind::Auto || kind == RamKind::NotLogic) {
+               if (ram.kind == RamKind::Distributed && opts.no_auto_distributed)
+                       return false;
+               if (ram.kind == RamKind::Block && opts.no_auto_block)
+                       return false;
+               if (ram.kind == RamKind::Huge && opts.no_auto_huge)
+                       return false;
+               return true;
+       }
+       return false;
+}
+
+// Apply specific RAM style restrictions, if any.
+bool MemMapping::check_ram_style(const Ram &ram) {
+       if (style == "")
+               return true;
+       for (auto &s: ram.style)
+               if (s == style)
+                       return true;
+       return false;
+}
+
+// Handle memory initializer restrictions, if any.
+bool MemMapping::check_init(const Ram &ram) {
+       bool has_nonx = false;
+       bool has_one = false;
+
+       for (auto &init: mem.inits) {
+               if (init.data.is_fully_undef())
+                       continue;
+               has_nonx = true;
+               for (auto bit: init.data)
+                       if (bit == State::S1)
+                               has_one = true;
+       }
+
+       switch (ram.init) {
+               case MemoryInitKind::None:
+                       return !has_nonx;
+               case MemoryInitKind::Zero:
+                       return !has_one;
+               default:
+                       return true;
+       }
+}
+
+bool apply_clock(MemConfig &cfg, const PortVariant &def, SigBit clk, bool clk_polarity) {
+       if (def.clk_shared == -1)
+               return true;
+       auto &cdef = cfg.def->shared_clocks[def.clk_shared];
+       auto &ccfg = cfg.shared_clocks[def.clk_shared];
+       if (cdef.anyedge) {
+               if (!ccfg.used) {
+                       ccfg.used = true;
+                       ccfg.clk = clk;
+                       ccfg.polarity = clk_polarity;
+                       return true;
+               } else {
+                       return ccfg.clk == clk && ccfg.polarity == clk_polarity;
+               }
+       } else {
+               bool invert = clk_polarity ^ (def.clk_pol == ClkPolKind::Posedge);
+               if (!ccfg.used) {
+                       ccfg.used = true;
+                       ccfg.clk = clk;
+                       ccfg.invert = invert;
+                       return true;
+               } else {
+                       return ccfg.clk == clk && ccfg.invert == invert;
+               }
+       }
+}
+
+// Perform write port assignment, validating clock options as we go.
+void MemMapping::assign_wr_ports() {
+       for (auto &port: mem.wr_ports) {
+               if (!port.clk_enable) {
+                       // Async write ports not supported.
+                       cfgs.clear();
+                       return;
+               }
+               MemConfigs new_cfgs;
+               for (auto &cfg: cfgs) {
+                       for (int pgi = 0; pgi < GetSize(cfg.def->port_groups); pgi++) {
+                               auto &pg = cfg.def->port_groups[pgi];
+                               // Make sure the target port group still has a free port.
+                               int used = 0;
+                               for (auto &oport: cfg.wr_ports)
+                                       if (oport.port_group == pgi)
+                                               used++;
+                               if (used >= GetSize(pg.names))
+                                       continue;
+                               for (int pvi = 0; pvi < GetSize(pg.variants); pvi++) {
+                                       auto &def = pg.variants[pvi];
+                                       // Make sure the target is a write port.
+                                       if (def.kind == PortKind::Ar || def.kind == PortKind::Sr)
+                                               continue;
+                                       MemConfig new_cfg = cfg;
+                                       WrPortConfig pcfg;
+                                       pcfg.rd_port = -1;
+                                       pcfg.port_group = pgi;
+                                       pcfg.port_variant = pvi;
+                                       pcfg.def = &def;
+                                       if (!apply_clock(new_cfg, def, port.clk, port.clk_polarity))
+                                               continue;
+                                       new_cfg.wr_ports.push_back(pcfg);
+                                       new_cfgs.push_back(new_cfg);
+                               }
+                       }
+               }
+               cfgs = new_cfgs;
+       }
+}
+
+// Perform read port assignment, validating clock and rden options as we go.
+void MemMapping::assign_rd_ports() {
+       for (int pidx = 0; pidx < GetSize(mem.rd_ports); pidx++) {
+               auto &port = mem.rd_ports[pidx];
+               MemConfigs new_cfgs;
+               for (auto &cfg: cfgs) {
+                       // First pass: read port not shared with a write port.
+                       for (int pgi = 0; pgi < GetSize(cfg.def->port_groups); pgi++) {
+                               auto &pg = cfg.def->port_groups[pgi];
+                               // Make sure the target port group has a port not used up by write ports.
+                               // Overuse by other read ports is not a problem â€” this will just result
+                               // in memory duplication.
+                               int used = 0;
+                               for (auto &oport: cfg.wr_ports)
+                                       if (oport.port_group == pgi)
+                                               used++;
+                               if (used >= GetSize(pg.names))
+                                       continue;
+                               for (int pvi = 0; pvi < GetSize(pg.variants); pvi++) {
+                                       auto &def = pg.variants[pvi];
+                                       // Make sure the target is a read port.
+                                       if (def.kind == PortKind::Sw)
+                                               continue;
+                                       // If mapping an async port, accept only async defs.
+                                       if (!port.clk_enable) {
+                                               if (def.kind == PortKind::Sr || def.kind == PortKind::Srsw)
+                                                       continue;
+                                       }
+                                       MemConfig new_cfg = cfg;
+                                       RdPortConfig pcfg;
+                                       pcfg.wr_port = -1;
+                                       pcfg.port_group = pgi;
+                                       pcfg.port_variant = pvi;
+                                       pcfg.def = &def;
+                                       if (def.kind == PortKind::Sr || def.kind == PortKind::Srsw) {
+                                               pcfg.emu_sync = false;
+                                               if (!apply_clock(new_cfg, def, port.clk, port.clk_polarity))
+                                                       continue;
+                                               // Decide if rden is usable.
+                                               if (port.en != State::S1) {
+                                                       if (def.clk_en) {
+                                                               pcfg.rd_en_to_clk_en = true;
+                                                       } else {
+                                                               pcfg.emu_en = !def.rd_en;
+                                                       }
+                                               }
+                                       } else {
+                                               pcfg.emu_sync = port.clk_enable;
+                                       }
+                                       new_cfg.rd_ports.push_back(pcfg);
+                                       new_cfgs.push_back(new_cfg);
+                               }
+                       }
+                       // Second pass: read port shared with a write port.
+                       for (int wpidx = 0; wpidx < GetSize(mem.wr_ports); wpidx++) {
+                               auto &wport = mem.wr_ports[wpidx];
+                               auto &wpcfg = cfg.wr_ports[wpidx];
+                               auto &def = *wpcfg.def;
+                               // Make sure the write port is not yet shared.
+                               if (wpcfg.rd_port != -1)
+                                       continue;
+                               // Make sure the target is a read port.
+                               if (def.kind == PortKind::Sw)
+                                       continue;
+                               // Validate address compatibility.
+                               if (!addr_compatible(wpidx, pidx))
+                                       continue;
+                               // Validate clock compatibility, if needed.
+                               if (def.kind == PortKind::Srsw) {
+                                       if (!port.clk_enable)
+                                               continue;
+                                       if (port.clk != wport.clk)
+                                               continue;
+                                       if (port.clk_polarity != wport.clk_polarity)
+                                               continue;
+                               }
+                               // Okay, let's fill it in.
+                               MemConfig new_cfg = cfg;
+                               new_cfg.wr_ports[wpidx].rd_port = pidx;
+                               RdPortConfig pcfg;
+                               pcfg.wr_port = wpidx;
+                               pcfg.port_group = wpcfg.port_group;
+                               pcfg.port_variant = wpcfg.port_variant;
+                               pcfg.def = wpcfg.def;
+                               pcfg.emu_sync = port.clk_enable && def.kind == PortKind::Arsw;
+                               // For srsw, check rden capability.
+                               if (def.kind == PortKind::Srsw) {
+                                       bool trans = port.transparency_mask[wpidx];
+                                       bool col_x = port.collision_x_mask[wpidx];
+                                       if (def.rdwr == RdWrKind::NoChange) {
+                                               if (!get_wr_excludes_rd(wpidx, pidx)) {
+                                                       if (!trans && !col_x)
+                                                               continue;
+                                                       if (trans)
+                                                               pcfg.emu_trans.push_back(wpidx);
+                                                       new_cfg.wr_ports[wpidx].force_uniform = true;
+                                               }
+                                               if (port.en != State::S1) {
+                                                       if (def.clk_en) {
+                                                               pcfg.rd_en_to_clk_en = true;
+                                                       } else {
+                                                               pcfg.emu_en = !def.rd_en;
+                                                       }
+                                               }
+                                       } else {
+                                               if (!col_x && !trans && def.rdwr != RdWrKind::Old)
+                                                       continue;
+                                               if (trans) {
+                                                       if (def.rdwr != RdWrKind::New && def.rdwr != RdWrKind::NewOnly)
+                                                               pcfg.emu_trans.push_back(wpidx);
+                                               }
+                                               if (def.rdwr == RdWrKind::NewOnly) {
+                                                       if (!get_wr_excludes_rd(wpidx, pidx))
+                                                               new_cfg.wr_ports[wpidx].force_uniform = true;
+                                               }
+                                               if (port.en != State::S1) {
+                                                       if (def.clk_en) {
+                                                               if (get_wr_implies_rd(wpidx, pidx)) {
+                                                                       pcfg.rd_en_to_clk_en = true;
+                                                               } else {
+                                                                       pcfg.emu_en = !def.rd_en;
+                                                               }
+                                                       } else {
+                                                               pcfg.emu_en = !def.rd_en;
+                                                       }
+                                               }
+                                       }
+                               }
+                               new_cfg.rd_ports.push_back(pcfg);
+                               new_cfgs.push_back(new_cfg);
+                       }
+               }
+               cfgs = new_cfgs;
+       }
+}
+
+// Validate transparency restrictions, determine where to add soft transparency logic.
+void MemMapping::handle_trans() {
+       if (mem.emulate_read_first_ok()) {
+               MemConfigs new_cfgs;
+               for (auto &cfg: cfgs) {
+                       new_cfgs.push_back(cfg);
+                       bool ok = true;
+                       // Using this trick will break read-write port sharing.
+                       for (auto &pcfg: cfg.rd_ports)
+                               if (pcfg.wr_port != -1)
+                                       ok = false;
+                       if (ok) {
+                               cfg.emu_read_first = true;
+                               new_cfgs.push_back(cfg);
+                       }
+               }
+               cfgs = new_cfgs;
+       }
+       for (int rpidx = 0; rpidx < GetSize(mem.rd_ports); rpidx++) {
+               auto &rport = mem.rd_ports[rpidx];
+               if (!rport.clk_enable)
+                       continue;
+               for (int wpidx = 0; wpidx < GetSize(mem.wr_ports); wpidx++) {
+                       auto &wport = mem.wr_ports[wpidx];
+                       if (!wport.clk_enable)
+                               continue;
+                       if (rport.clk != wport.clk)
+                               continue;
+                       if (rport.clk_polarity != wport.clk_polarity)
+                               continue;
+                       // If we got this far, we have a transparency restriction
+                       // to uphold.
+                       MemConfigs new_cfgs;
+                       for (auto &cfg: cfgs) {
+                               auto &rpcfg = cfg.rd_ports[rpidx];
+                               auto &wpcfg = cfg.wr_ports[wpidx];
+                               // The transparency relation for shared ports already handled while assigning them.
+                               if (rpcfg.wr_port == wpidx) {
+                                       new_cfgs.push_back(cfg);
+                                       continue;
+                               }
+                               if (rport.collision_x_mask[wpidx] && !cfg.emu_read_first) {
+                                       new_cfgs.push_back(cfg);
+                                       continue;
+                               }
+                               bool transparent = rport.transparency_mask[wpidx] || cfg.emu_read_first;
+                               if (rpcfg.emu_sync) {
+                                       // For async read port, just add the transparency logic
+                                       // if necessary.
+                                       if (transparent)
+                                               rpcfg.emu_trans.push_back(wpidx);
+                                       new_cfgs.push_back(cfg);
+                               } else {
+                                       // Otherwise, split through the relevant wrtrans caps.
+                                       // For non-transparent ports, the cap needs to be present.
+                                       // For transparent ports, we can emulate transparency
+                                       // even without a direct cap.
+                                       bool found = false;
+                                       for (auto &tdef: wpcfg.def->wrtrans) {
+                                               // Check if the target matches.
+                                               if (tdef.target_kind == WrTransTargetKind::Group && rpcfg.port_group != tdef.target_group)
+                                                       continue;
+                                               // Check if the transparency kind is acceptable.
+                                               if (transparent) {
+                                                       if (tdef.kind == WrTransKind::Old)
+                                                               continue;
+                                               } else {
+                                                       if (tdef.kind != WrTransKind::Old)
+                                                               continue;
+                                               }
+                                               // Okay, we can use this cap.
+                                               new_cfgs.push_back(cfg);
+                                               found = true;
+                                               break;
+                                       }
+                                       if (!found && transparent) {
+                                               // If the port pair is transparent, but no cap was
+                                               // found, use emulation.
+                                               rpcfg.emu_trans.push_back(wpidx);
+                                               new_cfgs.push_back(cfg);
+                                       }
+                               }
+                       }
+                       cfgs = new_cfgs;
+               }
+       }
+}
+
+// Determine where to add soft priority logic.
+void MemMapping::handle_priority() {
+       for (int p1idx = 0; p1idx < GetSize(mem.wr_ports); p1idx++) {
+               for (int p2idx = 0; p2idx < GetSize(mem.wr_ports); p2idx++) {
+                       auto &port2 = mem.wr_ports[p2idx];
+                       if (!port2.priority_mask[p1idx])
+                               continue;
+                       for (auto &cfg: cfgs) {
+                               auto &p1cfg = cfg.rd_ports[p1idx];
+                               auto &p2cfg = cfg.wr_ports[p2idx];
+                               bool found = false;
+                               for (auto &pgi: p2cfg.def->wrprio) {
+                                       if (pgi == p1cfg.port_group) {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               // If no cap was found, emulate.
+                               if (!found)
+                                       p2cfg.emu_prio.push_back(p1idx);
+                       }
+               }
+       }
+}
+
+bool is_all_zero(const Const &val) {
+       for (auto bit: val.bits)
+               if (bit == State::S1)
+                       return false;
+       return true;
+}
+
+// Determine where to add soft init value / reset logic.
+void MemMapping::handle_rd_rst() {
+       for (auto &cfg: cfgs) {
+               for (int pidx = 0; pidx < GetSize(mem.rd_ports); pidx++) {
+                       auto &port = mem.rd_ports[pidx];
+                       auto &pcfg = cfg.rd_ports[pidx];
+                       // Only sync ports are relevant.
+                       // If emulated by async port or we already emulate CE, init will be
+                       // included for free.
+                       if (!port.clk_enable || pcfg.emu_sync || pcfg.emu_en)
+                               continue;
+                       switch (pcfg.def->rdinitval) {
+                               case ResetValKind::None:
+                                       pcfg.emu_init = !port.init_value.is_fully_undef();
+                                       break;
+                               case ResetValKind::Zero:
+                                       pcfg.emu_init = !is_all_zero(port.init_value);
+                                       break;
+                               default:
+                                       break;
+                       }
+                       Const init_val = port.init_value;
+                       if (port.arst != State::S0) {
+                               switch (pcfg.def->rdarstval) {
+                                       case ResetValKind::None:
+                                               pcfg.emu_arst = true;
+                                               break;
+                                       case ResetValKind::Zero:
+                                               pcfg.emu_arst = !is_all_zero(port.arst_value);
+                                               break;
+                                       case ResetValKind::Init:
+                                               if (init_val.is_fully_undef())
+                                                       init_val = port.arst_value;
+                                               pcfg.emu_arst = init_val != port.arst_value;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                       }
+                       if (port.srst != State::S0) {
+                               switch (pcfg.def->rdsrstval) {
+                                       case ResetValKind::None:
+                                               pcfg.emu_srst = true;
+                                               break;
+                                       case ResetValKind::Zero:
+                                               pcfg.emu_srst = !is_all_zero(port.srst_value);
+                                               break;
+                                       case ResetValKind::Init:
+                                               if (init_val.is_fully_undef())
+                                                       init_val = port.srst_value;
+                                               pcfg.emu_srst = init_val != port.srst_value;
+                                               break;
+                                       default:
+                                               break;
+                               }
+                               if (!pcfg.emu_srst && pcfg.def->rdsrst_block_wr && pcfg.wr_port != -1) {
+                                       if (!get_wr_excludes_srst(pcfg.wr_port, pidx))
+                                               pcfg.emu_srst = true;
+                               }
+                               if (!pcfg.emu_srst && port.en != State::S1) {
+                                       if (port.ce_over_srst) {
+                                               switch (pcfg.def->rdsrstmode) {
+                                                       case SrstKind::Ungated:
+                                                               pcfg.emu_srst_en_prio = true;
+                                                               break;
+                                                       case SrstKind::GatedClkEn:
+                                                               pcfg.emu_srst_en_prio = !pcfg.rd_en_to_clk_en;
+                                                               break;
+                                                       case SrstKind::GatedRdEn:
+                                                               break;
+                                                       default:
+                                                               log_assert(0);
+                                               }
+                                       } else {
+                                               switch (pcfg.def->rdsrstmode) {
+                                                       case SrstKind::Ungated:
+                                                               break;
+                                                       case SrstKind::GatedClkEn:
+                                                               if (pcfg.rd_en_to_clk_en) {
+                                                                       if (pcfg.def->rd_en) {
+                                                                               pcfg.rd_en_to_clk_en = false;
+                                                                       } else {
+                                                                               pcfg.emu_srst_en_prio = true;
+                                                                       }
+                                                               }
+                                                               break;
+                                                       case SrstKind::GatedRdEn:
+                                                               pcfg.emu_srst_en_prio = true;
+                                                               break;
+                                                       default:
+                                                               log_assert(0);
+                                               }
+                                       }
+                               }
+                       } else {
+                               if (pcfg.def->rd_en && pcfg.def->rdwr == RdWrKind::NoChange && pcfg.wr_port != -1) {
+                                       pcfg.rd_en_to_clk_en = false;
+                               }
+                       }
+               }
+       }
+}
+
+void MemMapping::score_emu_ports() {
+       for (auto &cfg: cfgs) {
+               std::vector<int> port_usage_wr(cfg.def->port_groups.size());
+               std::vector<int> port_usage_rd(cfg.def->port_groups.size());
+               int score = 0;
+               // 3 points for every write port if we need to do read-first emulation.
+               if (cfg.emu_read_first)
+                       score += 3 * GetSize(cfg.wr_ports);
+               for (auto &pcfg: cfg.wr_ports) {
+                       // 1 point for every priority relation we need to fix up.
+                       // This is just a gate for every distinct wren pair.
+                       score += GetSize(pcfg.emu_prio);
+                       port_usage_wr[pcfg.port_group]++;
+               }
+               for (auto &pcfg: cfg.rd_ports) {
+                       // 3 points for every soft transparency logic instance.  This involves
+                       // registers and other major mess.
+                       score += 3 * GetSize(pcfg.emu_trans);
+                       // 3 points for CE soft logic.  Likewise involves registers.
+                       // If we already do this, subsumes any init/srst/arst emulation.
+                       if (pcfg.emu_en)
+                               score += 3;
+                       // 2 points for soft init value / reset logic: involves single bit
+                       // register and some muxes.
+                       if (pcfg.emu_init)
+                               score += 2;
+                       if (pcfg.emu_arst)
+                               score += 2;
+                       if (pcfg.emu_srst)
+                               score += 2;
+                       // 1 point for wrong srst/en priority (fixed with a single gate).
+                       if (pcfg.emu_srst_en_prio)
+                               score++;
+                       // 1 point for every non-shared read port used, as a tiebreaker
+                       // to prefer single-port configs.
+                       if (pcfg.wr_port == -1) {
+                               score++;
+                               port_usage_rd[pcfg.port_group]++;
+                       }
+               }
+               cfg.score_emu = score;
+               int repl_port = 1;
+               for (int i = 0; i < GetSize(cfg.def->port_groups); i++) {
+                       int space = GetSize(cfg.def->port_groups[i].names) - port_usage_wr[i];
+                       log_assert(space >= 0);
+                       if (port_usage_rd[i] > 0) {
+                               log_assert(space > 0);
+                               int usage = port_usage_rd[i];
+                               int cur = (usage + space - 1) / space;
+                               if (cur > repl_port)
+                                       repl_port = cur;
+                       }
+               }
+               cfg.repl_port = repl_port;
+       }
+}
+
+void MemMapping::handle_geom() {
+       std::vector<int> wren_size;
+       for (auto &port: mem.wr_ports) {
+               SigSpec en = port.en;
+               en.sort_and_unify();
+               wren_size.push_back(GetSize(en));
+       }
+       for (auto &cfg: cfgs) {
+               // First, create a set of "byte boundaries": the bit positions in source memory word
+               // that have write enable different from the previous bit in any write port.
+               // Bit 0 is considered to be a byte boundary as well.
+               // Likewise, create a set of "word boundaries" that are like above, but only for write ports
+               // with the "force uniform" flag set.
+               std::vector<bool> byte_boundary(mem.width, false);
+               std::vector<bool> word_boundary(mem.width, false);
+               byte_boundary[0] = true;
+               for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) {
+                       auto &port = mem.wr_ports[pidx];
+                       auto &pcfg = cfg.wr_ports[pidx];
+                       if (pcfg.force_uniform)
+                               word_boundary[0] = true;
+                       for (int sub = 0; sub < (1 << port.wide_log2); sub++) {
+                               for (int i = 1; i < mem.width; i++) {
+                                       int pos = sub * mem.width + i;
+                                       if (port.en[pos] != port.en[pos-1]) {
+                                               byte_boundary[i] = true;
+                                               if (pcfg.force_uniform)
+                                                       word_boundary[i] = true;
+                                       }
+                               }
+                       }
+               }
+               bool got_config = false;
+               int best_cost = 0;
+               int byte_width_log2 = 0;
+               for (int i = 0; i < GetSize(cfg.def->dbits); i++)
+                       if (cfg.def->byte >= cfg.def->dbits[i])
+                               byte_width_log2 = i;
+               if (cfg.def->byte == 0)
+                       byte_width_log2 = GetSize(cfg.def->dbits) - 1;
+               pool<int> no_wide_bits;
+               // Determine which of the source address bits involved in wide ports
+               // are "uniform".  Bits are considered uniform if, when a port is widened through
+               // them, the write enables are the same for both values of the bit.
+               int max_wr_wide_log2 = 0;
+               for (auto &port: mem.wr_ports)
+                       if (port.wide_log2 > max_wr_wide_log2)
+                               max_wr_wide_log2 = port.wide_log2;
+               int max_wide_log2 = max_wr_wide_log2;
+               for (auto &port: mem.rd_ports)
+                       if (port.wide_log2 > max_wide_log2)
+                               max_wide_log2 = port.wide_log2;
+               int wide_nu_start = max_wide_log2;
+               int wide_nu_end = max_wr_wide_log2;
+               for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+                       auto &port = mem.wr_ports[i];
+                       auto &pcfg = cfg.wr_ports[i];
+                       for (int j = 0; j < port.wide_log2; j++) {
+                               bool uniform = true;
+                               // If write enables don't match, mark bit as non-uniform.
+                               for (int k = 0; k < (1 << port.wide_log2); k += 2 << j)
+                                       if (port.en.extract(k * mem.width, mem.width << j) != port.en.extract((k + (1 << j)) * mem.width, mem.width << j))
+                                               uniform = false;
+                               if (!uniform) {
+                                       if (pcfg.force_uniform) {
+                                               for (int k = j; k < port.wide_log2; k++)
+                                                       no_wide_bits.insert(k);
+                                       }
+                                       if (j < wide_nu_start)
+                                               wide_nu_start = j;
+                                       break;
+                               }
+                       }
+                       if (pcfg.def->width_tied && pcfg.rd_port != -1) {
+                               // If:
+                               //
+                               // - the write port is merged with a read port
+                               // - the read port is wider than the write port
+                               // - read and write widths are tied
+                               //
+                               // then we will have to artificially widen the write
+                               // port to the width of the read port, and emulate
+                               // a narrower write path by use of write enables,
+                               // which will definitely be non-uniform over the added
+                               // bits.
+                               auto &rport = mem.rd_ports[pcfg.rd_port];
+                               if (rport.wide_log2 > port.wide_log2) {
+                                       if (port.wide_log2 < wide_nu_start)
+                                               wide_nu_start = port.wide_log2;
+                                       if (rport.wide_log2 > wide_nu_end)
+                                               wide_nu_end = rport.wide_log2;
+                                       if (pcfg.force_uniform) {
+                                               for (int k = port.wide_log2; k < rport.wide_log2; k++)
+                                                       no_wide_bits.insert(k);
+                                       }
+                               }
+                       }
+               }
+               // Iterate over base widths.
+               for (int base_width_log2 = 0; base_width_log2 < GetSize(cfg.def->dbits); base_width_log2++) {
+                       // Now, see how many data bits we actually have available.
+                       // This is usually dbits[base_width_log2], but could be smaller if we
+                       // ran afoul of a max width limitation.  Configurations where this
+                       // happens are not useful, unless we need it to satisfy a *minimum*
+                       // width limitation.
+                       int unit_width_log2 = base_width_log2;
+                       for (auto &pcfg: cfg.wr_ports)
+                               if (unit_width_log2 > pcfg.def->max_wr_wide_log2)
+                                       unit_width_log2 = pcfg.def->max_wr_wide_log2;
+                       for (auto &pcfg: cfg.rd_ports)
+                               if (unit_width_log2 > pcfg.def->max_rd_wide_log2)
+                                       unit_width_log2 = pcfg.def->max_rd_wide_log2;
+                       if (unit_width_log2 != base_width_log2 && got_config)
+                               break;
+                       int unit_width = cfg.def->dbits[unit_width_log2];
+                       // Also determine effective byte width (the granularity of write enables).
+                       int effective_byte = cfg.def->byte;
+                       if (effective_byte == 0 || effective_byte > unit_width)
+                               effective_byte = unit_width;
+                       if (mem.wr_ports.empty())
+                               effective_byte = 1;
+                       log_assert(unit_width % effective_byte == 0);
+                       // Create the swizzle pattern.
+                       std::vector<int> swizzle;
+                       for (int i = 0; i < mem.width; i++) {
+                               if (word_boundary[i])
+                                       while (GetSize(swizzle) % unit_width)
+                                               swizzle.push_back(-1);
+                               else if (byte_boundary[i])
+                                       while (GetSize(swizzle) % effective_byte)
+                                               swizzle.push_back(-1);
+                               swizzle.push_back(i);
+                       }
+                       if (word_boundary[0])
+                               while (GetSize(swizzle) % unit_width)
+                                       swizzle.push_back(-1);
+                       else
+                               while (GetSize(swizzle) % effective_byte)
+                                       swizzle.push_back(-1);
+                       // Now evaluate the configuration, then keep adding more hard wide bits
+                       // and evaluating.
+                       int hard_wide_mask = 0;
+                       int hard_wide_num = 0;
+                       bool byte_failed = false;
+                       while (1) {
+                               // Check if all min width constraints are satisfied.
+                               // Only check these constraints for write ports with width below
+                               // byte width â€” for other ports, we can emulate narrow width with
+                               // a larger one.
+                               bool min_width_ok = true;
+                               int min_width_bit = wide_nu_start;
+                               for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) {
+                                       auto &port = mem.wr_ports[pidx];
+                                       int w = base_width_log2;
+                                       for (int i = 0; i < port.wide_log2; i++)
+                                               if (hard_wide_mask & 1 << i)
+                                                       w++;
+                                       if (w < cfg.wr_ports[pidx].def->min_wr_wide_log2 && w < byte_width_log2) {
+                                               min_width_ok = false;
+                                               if (min_width_bit > port.wide_log2)
+                                                       min_width_bit = port.wide_log2;
+                                       }
+                               }
+                               if (min_width_ok) {
+                                       int emu_wide_bits = max_wide_log2 - hard_wide_num;
+                                       int mult_wide = 1 << emu_wide_bits;
+                                       int addrs = 1 << (cfg.def->abits - base_width_log2 + emu_wide_bits);
+                                       int min_addr = mem.start_offset / addrs;
+                                       int max_addr = (mem.start_offset + mem.size - 1) / addrs;
+                                       int mult_a = max_addr - min_addr + 1;
+                                       int bits = mult_a * mult_wide * GetSize(swizzle);
+                                       int repl = (bits + unit_width - 1) / unit_width;
+                                       int score_demux = 0;
+                                       for (int i = 0; i < GetSize(mem.wr_ports); i++) {
+                                               auto &port = mem.wr_ports[i];
+                                               int w = emu_wide_bits;
+                                               for (int i = 0; i < port.wide_log2; i++)
+                                                       if (!(hard_wide_mask & 1 << i))
+                                                               w--;
+                                               if (w || mult_a != 1)
+                                                       score_demux += (mult_a << w) * wren_size[i];
+                                       }
+                                       int score_mux = 0;
+                                       for (auto &port: mem.rd_ports) {
+                                               int w = emu_wide_bits;
+                                               for (int i = 0; i < port.wide_log2; i++)
+                                                       if (!(hard_wide_mask & 1 << i))
+                                                               w--;
+                                               score_mux += ((mult_a << w) - 1) * GetSize(port.data);
+                                       }
+                                       double cost = (cfg.def->cost - cfg.def->widthscale) * repl * cfg.repl_port;
+                                       cost += cfg.def->widthscale * mult_a * mult_wide * mem.width / unit_width * cfg.repl_port;
+                                       cost += score_mux * FACTOR_MUX;
+                                       cost += score_demux * FACTOR_DEMUX;
+                                       cost += cfg.score_emu * FACTOR_EMU;
+                                       if (!got_config || cost < best_cost) {
+                                               cfg.base_width_log2 = base_width_log2;
+                                               cfg.unit_width_log2 = unit_width_log2;
+                                               cfg.swizzle = swizzle;
+                                               cfg.hard_wide_mask = hard_wide_mask;
+                                               cfg.emu_wide_mask = ((1 << max_wide_log2) - 1) & ~hard_wide_mask;
+                                               cfg.repl_d = repl;
+                                               cfg.score_demux = score_demux;
+                                               cfg.score_mux = score_mux;
+                                               cfg.cost = cost;
+                                               best_cost = cost;
+                                               got_config = true;
+                                       }
+                               }
+                               if (cfg.def->width_mode != WidthMode::PerPort)
+                                       break;
+                               // Now, pick the next bit to add to the hard wide mask.
+next_hw:
+                               int scan_from;
+                               int scan_to;
+                               bool retry = false;
+                               if (!min_width_ok) {
+                                       // If we still haven't met the minimum width limits,
+                                       // add the highest one that will be useful for working
+                                       // towards all unmet limits.
+                                       scan_from = min_width_bit;
+                                       scan_to = 0;
+                                       // If the relevant write port is not wide, it's impossible.
+                               } else if (byte_failed) {
+                                       // If we already failed with uniformly-written bits only,
+                                       // go with uniform bits that are only involved in reads.
+                                       scan_from = max_wide_log2;
+                                       scan_to = wide_nu_end;
+                               } else if (base_width_log2 + hard_wide_num < byte_width_log2) {
+                                       // If we still need uniform bits, prefer the low ones.
+                                       scan_from = wide_nu_start;
+                                       scan_to = 0;
+                                       retry = true;
+                               } else {
+                                       scan_from = max_wide_log2;
+                                       scan_to = 0;
+                               }
+                               int bit = scan_from - 1;
+                               while (1) {
+                                       if (bit < scan_to) {
+hw_bit_failed:
+                                               if (retry) {
+                                                       byte_failed = true;
+                                                       goto next_hw;
+                                               } else {
+                                                       goto bw_done;
+                                               }
+                                       }
+                                       if (!(hard_wide_mask & 1 << bit) && !no_wide_bits.count(bit))
+                                               break;
+                                       bit--;
+                               }
+                               int new_hw_mask = hard_wide_mask | 1 << bit;
+                               // Check if all max width constraints are satisfied.
+                               for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) {
+                                       auto &port = mem.wr_ports[pidx];
+                                       int w = base_width_log2;
+                                       for (int i = 0; i < port.wide_log2; i++)
+                                               if (new_hw_mask & 1 << i)
+                                                       w++;
+                                       if (w > cfg.wr_ports[pidx].def->max_wr_wide_log2) {
+                                               goto hw_bit_failed;
+                                       }
+                               }
+                               for (int pidx = 0; pidx < GetSize(mem.rd_ports); pidx++) {
+                                       auto &port = mem.rd_ports[pidx];
+                                       int w = base_width_log2;
+                                       for (int i = 0; i < port.wide_log2; i++)
+                                               if (new_hw_mask & 1 << i)
+                                                       w++;
+                                       if (w > cfg.rd_ports[pidx].def->max_rd_wide_log2) {
+                                               goto hw_bit_failed;
+                                       }
+                               }
+                               // Bit ok, commit.
+                               hard_wide_mask = new_hw_mask;
+                               hard_wide_num++;
+                       }
+bw_done:;
+               }
+               log_assert(got_config);
+       }
+}
+
+void MemMapping::prune_post_geom() {
+       std::vector<bool> keep;
+       dict<std::string, int> rsrc;
+       for (int i = 0; i < GetSize(cfgs); i++) {
+               auto &cfg = cfgs[i];
+               std::string key = cfg.def->resource_name;
+               if (key.empty()) {
+                       switch (cfg.def->kind) {
+                               case RamKind::Distributed:
+                                       key = "[distributed]";
+                                       break;
+                               case RamKind::Block:
+                                       key = "[block]";
+                                       break;
+                               case RamKind::Huge:
+                                       key = "[huge]";
+                                       break;
+                               default:
+                                       break;
+                       }
+               }
+               auto it = rsrc.find(key);
+               if (it == rsrc.end()) {
+                       rsrc[key] = i;
+                       keep.push_back(true);
+               } else {
+                       auto &ocfg = cfgs[it->second];
+                       if (cfg.cost < ocfg.cost) {
+                               keep[it->second] = false;
+                               it->second = i;
+                               keep.push_back(true);
+                       } else {
+                               keep.push_back(false);
+                       }
+               }
+       }
+       MemConfigs new_cfgs;
+       for (int i = 0; i < GetSize(cfgs); i++)
+               if (keep[i])
+                       new_cfgs.push_back(cfgs[i]);
+       cfgs = new_cfgs;
+}
+
+Swizzle gen_swizzle(const Mem &mem, const MemConfig &cfg, int sw_wide_log2, int hw_wide_log2) {
+       Swizzle res;
+
+       std::vector<int> emu_wide_bits;
+       std::vector<int> hard_wide_bits;
+       for (int i = 0; i < ceil_log2(mem.size); i++) {
+               if (cfg.emu_wide_mask & 1 << i)
+                       emu_wide_bits.push_back(i);
+               else if (GetSize(hard_wide_bits) < hw_wide_log2 - cfg.base_width_log2)
+                       hard_wide_bits.push_back(i);
+       }
+       for (int x : hard_wide_bits)
+               if (x >= sw_wide_log2)
+                       res.addr_mux_bits.push_back(x);
+       for (int x : emu_wide_bits)
+               if (x >= sw_wide_log2)
+                       res.addr_mux_bits.push_back(x);
+
+       res.addr_shift = cfg.def->abits - cfg.base_width_log2 + GetSize(emu_wide_bits);
+       res.addr_start = mem.start_offset & ~((1 << res.addr_shift) - 1);
+       res.addr_end = ((mem.start_offset + mem.size - 1) | ((1 << res.addr_shift) - 1)) + 1;
+       int hnum = (res.addr_end - res.addr_start) >> res.addr_shift;
+       int unit_width = cfg.def->dbits[cfg.unit_width_log2];
+
+       for (int rd = 0; rd < cfg.repl_d; rd++) {
+               std::vector<SwizzleBit> bits(cfg.def->dbits[hw_wide_log2]);
+               for (auto &bit: bits)
+                       bit.valid = false;
+               res.bits.push_back(bits);
+       }
+
+       for (int hi = 0; hi < hnum; hi++) {
+               for (int ewi = 0; ewi < (1 << GetSize(emu_wide_bits)); ewi++) {
+                       for (int hwi = 0; hwi < (1 << GetSize(hard_wide_bits)); hwi++) {
+                               int mux_idx = 0;
+                               int sub = 0;
+                               int mib = 0;
+                               int hbit_base = 0;
+                               for (int i = 0; i < GetSize(hard_wide_bits); i++) {
+                                       if (hard_wide_bits[i] < sw_wide_log2) {
+                                               if (hwi & 1 << i)
+                                                       sub |= 1 << hard_wide_bits[i];
+                                       } else {
+                                               if (hwi & 1 << i)
+                                                       mux_idx |= 1 << mib;
+                                               mib++;
+                                       }
+                                       if (hwi & 1 << i)
+                                               hbit_base += cfg.def->dbits[i + cfg.base_width_log2];
+                               }
+                               for (int i = 0; i < GetSize(emu_wide_bits); i++) {
+                                       if (emu_wide_bits[i] < sw_wide_log2) {
+                                               if (ewi & 1 << i)
+                                                       sub |= 1 << emu_wide_bits[i];
+                                       } else {
+                                               if (ewi & 1 << i)
+                                                       mux_idx |= 1 << mib;
+                                               mib++;
+                                       }
+                               }
+                               mux_idx |= hi << mib;
+                               int addr = res.addr_start + (hi << res.addr_shift);
+                               for (int i = 0; i < GetSize(res.addr_mux_bits); i++)
+                                       if (mux_idx & 1 << i)
+                                               addr += 1 << res.addr_mux_bits[i];
+                               for (int bit = 0; bit < GetSize(cfg.swizzle); bit++) {
+                                       if (cfg.swizzle[bit] == -1)
+                                               continue;
+                                       int rbit = bit + GetSize(cfg.swizzle) * (ewi + (hi << GetSize(emu_wide_bits)));
+                                       int rep = rbit / unit_width;
+                                       int hbit = hbit_base + rbit % unit_width;
+                                       auto &swz = res.bits[rep][hbit];
+                                       swz.valid = true;
+                                       swz.addr = addr;
+                                       swz.mux_idx = mux_idx;
+                                       swz.bit = cfg.swizzle[bit] + sub * mem.width;
+                               }
+                       }
+               }
+       }
+
+       return res;
+}
+
+void clean_undef(std::vector<State> &val) {
+       for (auto &bit : val)
+               if (bit != State::S1)
+                       bit = State::S0;
+}
+
+std::vector<SigSpec> generate_demux(Mem &mem, int wpidx, const Swizzle &swz) {
+       auto &port = mem.wr_ports[wpidx];
+       std::vector<SigSpec> res;
+       int hi_bits = ceil_log2(swz.addr_end - swz.addr_start) - swz.addr_shift;
+       auto compressed = port.compress_en();
+       SigSpec sig_a = compressed.first;
+       SigSpec addr = port.addr;
+       if (GetSize(addr) > hi_bits + swz.addr_shift) {
+               int lo = mem.start_offset;
+               int hi = mem.start_offset + mem.size;
+               int bits = ceil_log2(hi);
+               for (int i = 0; i < bits; i++) {
+                       int new_lo = lo;
+                       if (lo & 1 << i)
+                               new_lo -= 1 << i;
+                       int new_hi = hi;
+                       if (hi & 1 << i)
+                               new_hi += 1 << i;
+                       if (new_hi - new_lo > (1 << (hi_bits + swz.addr_shift)))
+                               break;
+                       lo = new_lo;
+                       hi = new_hi;
+               }
+               SigSpec in_range = mem.module->And(NEW_ID, mem.module->Ge(NEW_ID, addr, lo), mem.module->Lt(NEW_ID, addr, hi));
+               sig_a = mem.module->Mux(NEW_ID, Const(State::S0, GetSize(sig_a)), sig_a, in_range);
+       }
+       addr.extend_u0(swz.addr_shift + hi_bits, false);
+       SigSpec sig_s;
+       for (int x : swz.addr_mux_bits)
+               sig_s.append(addr[x]);
+       for (int i = 0; i < hi_bits; i++)
+               sig_s.append(addr[swz.addr_shift + i]);
+       SigSpec sig_y;
+       if (GetSize(sig_s) == 0)
+               sig_y = sig_a;
+       else
+               sig_y = mem.module->Demux(NEW_ID, sig_a, sig_s);
+       for (int i = 0; i < ((swz.addr_end - swz.addr_start) >> swz.addr_shift); i++) {
+               for (int j = 0; j < (1 << GetSize(swz.addr_mux_bits)); j++) {
+                       int hi = ((swz.addr_start >> swz.addr_shift) + i) & ((1 << hi_bits) - 1);
+                       int pos = (hi << GetSize(swz.addr_mux_bits) | j) * GetSize(sig_a);
+                       res.push_back(port.decompress_en(compressed.second, sig_y.extract(pos, GetSize(sig_a))));
+               }
+       }
+       return res;
+}
+
+std::vector<SigSpec> generate_mux(Mem &mem, int rpidx, const Swizzle &swz) {
+       auto &port = mem.rd_ports[rpidx];
+       std::vector<SigSpec> res;
+       int hi_bits = ceil_log2(swz.addr_end - swz.addr_start) - swz.addr_shift;
+       SigSpec sig_s;
+       SigSpec addr = port.addr;
+       addr.extend_u0(swz.addr_shift + hi_bits, false);
+       for (int x : swz.addr_mux_bits)
+               sig_s.append(addr[x]);
+       for (int i = 0; i < hi_bits; i++)
+               sig_s.append(addr[swz.addr_shift + i]);
+       if (GetSize(sig_s) == 0) {
+               return {port.data};
+       }
+       if (port.clk_enable) {
+               SigSpec new_sig_s = mem.module->addWire(NEW_ID, GetSize(sig_s));
+               mem.module->addDffe(NEW_ID, port.clk, port.en, sig_s, new_sig_s, port.clk_polarity);
+               sig_s = new_sig_s;
+       }
+       SigSpec sig_a = Const(State::Sx, GetSize(port.data) << hi_bits << GetSize(swz.addr_mux_bits));
+       for (int i = 0; i < ((swz.addr_end - swz.addr_start) >> swz.addr_shift); i++) {
+               for (int j = 0; j < (1 << GetSize(swz.addr_mux_bits)); j++) {
+                       SigSpec sig = mem.module->addWire(NEW_ID, GetSize(port.data));
+                       int hi = ((swz.addr_start >> swz.addr_shift) + i) & ((1 << hi_bits) - 1);
+                       int pos = (hi << GetSize(swz.addr_mux_bits) | j) * GetSize(port.data);
+                       for (int k = 0; k < GetSize(port.data); k++)
+                               sig_a[pos + k] = sig[k];
+                       res.push_back(sig);
+               }
+       }
+       mem.module->addBmux(NEW_ID, sig_a, sig_s, port.data);
+       return res;
+}
+
+void MemMapping::emit_port(const MemConfig &cfg, std::vector<Cell*> &cells, const PortVariant &pdef, const char *name, int wpidx, int rpidx, const std::vector<int> &hw_addr_swizzle) {
+       for (auto &it: pdef.options)
+               for (auto cell: cells)
+                       cell->setParam(stringf("\\PORT_%s_OPTION_%s", name, it.first.c_str()), it.second);
+       SigSpec addr = Const(State::Sx, cfg.def->abits);
+       int wide_log2 = 0, wr_wide_log2 = 0, rd_wide_log2 = 0;
+       SigSpec clk = State::S0;
+       SigSpec clk_en = State::S0;
+       bool clk_pol = true;
+       if (wpidx != -1) {
+               auto &wport = mem.wr_ports[wpidx];
+               clk = wport.clk;
+               clk_pol = wport.clk_polarity;
+               addr = wport.addr;
+               wide_log2 = wr_wide_log2 = wport.wide_log2;
+               if (rpidx != -1) {
+                       auto &rport = mem.rd_ports[rpidx];
+                       auto &rpcfg = cfg.rd_ports[rpidx];
+                       rd_wide_log2 = rport.wide_log2;
+                       if (rd_wide_log2 > wr_wide_log2)
+                               wide_log2 = rd_wide_log2;
+                       else
+                               addr = rport.addr;
+                       if (pdef.clk_en) {
+                               if (rpcfg.rd_en_to_clk_en) {
+                                       if (pdef.rdwr == RdWrKind::NoChange) {
+                                               clk_en = mem.module->Or(NEW_ID, rport.en, mem.module->ReduceOr(NEW_ID, wport.en));
+                                       } else {
+                                               clk_en = rport.en;
+                                       }
+                               } else {
+                                       clk_en = State::S1;
+                               }
+                       }
+               } else {
+                       if (pdef.clk_en)
+                               clk_en = State::S1;
+               }
+       } else if (rpidx != -1) {
+               auto &rport = mem.rd_ports[rpidx];
+               auto &rpcfg = cfg.rd_ports[rpidx];
+               if (rport.clk_enable) {
+                       clk = rport.clk;
+                       clk_pol = rport.clk_polarity;
+               }
+               addr = rport.addr;
+               wide_log2 = rd_wide_log2 = rport.wide_log2;
+               if (pdef.clk_en) {
+                       if (rpcfg.rd_en_to_clk_en)
+                               clk_en = rport.en;
+                       else
+                               clk_en = State::S1;
+               }
+
+       }
+       addr = worker.sigmap_xmux(addr);
+       if (pdef.kind != PortKind::Ar) {
+               switch (pdef.clk_pol) {
+                       case ClkPolKind::Posedge:
+                               if (!clk_pol)
+                                       clk = mem.module->Not(NEW_ID, clk);
+                               break;
+                       case ClkPolKind::Negedge:
+                               if (clk_pol)
+                                       clk = mem.module->Not(NEW_ID, clk);
+                               break;
+                       case ClkPolKind::Anyedge:
+                               for (auto cell: cells)
+                                       cell->setParam(stringf("\\PORT_%s_CLK_POL", name), clk_pol);
+               }
+               for (auto cell: cells) {
+                       cell->setPort(stringf("\\PORT_%s_CLK", name), clk);
+                       if (pdef.clk_en)
+                               cell->setPort(stringf("\\PORT_%s_CLK_EN", name), clk_en);
+               }
+       }
+
+       // Width determination.
+       if (pdef.width_tied) {
+               rd_wide_log2 = wr_wide_log2 = wide_log2;
+       }
+       int hw_wr_wide_log2 = cfg.base_width_log2;
+       for (int i = 0; i < wr_wide_log2; i++)
+               if (cfg.hard_wide_mask & (1 << i))
+                       hw_wr_wide_log2++;
+       if (hw_wr_wide_log2 < pdef.min_wr_wide_log2)
+               hw_wr_wide_log2 = pdef.min_wr_wide_log2;
+       if (hw_wr_wide_log2 > pdef.max_wr_wide_log2)
+               hw_wr_wide_log2 = pdef.max_wr_wide_log2;
+       int hw_rd_wide_log2 = cfg.base_width_log2;
+       for (int i = 0; i < rd_wide_log2; i++)
+               if (cfg.hard_wide_mask & (1 << i))
+                       hw_rd_wide_log2++;
+       if (hw_rd_wide_log2 < pdef.min_rd_wide_log2)
+               hw_rd_wide_log2 = pdef.min_rd_wide_log2;
+       if (hw_rd_wide_log2 > pdef.max_rd_wide_log2)
+               hw_rd_wide_log2 = pdef.max_rd_wide_log2;
+       if (pdef.width_tied) {
+               // For unused ports, pick max available width,
+               // in case narrow ports require disabling parity
+               // bits etc.
+               if (wpidx == -1 && rpidx == -1) {
+                       hw_wr_wide_log2 = pdef.max_wr_wide_log2;
+                       hw_rd_wide_log2 = pdef.max_rd_wide_log2;
+               }
+       } else {
+               if (wpidx == -1)
+                       hw_wr_wide_log2 = pdef.max_wr_wide_log2;
+               if (rpidx == -1)
+                       hw_rd_wide_log2 = pdef.max_rd_wide_log2;
+       }
+       if (cfg.def->width_mode == WidthMode::PerPort) {
+               for (auto cell: cells) {
+                       if (pdef.width_tied) {
+                               cell->setParam(stringf("\\PORT_%s_WIDTH", name), cfg.def->dbits[hw_wr_wide_log2]);
+                       } else {
+                               if (pdef.kind != PortKind::Ar && pdef.kind != PortKind::Sr)
+                                       cell->setParam(stringf("\\PORT_%s_WR_WIDTH", name), cfg.def->dbits[hw_wr_wide_log2]);
+                               if (pdef.kind != PortKind::Sw)
+                                       cell->setParam(stringf("\\PORT_%s_RD_WIDTH", name), cfg.def->dbits[hw_rd_wide_log2]);
+                       }
+               }
+       }
+
+       // Address determination.
+       SigSpec hw_addr;
+       for (int x: hw_addr_swizzle) {
+               if (x == -1 || x >= GetSize(addr))
+                       hw_addr.append(State::S0);
+               else
+                       hw_addr.append(addr[x]);
+       }
+       for (int i = 0; i < hw_wr_wide_log2 && i < hw_rd_wide_log2; i++)
+               hw_addr[i] = State::S0;
+       for (auto cell: cells)
+               cell->setPort(stringf("\\PORT_%s_ADDR", name), hw_addr);
+
+       // Write part.
+       if (pdef.kind != PortKind::Ar && pdef.kind != PortKind::Sr) {
+               int width = cfg.def->dbits[hw_wr_wide_log2];
+               int effective_byte = cfg.def->byte;
+               if (effective_byte == 0 || effective_byte > width)
+                       effective_byte = width;
+               if (wpidx != -1) {
+                       auto &wport = mem.wr_ports[wpidx];
+                       Swizzle port_swz = gen_swizzle(mem, cfg, wport.wide_log2, hw_wr_wide_log2);
+                       std::vector<SigSpec> big_wren = generate_demux(mem, wpidx, port_swz);
+                       for (int rd = 0; rd < cfg.repl_d; rd++) {
+                               auto cell = cells[rd];
+                               SigSpec hw_wdata;
+                               SigSpec hw_wren;
+                               for (auto &bit : port_swz.bits[rd]) {
+                                       if (!bit.valid) {
+                                               hw_wdata.append(State::Sx);
+                                       } else {
+                                               hw_wdata.append(wport.data[bit.bit]);
+                                       }
+                               }
+                               for (int i = 0; i < GetSize(port_swz.bits[rd]); i += effective_byte) {
+                                       auto &bit = port_swz.bits[rd][i];
+                                       if (!bit.valid) {
+                                               hw_wren.append(State::S0);
+                                       } else {
+                                               hw_wren.append(big_wren[bit.mux_idx][bit.bit]);
+                                       }
+                               }
+                               cell->setPort(stringf("\\PORT_%s_WR_DATA", name), hw_wdata);
+                               if (pdef.wrbe_separate) {
+                                       // TODO make some use of it
+                                       SigSpec en = mem.module->ReduceOr(NEW_ID, hw_wren);
+                                       cell->setPort(stringf("\\PORT_%s_WR_EN", name), en);
+                                       cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren);
+                                       if (cfg.def->width_mode != WidthMode::Single)
+                                               cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
+                               } else {
+                                       cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren);
+                                       if (cfg.def->byte != 0 && cfg.def->width_mode != WidthMode::Single)
+                                               cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren));
+                               }
+                       }
+               } else {
+                       for (auto cell: cells) {
+                               cell->setPort(stringf("\\PORT_%s_WR_DATA", name), Const(State::Sx, width));
+                               SigSpec hw_wren = Const(State::S0, width / effective_byte);
+                               if (pdef.wrbe_separate) {
+                                       cell->setPort(stringf("\\PORT_%s_WR_EN", name), State::S0);
+                                       cell->setPort(stringf("\\PORT_%s_WR_BE", name), hw_wren);
+                                       cell->setParam(stringf("\\PORT_%s_WR_BE_WIDTH", name), GetSize(hw_wren));
+                               } else {
+                                       cell->setPort(stringf("\\PORT_%s_WR_EN", name), hw_wren);
+                                       if (cfg.def->byte != 0)
+                                               cell->setParam(stringf("\\PORT_%s_WR_EN_WIDTH", name), GetSize(hw_wren));
+                               }
+                       }
+               }
+       }
+
+       // Read part.
+       if (pdef.kind != PortKind::Sw) {
+               int width = cfg.def->dbits[hw_rd_wide_log2];
+               if (rpidx != -1) {
+                       auto &rport = mem.rd_ports[rpidx];
+                       auto &rpcfg = cfg.rd_ports[rpidx];
+                       Swizzle port_swz = gen_swizzle(mem, cfg, rport.wide_log2, hw_rd_wide_log2);
+                       std::vector<SigSpec> big_rdata = generate_mux(mem, rpidx, port_swz);
+                       for (int rd = 0; rd < cfg.repl_d; rd++) {
+                               auto cell = cells[rd];
+                               if (pdef.kind == PortKind::Sr || pdef.kind == PortKind::Srsw) {
+                                       if (pdef.rd_en)
+                                               cell->setPort(stringf("\\PORT_%s_RD_EN", name), rpcfg.rd_en_to_clk_en ? State::S1 : rport.en);
+                                       if (pdef.rdarstval != ResetValKind::None)
+                                               cell->setPort(stringf("\\PORT_%s_RD_ARST", name), rport.arst);
+                                       if (pdef.rdsrstval != ResetValKind::None)
+                                               cell->setPort(stringf("\\PORT_%s_RD_SRST", name), rport.srst);
+                                       if (pdef.rdinitval == ResetValKind::Any || pdef.rdinitval == ResetValKind::NoUndef) {
+                                               Const val = rport.init_value;
+                                               if (pdef.rdarstval == ResetValKind::Init && rport.arst != State::S0) {
+                                                       log_assert(val.is_fully_undef() || val == rport.arst_value);
+                                                       val = rport.arst_value;
+                                               }
+                                               if (pdef.rdsrstval == ResetValKind::Init && rport.srst != State::S0) {
+                                                       log_assert(val.is_fully_undef() || val == rport.srst_value);
+                                                       val = rport.srst_value;
+                                               }
+                                               std::vector<State> hw_val;
+                                               for (auto &bit : port_swz.bits[rd]) {
+                                                       if (!bit.valid) {
+                                                               hw_val.push_back(State::Sx);
+                                                       } else {
+                                                               hw_val.push_back(val.bits[bit.bit]);
+                                                       }
+                                               }
+                                               if (pdef.rdinitval == ResetValKind::NoUndef)
+                                                       clean_undef(hw_val);
+                                               cell->setParam(stringf("\\PORT_%s_RD_INIT_VALUE", name), hw_val);
+                                       }
+                                       if (pdef.rdarstval == ResetValKind::Any || pdef.rdarstval == ResetValKind::NoUndef) {
+                                               std::vector<State> hw_val;
+                                               for (auto &bit : port_swz.bits[rd]) {
+                                                       if (!bit.valid) {
+                                                               hw_val.push_back(State::Sx);
+                                                       } else {
+                                                               hw_val.push_back(rport.arst_value.bits[bit.bit]);
+                                                       }
+                                               }
+                                               if (pdef.rdarstval == ResetValKind::NoUndef)
+                                                       clean_undef(hw_val);
+                                               cell->setParam(stringf("\\PORT_%s_RD_ARST_VALUE", name), hw_val);
+                                       }
+                                       if (pdef.rdsrstval == ResetValKind::Any || pdef.rdsrstval == ResetValKind::NoUndef) {
+                                               std::vector<State> hw_val;
+                                               for (auto &bit : port_swz.bits[rd]) {
+                                                       if (!bit.valid) {
+                                                               hw_val.push_back(State::Sx);
+                                                       } else {
+                                                               hw_val.push_back(rport.srst_value.bits[bit.bit]);
+                                                       }
+                                               }
+                                               if (pdef.rdsrstval == ResetValKind::NoUndef)
+                                                       clean_undef(hw_val);
+                                               cell->setParam(stringf("\\PORT_%s_RD_SRST_VALUE", name), hw_val);
+                                       }
+                               }
+                               SigSpec hw_rdata = mem.module->addWire(NEW_ID, width);
+                               cell->setPort(stringf("\\PORT_%s_RD_DATA", name), hw_rdata);
+                               SigSpec lhs;
+                               SigSpec rhs;
+                               for (int i = 0; i < GetSize(hw_rdata); i++) {
+                                       auto &bit = port_swz.bits[rd][i];
+                                       if (bit.valid) {
+                                               lhs.append(big_rdata[bit.mux_idx][bit.bit]);
+                                               rhs.append(hw_rdata[i]);
+                                       }
+                               }
+                               mem.module->connect(lhs, rhs);
+                       }
+               } else {
+                       for (auto cell: cells) {
+                               if (pdef.kind == PortKind::Sr || pdef.kind == PortKind::Srsw) {
+                                       if (pdef.rd_en)
+                                               cell->setPort(stringf("\\PORT_%s_RD_EN", name), State::S0);
+                                       if (pdef.rdarstval != ResetValKind::None)
+                                               cell->setPort(stringf("\\PORT_%s_RD_ARST", name), State::S0);
+                                       if (pdef.rdsrstval != ResetValKind::None)
+                                               cell->setPort(stringf("\\PORT_%s_RD_SRST", name), State::S0);
+                                       if (pdef.rdinitval == ResetValKind::Any)
+                                               cell->setParam(stringf("\\PORT_%s_RD_INIT_VALUE", name), Const(State::Sx, width));
+                                       else if (pdef.rdinitval == ResetValKind::NoUndef)
+                                               cell->setParam(stringf("\\PORT_%s_RD_INIT_VALUE", name), Const(State::S0, width));
+                                       if (pdef.rdarstval == ResetValKind::Any)
+                                               cell->setParam(stringf("\\PORT_%s_RD_ARST_VALUE", name), Const(State::Sx, width));
+                                       else if (pdef.rdarstval == ResetValKind::NoUndef)
+                                               cell->setParam(stringf("\\PORT_%s_RD_ARST_VALUE", name), Const(State::S0, width));
+                                       if (pdef.rdsrstval == ResetValKind::Any)
+                                               cell->setParam(stringf("\\PORT_%s_RD_SRST_VALUE", name), Const(State::Sx, width));
+                                       else if (pdef.rdsrstval == ResetValKind::NoUndef)
+                                               cell->setParam(stringf("\\PORT_%s_RD_SRST_VALUE", name), Const(State::S0, width));
+                               }
+                               SigSpec hw_rdata = mem.module->addWire(NEW_ID, width);
+                               cell->setPort(stringf("\\PORT_%s_RD_DATA", name), hw_rdata);
+                       }
+               }
+       }
+}
+
+void MemMapping::emit(const MemConfig &cfg) {
+       log("mapping memory %s.%s via %s\n", log_id(mem.module->name), log_id(mem.memid), log_id(cfg.def->id));
+       // First, handle emulations.
+       if (cfg.emu_read_first)
+               mem.emulate_read_first(&worker.initvals);
+       for (int pidx = 0; pidx < GetSize(mem.rd_ports); pidx++) {
+               auto &pcfg = cfg.rd_ports[pidx];
+               auto &port = mem.rd_ports[pidx];
+               if (pcfg.emu_sync)
+                       mem.extract_rdff(pidx, &worker.initvals);
+               else if (pcfg.emu_en)
+                       mem.emulate_rden(pidx, &worker.initvals);
+               else {
+                       if (pcfg.emu_srst_en_prio) {
+                               if (port.ce_over_srst)
+                                       mem.emulate_rd_ce_over_srst(pidx);
+                               else
+                                       mem.emulate_rd_srst_over_ce(pidx);
+                       }
+                       mem.emulate_reset(pidx, pcfg.emu_init, pcfg.emu_arst, pcfg.emu_srst, &worker.initvals);
+               }
+       }
+       for (int pidx = 0; pidx < GetSize(mem.wr_ports); pidx++) {
+               auto &pcfg = cfg.wr_ports[pidx];
+               for (int opidx: pcfg.emu_prio) {
+                       mem.emulate_priority(opidx, pidx, &worker.initvals);
+               }
+       }
+       for (int pidx = 0; pidx < GetSize(mem.rd_ports); pidx++) {
+               auto &port = mem.rd_ports[pidx];
+               auto &pcfg = cfg.rd_ports[pidx];
+               for (int opidx: pcfg.emu_trans) {
+                       // The port may no longer be transparent due to transparency being
+                       // nuked as part of emu_sync or emu_prio.
+                       if (port.transparency_mask[opidx])
+                               mem.emulate_transparency(opidx, pidx, &worker.initvals);
+               }
+       }
+
+       // tgt (repl, port group, port) -> mem (wr port, rd port), where -1 means no port.
+       std::vector<std::vector<std::vector<std::pair<int, int>>>> ports(cfg.repl_port);
+       for (int i = 0; i < cfg.repl_port; i++)
+               ports[i].resize(cfg.def->port_groups.size());
+       for (int i = 0; i < GetSize(cfg.wr_ports); i++) {
+               auto &pcfg = cfg.wr_ports[i];
+               for (int j = 0; j < cfg.repl_port; j++) {
+                       if (j == 0) {
+                               ports[j][pcfg.port_group].push_back({i, pcfg.rd_port});
+                       } else {
+                               ports[j][pcfg.port_group].push_back({i, -1});
+                       }
+               }
+       }
+       for (int i = 0; i < GetSize(cfg.rd_ports); i++) {
+               auto &pcfg = cfg.rd_ports[i];
+               if (pcfg.wr_port != -1)
+                       continue;
+               auto &pg = cfg.def->port_groups[pcfg.port_group];
+               int j = 0;
+               while (GetSize(ports[j][pcfg.port_group]) >= GetSize(pg.names))
+                       j++;
+               ports[j][pcfg.port_group].push_back({-1, i});
+       }
+
+       Swizzle init_swz = gen_swizzle(mem, cfg, 0, GetSize(cfg.def->dbits) - 1);
+       Const init_data = mem.get_init_data();
+
+       std::vector<int> hw_addr_swizzle;
+       for (int i = 0; i < cfg.base_width_log2; i++)
+               hw_addr_swizzle.push_back(-1);
+       for (int i = 0; i < init_swz.addr_shift; i++)
+               if (!(cfg.emu_wide_mask & 1 << i))
+                       hw_addr_swizzle.push_back(i);
+       log_assert(GetSize(hw_addr_swizzle) == cfg.def->abits);
+
+       for (int rp = 0; rp < cfg.repl_port; rp++) {
+               std::vector<Cell *> cells;
+               for (int rd = 0; rd < cfg.repl_d; rd++) {
+                       Cell *cell = mem.module->addCell(stringf("%s.%d.%d", mem.memid.c_str(), rp, rd), cfg.def->id);
+                       if (cfg.def->width_mode == WidthMode::Global)
+                               cell->setParam(ID::WIDTH, cfg.def->dbits[cfg.base_width_log2]);
+                       if (cfg.def->widthscale) {
+                               std::vector<State> val;
+                               for (auto &bit: init_swz.bits[rd])
+                                       val.push_back(bit.valid ? State::S1 : State::S0);
+                               cell->setParam(ID::BITS_USED, val);
+                       }
+                       for (auto &it: cfg.def->options)
+                               cell->setParam(stringf("\\OPTION_%s", it.first.c_str()), it.second);
+                       for (int i = 0; i < GetSize(cfg.def->shared_clocks); i++) {
+                               auto &cdef = cfg.def->shared_clocks[i];
+                               auto &ccfg = cfg.shared_clocks[i];
+                               if (cdef.anyedge) {
+                                       cell->setParam(stringf("\\CLK_%s_POL", cdef.name.c_str()), ccfg.used ? ccfg.polarity : true);
+                                       cell->setPort(stringf("\\CLK_%s", cdef.name.c_str()), ccfg.used ? ccfg.clk : State::S0);
+                               } else {
+                                       SigSpec sig = ccfg.used ? ccfg.clk : State::S0;
+                                       if (ccfg.used && ccfg.invert)
+                                               sig = mem.module->Not(NEW_ID, sig);
+                                       cell->setPort(stringf("\\CLK_%s", cdef.name.c_str()), sig);
+                               }
+                       }
+                       if (cfg.def->init == MemoryInitKind::Any || cfg.def->init == MemoryInitKind::NoUndef) {
+                               std::vector<State> initval;
+                               for (int hwa = 0; hwa < (1 << cfg.def->abits); hwa += 1 << (GetSize(cfg.def->dbits) - 1)) {
+                                       for (auto &bit: init_swz.bits[rd]) {
+                                               if (!bit.valid) {
+                                                       initval.push_back(State::Sx);
+                                               } else {
+                                                       int addr = bit.addr;
+                                                       for (int i = GetSize(cfg.def->dbits) - 1; i < cfg.def->abits; i++)
+                                                               if (hwa & 1 << i)
+                                                                       addr += 1 << hw_addr_swizzle[i];
+                                                       if (addr >= mem.start_offset && addr < mem.start_offset + mem.size)
+                                                               initval.push_back(init_data.bits[(addr - mem.start_offset) * mem.width + bit.bit]);
+                                                       else
+                                                               initval.push_back(State::Sx);
+                                               }
+                                       }
+                               }
+                               if (cfg.def->init == MemoryInitKind::NoUndef)
+                                       clean_undef(initval);
+                               cell->setParam(ID::INIT, initval);
+                       }
+                       cells.push_back(cell);
+               }
+               for (int pgi = 0; pgi < GetSize(cfg.def->port_groups); pgi++) {
+                       auto &pg = cfg.def->port_groups[pgi];
+                       for (int pi = 0; pi < GetSize(pg.names); pi++) {
+                               bool used = pi < GetSize(ports[rp][pgi]);
+                               bool used_r = false;
+                               bool used_w = false;
+                               if (used) {
+                                       auto &pd = ports[rp][pgi][pi];
+                                       const PortVariant *pdef;
+                                       if (pd.first != -1)
+                                               pdef = cfg.wr_ports[pd.first].def;
+                                       else
+                                               pdef = cfg.rd_ports[pd.second].def;
+                                       used_w = pd.first != -1;
+                                       used_r = pd.second != -1;
+                                       emit_port(cfg, cells, *pdef, pg.names[pi].c_str(), pd.first, pd.second, hw_addr_swizzle);
+                               } else {
+                                       emit_port(cfg, cells, pg.variants[0], pg.names[pi].c_str(), -1, -1, hw_addr_swizzle);
+                               }
+                               if (pg.optional)
+                                       for (auto cell: cells)
+                                               cell->setParam(stringf("\\PORT_%s_USED", pg.names[pi].c_str()), used);
+                               if (pg.optional_rw)
+                                       for (auto cell: cells) {
+                                               cell->setParam(stringf("\\PORT_%s_RD_USED", pg.names[pi].c_str()), used_r);
+                                               cell->setParam(stringf("\\PORT_%s_WR_USED", pg.names[pi].c_str()), used_w);
+                                       }
+                       }
+               }
+       }
+       mem.remove();
+}
+
+struct MemoryLibMapPass : public Pass {
+       MemoryLibMapPass() : Pass("memory_libmap", "map memories to cells") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    memory_libmap -lib <library_file> [-D <condition>] [selection]\n");
+               log("\n");
+               log("This pass takes a description of available RAM cell types and maps\n");
+               log("all selected memories to one of them, or leaves them  to be mapped to FFs.\n");
+               log("\n");
+               log("  -lib <library_file>\n");
+               log("    Selects a library file containing RAM cell definitions. This option\n");
+               log("    can be passed more than once to select multiple libraries.\n");
+               log("    See passes/memory/memlib.md for description of the library format.\n");
+               log("\n");
+               log("  -D <condition>\n");
+               log("    Enables a condition that can be checked within the library file\n");
+               log("    to eg. select between slightly different hardware variants.\n");
+               log("    This option can be passed any number of times.\n");
+               log("\n");
+               log("  -logic-cost-rom <num>\n");
+               log("  -logic-cost-ram <num>\n");
+               log("    Sets the cost of a single bit for memory lowered to soft logic.\n");
+               log("\n");
+               log("  -no-auto-distributed\n");
+               log("  -no-auto-block\n");
+               log("  -no-auto-huge\n");
+               log("    Disables automatic mapping of given kind of RAMs.  Manual mapping\n");
+               log("    (using ram_style or other attributes) is still supported.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               std::vector<std::string> lib_files;
+               pool<std::string> defines;
+               PassOptions opts;
+               opts.no_auto_distributed = false;
+               opts.no_auto_block = false;
+               opts.no_auto_huge = false;
+               opts.logic_cost_ram = 1.0;
+               opts.logic_cost_rom = 1.0/16.0;
+               log_header(design, "Executing MEMORY_LIBMAP pass (mapping memories to cells).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++) {
+                       if (args[argidx] == "-lib" && argidx+1 < args.size()) {
+                               lib_files.push_back(args[++argidx]);
+                               continue;
+                       }
+                       if (args[argidx] == "-D" && argidx+1 < args.size()) {
+                               defines.insert(args[++argidx]);
+                               continue;
+                       }
+                       if (args[argidx] == "-no-auto-distributed") {
+                               opts.no_auto_distributed = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-no-auto-block") {
+                               opts.no_auto_block = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-no-auto-huge") {
+                               opts.no_auto_huge = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-logic-cost-rom" && argidx+1 < args.size()) {
+                               opts.logic_cost_rom = strtod(args[++argidx].c_str(), nullptr);
+                               continue;
+                       }
+                       if (args[argidx] == "-logic-cost-ram" && argidx+1 < args.size()) {
+                               opts.logic_cost_ram = strtod(args[++argidx].c_str(), nullptr);
+                               continue;
+                       }
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               Library lib = parse_library(lib_files, defines);
+
+               for (auto module : design->selected_modules()) {
+                       MapWorker worker(module);
+                       auto mems = Mem::get_selected_memories(module);
+                       for (auto &mem : mems)
+                       {
+                               MemMapping map(worker, mem, lib, opts);
+                               int idx = -1;
+                               int best = map.logic_cost;
+                               if (!map.logic_ok) {
+                                       if (map.cfgs.empty())
+                                               log_error("no valid mapping found for memory %s.%s\n", log_id(module->name), log_id(mem.memid));
+                                       idx = 0;
+                                       best = map.cfgs[0].cost;
+                               }
+                               for (int i = 0; i < GetSize(map.cfgs); i++) {
+                                       if (map.cfgs[i].cost < best) {
+                                               idx = i;
+                                               best = map.cfgs[i].cost;
+                                       }
+                               }
+                               if (idx == -1) {
+                                       log("using FF mapping for memory %s.%s\n", log_id(module->name), log_id(mem.memid));
+                               } else {
+                                       map.emit(map.cfgs[idx]);
+                               }
+                       }
+               }
+       }
+} MemoryLibMapPass;
+
+PRIVATE_NAMESPACE_END
index 4e52ad8da0439164db72a3dc5bc50061b9eba2ed..76bf8a84e316a1cc4147d0b935e99697cb166b69 100644 (file)
@@ -19,6 +19,7 @@ OBJS += passes/opt/opt_demorgan.o
 OBJS += passes/opt/rmports.o
 OBJS += passes/opt/opt_lut.o
 OBJS += passes/opt/opt_lut_ins.o
+OBJS += passes/opt/opt_ffinv.o
 OBJS += passes/opt/pmux2shiftx.o
 OBJS += passes/opt/muxpack.o
 endif
diff --git a/passes/opt/opt_ffinv.cc b/passes/opt/opt_ffinv.cc
new file mode 100644 (file)
index 0000000..fd76dd2
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2022  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/yosys.h"
+#include "kernel/sigtools.h"
+#include "kernel/modtools.h"
+#include "kernel/ffinit.h"
+#include "kernel/ff.h"
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct OptFfInvWorker
+{
+       int count = 0;
+       RTLIL::Module *module;
+       ModIndex index;
+       FfInitVals initvals;
+
+       // Case 1:
+       // - FF is driven by inverter
+       // - ... which has no other users
+       // - all users of FF are LUTs
+       bool push_d_inv(FfData &ff) {
+               if (index.query_is_input(ff.sig_d))
+                       return false;
+               if (index.query_is_output(ff.sig_d))
+                       return false;
+               auto d_ports = index.query_ports(ff.sig_d);
+               if (d_ports.size() != 2)
+                       return false;
+               Cell *d_inv = nullptr;
+               for (auto &port: d_ports) {
+                       if (port.cell == ff.cell && port.port == ID::D)
+                               continue;
+                       if (port.port != ID::Y)
+                               return false;
+                       if (port.cell->type.in(ID($not), ID($_NOT_))) {
+                               // OK
+                       } else if (port.cell->type.in(ID($lut))) {
+                               if (port.cell->getParam(ID::WIDTH) != 1)
+                                       return false;
+                               if (port.cell->getParam(ID::LUT).as_int() != 1)
+                                       return false;
+                       } else {
+                               return false;
+                       }
+                       log_assert(d_inv == nullptr);
+                       d_inv = port.cell;
+               }
+
+               if (index.query_is_output(ff.sig_q))
+                       return false;
+               auto q_ports = index.query_ports(ff.sig_q);
+               pool<Cell *> q_luts;
+               for (auto &port: q_ports) {
+                       if (port.cell == ff.cell && port.port == ID::Q)
+                               continue;
+                       if (port.port != ID::A)
+                               return false;
+                       if (!port.cell->type.in(ID($not), ID($_NOT_), ID($lut)))
+                               return false;
+                       q_luts.insert(port.cell);
+               }
+
+               ff.flip_rst_bits({0});
+               ff.sig_d = d_inv->getPort(ID::A);
+
+               for (Cell *lut: q_luts) {
+                       if (lut->type == ID($lut)) {
+                               int flip_mask = 0;
+                               SigSpec sig_a = lut->getPort(ID::A);
+                               for (int i = 0; i < GetSize(sig_a); i++) {
+                                       if (index.sigmap(sig_a[i]) == index.sigmap(ff.sig_q)) {
+                                               flip_mask |= 1 << i;
+                                       }
+                               }
+                               Const mask = lut->getParam(ID::LUT);
+                               Const new_mask;
+                               for (int j = 0; j < (1 << GetSize(sig_a)); j++) {
+                                       new_mask.bits.push_back(mask.bits[j ^ flip_mask]);
+                               }
+                               if (GetSize(sig_a) == 1 && new_mask.as_int() == 2) {
+                                       module->connect(lut->getPort(ID::Y), ff.sig_q);
+                                       module->remove(lut);
+                               } else {
+                                       lut->setParam(ID::LUT, new_mask);
+                               }
+                       } else {
+                               // it was an inverter
+                               module->connect(lut->getPort(ID::Y), ff.sig_q);
+                               module->remove(lut);
+                       }
+               }
+
+               ff.emit();
+               return true;
+       }
+
+       // Case 2:
+       // - FF is driven by LUT
+       // - ... which has no other users
+       // - FF has one user
+       // - ... which is an inverter
+       bool push_q_inv(FfData &ff) {
+               if (index.query_is_input(ff.sig_d))
+                       return false;
+               if (index.query_is_output(ff.sig_d))
+                       return false;
+
+               Cell *d_lut = nullptr;
+               auto d_ports = index.query_ports(ff.sig_d);
+               if (d_ports.size() != 2)
+                       return false;
+               for (auto &port: d_ports) {
+                       if (port.cell == ff.cell && port.port == ID::D)
+                               continue;
+                       if (port.port != ID::Y)
+                               return false;
+                       if (!port.cell->type.in(ID($not), ID($_NOT_), ID($lut)))
+                               return false;
+                       log_assert(d_lut == nullptr);
+                       d_lut = port.cell;
+               }
+
+               if (index.query_is_output(ff.sig_q))
+                       return false;
+               auto q_ports = index.query_ports(ff.sig_q);
+               if (q_ports.size() != 2)
+                       return false;
+               Cell *q_inv = nullptr;
+               for (auto &port: q_ports) {
+                       if (port.cell == ff.cell && port.port == ID::Q)
+                               continue;
+                       if (port.port != ID::A)
+                               return false;
+                       if (port.cell->type.in(ID($not), ID($_NOT_))) {
+                               // OK
+                       } else if (port.cell->type.in(ID($lut))) {
+                               if (port.cell->getParam(ID::WIDTH) != 1)
+                                       return false;
+                               if (port.cell->getParam(ID::LUT).as_int() != 1)
+                                       return false;
+                       } else {
+                               return false;
+                       }
+                       log_assert(q_inv == nullptr);
+                       q_inv = port.cell;
+               }
+
+               ff.flip_rst_bits({0});
+               ff.sig_q = q_inv->getPort(ID::Y);
+               module->remove(q_inv);
+
+               if (d_lut->type == ID($lut)) {
+                       Const mask = d_lut->getParam(ID::LUT);
+                       Const new_mask;
+                       for (int i = 0; i < GetSize(mask); i++) {
+                               if (mask.bits[i] == State::S0)
+                                       new_mask.bits.push_back(State::S1);
+                               else
+                                       new_mask.bits.push_back(State::S0);
+                       }
+                       d_lut->setParam(ID::LUT, new_mask);
+                       if (d_lut->getParam(ID::WIDTH) == 1 && new_mask.as_int() == 2) {
+                               module->connect(ff.sig_d, d_lut->getPort(ID::A));
+                               module->remove(d_lut);
+                       }
+               } else {
+                       // it was an inverter
+                       module->connect(ff.sig_d, d_lut->getPort(ID::A));
+                       module->remove(d_lut);
+               }
+
+               ff.emit();
+               return true;
+       }
+
+       OptFfInvWorker(RTLIL::Module *module) :
+               module(module), index(module), initvals(&index.sigmap, module)
+       {
+               log("Discovering LUTs.\n");
+
+               for (Cell *cell : module->selected_cells()) {
+                       if (!RTLIL::builtin_ff_cell_types().count(cell->type))
+                               continue;
+
+                       FfData ff(&initvals, cell);
+                       if (ff.has_sr)
+                               continue;
+                       if (!ff.has_clk)
+                               continue;
+                       if (ff.has_aload)
+                               continue;
+                       if (ff.width != 1)
+                               continue;
+
+                       if (push_d_inv(ff)) {
+                               count++;
+                       } else if (push_q_inv(ff)) {
+                               count++;
+                       }
+               }
+       }
+};
+
+struct OptFfInvPass : public Pass {
+       OptFfInvPass() : Pass("opt_ffinv", "push inverters through FFs") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    opt_ffinv [selection]\n");
+               log("\n");
+               log("This pass pushes inverters to the other side of a FF when they can be merged\n");
+               log("into LUTs on the other side.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               log_header(design, "Executing OPT_FFINV pass (push inverters through FFs).\n");
+
+               size_t argidx;
+               for (argidx = 1; argidx < args.size(); argidx++)
+               {
+                       break;
+               }
+               extra_args(args, argidx, design);
+
+               int total_count = 0;
+               for (auto module : design->selected_modules())
+               {
+                       OptFfInvWorker worker(module);
+                       total_count += worker.count;
+               }
+               if (total_count)
+                       design->scratchpad_set_bool("opt.did_something", true);
+               log("Pushed %d inverters.\n", total_count);
+       }
+} OptFfInvPass;
+
+PRIVATE_NAMESPACE_END
index 50244bf33defa64791d76a551cb8d6d9a0c9f3e2..21e169a3474daec075070ad391e52f8a10fb123f 100644 (file)
@@ -5,6 +5,7 @@ OBJS += passes/proc/proc_clean.o
 OBJS += passes/proc/proc_rmdead.o
 OBJS += passes/proc/proc_init.o
 OBJS += passes/proc/proc_arst.o
+OBJS += passes/proc/proc_rom.o
 OBJS += passes/proc/proc_mux.o
 OBJS += passes/proc/proc_dlatch.o
 OBJS += passes/proc/proc_dff.o
index d7aac57b66fa0215fd5bdd740ccb0f1485784316..c18651d5e51b809cdbf0c06667c4868cacb80e38 100644 (file)
@@ -40,6 +40,7 @@ struct ProcPass : public Pass {
                log("    proc_prune\n");
                log("    proc_init\n");
                log("    proc_arst\n");
+               log("    proc_rom\n");
                log("    proc_mux\n");
                log("    proc_dlatch\n");
                log("    proc_dff\n");
@@ -55,6 +56,9 @@ struct ProcPass : public Pass {
                log("    -nomux\n");
                log("        Will omit the proc_mux pass.\n");
                log("\n");
+               log("    -norom\n");
+               log("        Will omit the proc_rom pass.\n");
+               log("\n");
                log("    -global_arst [!]<netname>\n");
                log("        This option is passed through to proc_arst.\n");
                log("\n");
@@ -72,6 +76,7 @@ struct ProcPass : public Pass {
                bool ifxmode = false;
                bool nomux = false;
                bool noopt = false;
+               bool norom = false;
 
                log_header(design, "Executing PROC pass (convert processes to netlists).\n");
                log_push();
@@ -95,6 +100,10 @@ struct ProcPass : public Pass {
                                noopt = true;
                                continue;
                        }
+                       if (args[argidx] == "-norom") {
+                               norom = true;
+                               continue;
+                       }
                        break;
                }
                extra_args(args, argidx, design);
@@ -108,6 +117,8 @@ struct ProcPass : public Pass {
                        Pass::call(design, "proc_arst");
                else
                        Pass::call(design, "proc_arst -global_arst " + global_arst);
+               if (!norom)
+                       Pass::call(design, "proc_rom");
                if (!nomux)
                        Pass::call(design, ifxmode ? "proc_mux -ifx" : "proc_mux");
                Pass::call(design, "proc_dlatch");
diff --git a/passes/proc/proc_rom.cc b/passes/proc/proc_rom.cc
new file mode 100644 (file)
index 0000000..b83466c
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ *  yosys -- Yosys Open SYnthesis Suite
+ *
+ *  Copyright (C) 2022  Marcelina KoÅ›cielnicka <mwk@0x04.net>
+ *
+ *  Permission to use, copy, modify, and/or distribute this software for any
+ *  purpose with or without fee is hereby granted, provided that the above
+ *  copyright notice and this permission notice appear in all copies.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include "kernel/register.h"
+#include "kernel/sigtools.h"
+#include "kernel/log.h"
+#include "kernel/mem.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+USING_YOSYS_NAMESPACE
+PRIVATE_NAMESPACE_BEGIN
+
+struct RomWorker
+{
+       RTLIL::Module *module;
+       SigMap sigmap;
+
+       int count = 0;
+
+       RomWorker(RTLIL::Module *mod) : module(mod), sigmap(mod) {}
+
+       void do_switch(RTLIL::SwitchRule *sw)
+       {
+               for (auto cs : sw->cases) {
+                       do_case(cs);
+               }
+
+               if (sw->cases.empty()) {
+                       log_debug("rejecting switch: no cases\n");
+                       return;
+               }
+
+               // A switch can be converted into ROM when:
+               //
+               // 1. No case contains a nested switch
+               // 2. All cases have the same set of assigned signals
+               // 3. All right-hand values in cases are constants
+               // 4. All compare values used in cases are fully-defined constants
+               // 5. The cases must cover all possible values (possibly by using default case)
+
+               SigSpec lhs;
+               dict<SigBit, int> lhs_lookup;
+               for (auto &it: sw->cases[0]->actions) {
+                       for (auto bit: it.first) {
+                               if (!lhs_lookup.count(bit)) {
+                                       lhs_lookup[bit] = GetSize(lhs);
+                                       lhs.append(bit);
+                               }
+                       }
+               }
+
+               int swsigbits = 0;
+               for (int i = 0; i < GetSize(sw->signal); i++)
+                       if (sw->signal[i] != State::S0)
+                               swsigbits = i + 1;
+
+               dict<int, Const> vals;
+               Const default_val;
+               bool got_default = false;
+               int maxaddr = 0;
+               for (auto cs : sw->cases) {
+                       if (!cs->switches.empty()) {
+                               log_debug("rejecting switch: has nested switches\n");
+                               return;
+                       }
+                       Const val = Const(State::Sm, GetSize(lhs));
+                       for (auto &it: cs->actions) {
+                               if (!it.second.is_fully_const()) {
+                                       log_debug("rejecting switch: rhs not const\n");
+                                       return;
+                               }
+                               for (int i = 0; i < GetSize(it.first); i++) {
+                                       auto it2 = lhs_lookup.find(it.first[i]);
+                                       if (it2 == lhs_lookup.end()) {
+                                               log_debug("rejecting switch: lhs not uniform\n");
+                                               return;
+                                       }
+                                       val[it2->second] = it.second[i].data;
+                               }
+                       }
+                       for (auto bit: val.bits) {
+                               if (bit == State::Sm) {
+                                       log_debug("rejecting switch: lhs not uniform\n");
+                                       return;
+                               }
+                       }
+
+                       for (auto &addr: cs->compare) {
+                               if (!addr.is_fully_def()) {
+                                       log_debug("rejecting switch: case value has undef bits\n");
+                                       return;
+                               }
+                               Const c = addr.as_const();
+                               while (GetSize(c) && c.bits.back() == State::S0)
+                                       c.bits.pop_back();
+                               if (GetSize(c) > swsigbits)
+                                       continue;
+                               if (GetSize(c) > 30) {
+                                       log_debug("rejecting switch: address too large\n");
+                                       return;
+                               }
+                               int a = c.as_int();
+                               if (vals.count(a))
+                                       continue;
+                               vals[a] = val;
+                               if (a > maxaddr)
+                                       maxaddr = a;
+                       }
+                       if (cs->compare.empty()) {
+                               default_val = val;
+                               got_default = true;
+                               break;
+                       }
+               }
+               int abits = ceil_log2(maxaddr + 1);
+               if (!got_default && (swsigbits > 30 || GetSize(vals) != (1 << swsigbits))) {
+                       log_debug("rejecting switch: not all values are covered\n");
+                       return;
+               }
+
+               // TODO: better density heuristic?
+               if (GetSize(vals) < 8) {
+                       log_debug("rejecting switch: not enough values\n");
+                       return;
+               }
+               if ((1 << abits) / GetSize(vals) > 4) {
+                       log_debug("rejecting switch: not enough density\n");
+                       return;
+               }
+
+               // Ok, let's do it.
+               SigSpec rdata = module->addWire(NEW_ID, GetSize(lhs));
+               Mem mem(module, NEW_ID, GetSize(lhs), 0, 1 << abits);
+               mem.attributes = sw->attributes;
+
+               Const init_data;
+               for (int i = 0; i < mem.size; i++) {
+                       auto it = vals.find(i);
+                       if (it == vals.end()) {
+                               log_assert(got_default);
+                               for (auto bit: default_val.bits)
+                                       init_data.bits.push_back(bit);
+                       } else {
+                               for (auto bit: it->second.bits)
+                                       init_data.bits.push_back(bit);
+                       }
+               }
+
+               MemInit init;
+               init.addr = 0;
+               init.data = init_data;
+               init.en = Const(State::S1, GetSize(lhs));
+               mem.inits.push_back(std::move(init));
+
+               MemRd rd;
+               rd.addr = sw->signal.extract(0, abits);
+               rd.data = rdata;
+               rd.init_value = Const(State::Sx, GetSize(lhs));
+               rd.arst_value = Const(State::Sx, GetSize(lhs));
+               rd.srst_value = Const(State::Sx, GetSize(lhs));
+               mem.rd_ports.push_back(std::move(rd));
+
+               mem.emit();
+               for (auto cs: sw->cases)
+                       delete cs;
+               sw->cases.clear();
+               sw->signal = sw->signal.extract(0, swsigbits);
+               if (abits == GetSize(sw->signal)) {
+                       sw->signal = SigSpec();
+                       RTLIL::CaseRule *cs = new RTLIL::CaseRule;
+                       cs->actions.push_back(SigSig(lhs, rdata));
+                       sw->cases.push_back(cs);
+               } else {
+                       sw->signal = sw->signal.extract_end(abits);
+                       RTLIL::CaseRule *cs = new RTLIL::CaseRule;
+                       cs->compare.push_back(Const(State::S0, GetSize(sw->signal)));
+                       cs->actions.push_back(SigSig(lhs, rdata));
+                       sw->cases.push_back(cs);
+                       RTLIL::CaseRule *cs2 = new RTLIL::CaseRule;
+                       cs2->actions.push_back(SigSig(lhs, default_val));
+                       sw->cases.push_back(cs2);
+               }
+
+               count += 1;
+       }
+
+       void do_case(RTLIL::CaseRule *cs)
+       {
+               for (auto sw: cs->switches) {
+                       do_switch(sw);
+               }
+       }
+
+       void do_process(RTLIL::Process *pr)
+       {
+               do_case(&pr->root_case);
+       }
+};
+
+struct ProcRomPass : public Pass {
+       ProcRomPass() : Pass("proc_rom", "convert switches to ROMs") { }
+       void help() override
+       {
+               //   |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|
+               log("\n");
+               log("    proc_rom [selection]\n");
+               log("\n");
+               log("This pass converts switches into read-only memories when appropriate.\n");
+               log("\n");
+       }
+       void execute(std::vector<std::string> args, RTLIL::Design *design) override
+       {
+               int total_count = 0;
+               log_header(design, "Executing PROC_ROM pass (convert switches to ROMs).\n");
+
+               extra_args(args, 1, design);
+
+               for (auto mod : design->modules()) {
+                       if (!design->selected(mod))
+                               continue;
+                       RomWorker worker(mod);
+                       for (auto &proc_it : mod->processes) {
+                               if (!design->selected(mod, proc_it.second))
+                                       continue;
+                               worker.do_process(proc_it.second);
+                       }
+                       total_count += worker.count;
+               }
+
+               log("Converted %d switch%s.\n",
+                   total_count, total_count == 1 ? "" : "es");
+       }
+} ProcRomPass;
+
+PRIVATE_NAMESPACE_END
index b8975f17835308ef5b577981067ba63f8a7243b9..acafb0b6579550458661c0d49c9958f8d12b8890 100644 (file)
@@ -155,6 +155,9 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
                r.first->second = new Design;
        Design *unmap_design = r.first->second;
 
+       // Keep track of derived versions of modules that we haven't used, to prevent these being used for unwanted techmaps later on.
+       pool<IdString> unused_derived;
+
        for (auto module : design->selected_modules())
                for (auto cell : module->cells()) {
                        auto inst_module = design->module(cell->type);
@@ -169,6 +172,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
                        else {
                                derived_type = inst_module->derive(design, cell->parameters);
                                derived_module = design->module(derived_type);
+                               unused_derived.insert(derived_type);
                        }
 
                        if (derived_module->get_bool_attribute(ID::abc9_flop)) {
@@ -192,6 +196,7 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
                                                // as a compatible type, yet will be safely unmapped later
                                                cell->type = derived_type;
                                                cell->parameters.clear();
+                                               unused_derived.erase(derived_type);
                                        }
                                        continue;
                                }
@@ -250,7 +255,11 @@ void prep_hier(RTLIL::Design *design, bool dff_mode)
 
                        cell->type = derived_type;
                        cell->parameters.clear();
+                       unused_derived.erase(derived_type);
                }
+       for (auto unused : unused_derived) {
+               design->remove(design->module(unused));
+       }
 }
 
 void prep_bypass(RTLIL::Design *design)
diff --git a/techlibs/anlogic/.gitignore b/techlibs/anlogic/.gitignore
deleted file mode 100644 (file)
index d127107..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-brams_init.mk
-brams_init_*.vh
index 79519c645d52fcda7c19eacb20716d65d54854a4..669e8bea53f144794cc71a5e118337464867ae63 100644 (file)
@@ -3,32 +3,11 @@ 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))
 $(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))
index a39701c63236101365eb08731e31e1c2fb71ef1f..910cdebe1831dd94aa8155640003fe974baecc3b 100644 (file)
@@ -1,43 +1,69 @@
-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 @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
+ram block $__ANLOGIC_BRAM_TDP_ {
+       abits 13;
+       widths 1 2 4 9 per_port;
+       cost 64;
+       init no_undef;
+       port srsw "A" "B" {
+               clock anyedge;
+               clken;
+               portoption "WRITEMODE" "NORMAL" {
+                       rdwr no_change;
+               }
+               portoption "WRITEMODE" "WRITETHROUGH" {
+                       rdwr new;
+               }
+               portoption "WRITEMODE" "READBEFOREWRITE" {
+                       rdwr old;
+               }
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated block_wr;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+}
 
-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
+ram block $__ANLOGIC_BRAM_SDP_ {
+       abits 13;
+       widths 1 2 4 9 18 per_port;
+       byte 9;
+       cost 64;
+       init no_undef;
+       port sr "R" {
+               clock anyedge;
+               clken;
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+       port sw "W" {
+               clock anyedge;
+               clken;
+       }
+}
 
-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
+ram block $__ANLOGIC_BRAM32K_ {
+       abits 12;
+       widths 8 16 per_port;
+       byte 8;
+       cost 192;
+       init no_undef;
+       port srsw "A" "B" {
+               clock anyedge;
+               clken;
+               portoption "WRITEMODE" "NORMAL" {
+                       rdwr no_change;
+               }
+               portoption "WRITEMODE" "WRITETHROUGH" {
+                       rdwr new;
+               }
+               # no reset - it doesn't really work without the pipeline
+               # output registers
+       }
+}
diff --git a/techlibs/anlogic/brams_init.py b/techlibs/anlogic/brams_init.py
deleted file mode 100644 (file)
index 8dda0d3..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#!/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)
index ee02b6d7ce126bf05bccb3c7b0f7c380d25c9a59..7e2642d65d394fffff591fc16c6950d69a3031e5 100644 (file)
-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
+module $__ANLOGIC_BRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_A_WIDTH = 9;
+parameter PORT_A_CLK_POL = 1;
+parameter PORT_A_OPTION_WRITEMODE = "NORMAL";
+
+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 [12:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+
+parameter PORT_B_WIDTH = 9;
+parameter PORT_B_CLK_POL = 1;
+parameter PORT_B_OPTION_WRITEMODE = "NORMAL";
+
+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 [12:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+
+function [255:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 32; i = i + 1) begin
+               init_slice[i*8+:8] = INIT[(idx * 32 + i) * 9 +: 8];
+       end
+endfunction
+
+function [255:0] initp_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 256; i = i + 1) begin
+               initp_slice[i] = INIT[(idx * 256 + i) * 9 + 8];
+       end
+endfunction
+
+wire [8:0] DOA;
+wire [8:0] DOB;
+// the replication is important â€” the BRAM behaves in... unexpected ways for
+// width 1 and 2
+wire [8:0] DIA = {9{PORT_A_WR_DATA}};
+wire [8:0] DIB = {9{PORT_B_WR_DATA}};
+
+assign PORT_A_RD_DATA = DOA;
+assign PORT_B_RD_DATA = DOB;
+
+EG_PHY_BRAM #(
+       .INIT_00(init_slice('h00)),
+       .INIT_01(init_slice('h01)),
+       .INIT_02(init_slice('h02)),
+       .INIT_03(init_slice('h03)),
+       .INIT_04(init_slice('h04)),
+       .INIT_05(init_slice('h05)),
+       .INIT_06(init_slice('h06)),
+       .INIT_07(init_slice('h07)),
+       .INIT_08(init_slice('h08)),
+       .INIT_09(init_slice('h09)),
+       .INIT_0A(init_slice('h0a)),
+       .INIT_0B(init_slice('h0b)),
+       .INIT_0C(init_slice('h0c)),
+       .INIT_0D(init_slice('h0d)),
+       .INIT_0E(init_slice('h0e)),
+       .INIT_0F(init_slice('h0f)),
+       .INIT_10(init_slice('h10)),
+       .INIT_11(init_slice('h11)),
+       .INIT_12(init_slice('h12)),
+       .INIT_13(init_slice('h13)),
+       .INIT_14(init_slice('h14)),
+       .INIT_15(init_slice('h15)),
+       .INIT_16(init_slice('h16)),
+       .INIT_17(init_slice('h17)),
+       .INIT_18(init_slice('h18)),
+       .INIT_19(init_slice('h19)),
+       .INIT_1A(init_slice('h1a)),
+       .INIT_1B(init_slice('h1b)),
+       .INIT_1C(init_slice('h1c)),
+       .INIT_1D(init_slice('h1d)),
+       .INIT_1E(init_slice('h1e)),
+       .INIT_1F(init_slice('h1f)),
+       .INITP_00(initp_slice('h00)),
+       .INITP_01(initp_slice('h01)),
+       .INITP_02(initp_slice('h02)),
+       .INITP_03(initp_slice('h03)),
+       .MODE("DP8K"),
+       .DATA_WIDTH_A($sformatf("%d", PORT_A_WIDTH)),
+       .DATA_WIDTH_B($sformatf("%d", PORT_B_WIDTH)),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CLKAMUX(PORT_A_CLK_POL ? "SIG" : "INV"),
+       .CLKBMUX(PORT_B_CLK_POL ? "SIG" : "INV"),
+       .WRITEMODE_A(PORT_A_OPTION_WRITEMODE),
+       .WRITEMODE_B(PORT_B_OPTION_WRITEMODE),
+) _TECHMAP_REPLACE_ (
+       .clka(PORT_A_CLK),
+       .wea(PORT_A_WR_EN),
+       .cea(PORT_A_CLK_EN),
+       .ocea(1'b1),
+       .rsta(OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+       .csa(3'b111),
+       .addra(PORT_A_WIDTH == 9 ? {PORT_A_ADDR[12:1], 1'b1} : PORT_A_ADDR),
+       .dia(DIA),
+       .doa(DOA),
+
+       .clkb(PORT_B_CLK),
+       .web(PORT_B_WR_EN),
+       .ceb(PORT_B_CLK_EN),
+       .oceb(1'b1),
+       .rstb(OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+       .csb(3'b111),
+       .addrb(PORT_B_WIDTH == 9 ? {PORT_B_ADDR[12:1], 1'b1} : PORT_B_ADDR),
+       .dib(DIB),
+       .dob(DOB),
+);
+
+endmodule
+
+
+module $__ANLOGIC_BRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_R_WIDTH = 18;
+parameter PORT_R_CLK_POL = 1;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input PORT_R_RD_SRST;
+input PORT_R_RD_ARST;
+input [12:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+
+parameter PORT_W_WIDTH = 18;
+parameter PORT_W_WR_EN_WIDTH = 2;
+parameter PORT_W_CLK_POL = 1;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [12:0] PORT_W_ADDR;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+
+function [255:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 32; i = i + 1) begin
+               init_slice[i*8+:8] = INIT[(idx * 32 + i) * 9 +: 8];
+       end
+endfunction
+
+function [255:0] initp_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 256; i = i + 1) begin
+               initp_slice[i] = INIT[(idx * 256 + i) * 9 + 8];
+       end
+endfunction
+
+wire [17:0] DI = {18{PORT_W_WR_DATA}};
+wire [17:0] DO;
+
+assign PORT_R_RD_DATA = PORT_R_WIDTH == 18 ? DO : DO[17:9];
+
+EG_PHY_BRAM #(
+       .INIT_00(init_slice('h00)),
+       .INIT_01(init_slice('h01)),
+       .INIT_02(init_slice('h02)),
+       .INIT_03(init_slice('h03)),
+       .INIT_04(init_slice('h04)),
+       .INIT_05(init_slice('h05)),
+       .INIT_06(init_slice('h06)),
+       .INIT_07(init_slice('h07)),
+       .INIT_08(init_slice('h08)),
+       .INIT_09(init_slice('h09)),
+       .INIT_0A(init_slice('h0a)),
+       .INIT_0B(init_slice('h0b)),
+       .INIT_0C(init_slice('h0c)),
+       .INIT_0D(init_slice('h0d)),
+       .INIT_0E(init_slice('h0e)),
+       .INIT_0F(init_slice('h0f)),
+       .INIT_10(init_slice('h10)),
+       .INIT_11(init_slice('h11)),
+       .INIT_12(init_slice('h12)),
+       .INIT_13(init_slice('h13)),
+       .INIT_14(init_slice('h14)),
+       .INIT_15(init_slice('h15)),
+       .INIT_16(init_slice('h16)),
+       .INIT_17(init_slice('h17)),
+       .INIT_18(init_slice('h18)),
+       .INIT_19(init_slice('h19)),
+       .INIT_1A(init_slice('h1a)),
+       .INIT_1B(init_slice('h1b)),
+       .INIT_1C(init_slice('h1c)),
+       .INIT_1D(init_slice('h1d)),
+       .INIT_1E(init_slice('h1e)),
+       .INIT_1F(init_slice('h1f)),
+       .INITP_00(initp_slice('h00)),
+       .INITP_01(initp_slice('h01)),
+       .INITP_02(initp_slice('h02)),
+       .INITP_03(initp_slice('h03)),
+       .MODE("PDPW8K"),
+       .DATA_WIDTH_A($sformatf("%d", PORT_W_WIDTH)),
+       .DATA_WIDTH_B($sformatf("%d", PORT_R_WIDTH)),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CLKAMUX(PORT_W_CLK_POL ? "SIG" : "INV"),
+       .CLKBMUX(PORT_R_CLK_POL ? "SIG" : "INV"),
+) _TECHMAP_REPLACE_ (
+       .clka(PORT_W_CLK),
+       .wea(PORT_W_WIDTH >= 9 ? 1'b1 : PORT_W_WR_EN[0]),
+       .cea(PORT_W_CLK_EN),
+       .ocea(1'b1),
+       .rsta(1'b0),
+       .csa(3'b111),
+       .addra(PORT_W_WIDTH == 18 ? {PORT_W_ADDR[12:2], PORT_W_WR_EN[1:0]} : (PORT_W_WIDTH == 9 ? {PORT_W_ADDR[12:1], PORT_W_WR_EN[0]} : PORT_W_ADDR)),
+       .dia(DI[8:0]),
+       .doa(DO[8:0]),
+
+       .clkb(PORT_R_CLK),
+       .web(1'b0),
+       .ceb(PORT_R_CLK_EN),
+       .oceb(1'b1),
+       .rstb(OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
+       .csb(3'b111),
+       .addrb(PORT_R_ADDR),
+       .dib(DI[17:9]),
+       .dob(DO[17:9]),
+);
+
 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)
-       );
+
+module $__ANLOGIC_BRAM32K_ (...);
+
+parameter INIT = 0;
+
+parameter PORT_A_WIDTH = 16;
+parameter PORT_A_WR_EN_WIDTH = 2;
+parameter PORT_A_CLK_POL = 1;
+parameter PORT_A_OPTION_WRITEMODE = "NORMAL";
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+input [11:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+
+parameter PORT_B_WIDTH = 16;
+parameter PORT_B_WR_EN_WIDTH = 2;
+parameter PORT_B_CLK_POL = 1;
+parameter PORT_B_OPTION_WRITEMODE = "NORMAL";
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+input [11:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+
+function [255:0] init_slice;
+       input integer idx;
+       init_slice = INIT[256 * idx +: 256];
+endfunction
+
+wire [15:0] DOA;
+wire [15:0] DOB;
+wire [15:0] DIA = PORT_A_WR_DATA;
+wire [15:0] DIB = PORT_B_WR_DATA;
+
+assign PORT_A_RD_DATA = DOA;
+assign PORT_B_RD_DATA = DOB;
+
+wire BYTE_A, BYTEWE_A;
+wire BYTE_B, BYTEWE_B;
+
+generate
+
+if (PORT_A_WIDTH == 8) begin
+       assign BYTE_A = PORT_A_ADDR[0];
+       assign BYTEWE_A = 1;
+end else begin
+       assign BYTE_A = PORT_A_WR_EN == 2;
+       assign BYTEWE_A = ^PORT_A_WR_EN;
+end
+
+if (PORT_B_WIDTH == 8) begin
+       assign BYTE_B = PORT_B_ADDR[0];
+       assign BYTEWE_B = 1;
+end else begin
+       assign BYTE_B = PORT_B_WR_EN == 2;
+       assign BYTEWE_B = ^PORT_B_WR_EN;
+end
+
+endgenerate
+
+EG_PHY_BRAM32K #(
+       .INIT_00(init_slice('h00)),
+       .INIT_01(init_slice('h01)),
+       .INIT_02(init_slice('h02)),
+       .INIT_03(init_slice('h03)),
+       .INIT_04(init_slice('h04)),
+       .INIT_05(init_slice('h05)),
+       .INIT_06(init_slice('h06)),
+       .INIT_07(init_slice('h07)),
+       .INIT_08(init_slice('h08)),
+       .INIT_09(init_slice('h09)),
+       .INIT_0A(init_slice('h0a)),
+       .INIT_0B(init_slice('h0b)),
+       .INIT_0C(init_slice('h0c)),
+       .INIT_0D(init_slice('h0d)),
+       .INIT_0E(init_slice('h0e)),
+       .INIT_0F(init_slice('h0f)),
+       .INIT_10(init_slice('h10)),
+       .INIT_11(init_slice('h11)),
+       .INIT_12(init_slice('h12)),
+       .INIT_13(init_slice('h13)),
+       .INIT_14(init_slice('h14)),
+       .INIT_15(init_slice('h15)),
+       .INIT_16(init_slice('h16)),
+       .INIT_17(init_slice('h17)),
+       .INIT_18(init_slice('h18)),
+       .INIT_19(init_slice('h19)),
+       .INIT_1A(init_slice('h1a)),
+       .INIT_1B(init_slice('h1b)),
+       .INIT_1C(init_slice('h1c)),
+       .INIT_1D(init_slice('h1d)),
+       .INIT_1E(init_slice('h1e)),
+       .INIT_1F(init_slice('h1f)),
+       .INIT_20(init_slice('h20)),
+       .INIT_21(init_slice('h21)),
+       .INIT_22(init_slice('h22)),
+       .INIT_23(init_slice('h23)),
+       .INIT_24(init_slice('h24)),
+       .INIT_25(init_slice('h25)),
+       .INIT_26(init_slice('h26)),
+       .INIT_27(init_slice('h27)),
+       .INIT_28(init_slice('h28)),
+       .INIT_29(init_slice('h29)),
+       .INIT_2A(init_slice('h2a)),
+       .INIT_2B(init_slice('h2b)),
+       .INIT_2C(init_slice('h2c)),
+       .INIT_2D(init_slice('h2d)),
+       .INIT_2E(init_slice('h2e)),
+       .INIT_2F(init_slice('h2f)),
+       .INIT_30(init_slice('h30)),
+       .INIT_31(init_slice('h31)),
+       .INIT_32(init_slice('h32)),
+       .INIT_33(init_slice('h33)),
+       .INIT_34(init_slice('h34)),
+       .INIT_35(init_slice('h35)),
+       .INIT_36(init_slice('h36)),
+       .INIT_37(init_slice('h37)),
+       .INIT_38(init_slice('h38)),
+       .INIT_39(init_slice('h39)),
+       .INIT_3A(init_slice('h3a)),
+       .INIT_3B(init_slice('h3b)),
+       .INIT_3C(init_slice('h3c)),
+       .INIT_3D(init_slice('h3d)),
+       .INIT_3E(init_slice('h3e)),
+       .INIT_3F(init_slice('h3f)),
+       .INIT_40(init_slice('h40)),
+       .INIT_41(init_slice('h41)),
+       .INIT_42(init_slice('h42)),
+       .INIT_43(init_slice('h43)),
+       .INIT_44(init_slice('h44)),
+       .INIT_45(init_slice('h45)),
+       .INIT_46(init_slice('h46)),
+       .INIT_47(init_slice('h47)),
+       .INIT_48(init_slice('h48)),
+       .INIT_49(init_slice('h49)),
+       .INIT_4A(init_slice('h4a)),
+       .INIT_4B(init_slice('h4b)),
+       .INIT_4C(init_slice('h4c)),
+       .INIT_4D(init_slice('h4d)),
+       .INIT_4E(init_slice('h4e)),
+       .INIT_4F(init_slice('h4f)),
+       .INIT_50(init_slice('h50)),
+       .INIT_51(init_slice('h51)),
+       .INIT_52(init_slice('h52)),
+       .INIT_53(init_slice('h53)),
+       .INIT_54(init_slice('h54)),
+       .INIT_55(init_slice('h55)),
+       .INIT_56(init_slice('h56)),
+       .INIT_57(init_slice('h57)),
+       .INIT_58(init_slice('h58)),
+       .INIT_59(init_slice('h59)),
+       .INIT_5A(init_slice('h5a)),
+       .INIT_5B(init_slice('h5b)),
+       .INIT_5C(init_slice('h5c)),
+       .INIT_5D(init_slice('h5d)),
+       .INIT_5E(init_slice('h5e)),
+       .INIT_5F(init_slice('h5f)),
+       .INIT_60(init_slice('h60)),
+       .INIT_61(init_slice('h61)),
+       .INIT_62(init_slice('h62)),
+       .INIT_63(init_slice('h63)),
+       .INIT_64(init_slice('h64)),
+       .INIT_65(init_slice('h65)),
+       .INIT_66(init_slice('h66)),
+       .INIT_67(init_slice('h67)),
+       .INIT_68(init_slice('h68)),
+       .INIT_69(init_slice('h69)),
+       .INIT_6A(init_slice('h6a)),
+       .INIT_6B(init_slice('h6b)),
+       .INIT_6C(init_slice('h6c)),
+       .INIT_6D(init_slice('h6d)),
+       .INIT_6E(init_slice('h6e)),
+       .INIT_6F(init_slice('h6f)),
+       .INIT_70(init_slice('h70)),
+       .INIT_71(init_slice('h71)),
+       .INIT_72(init_slice('h72)),
+       .INIT_73(init_slice('h73)),
+       .INIT_74(init_slice('h74)),
+       .INIT_75(init_slice('h75)),
+       .INIT_76(init_slice('h76)),
+       .INIT_77(init_slice('h77)),
+       .INIT_78(init_slice('h78)),
+       .INIT_79(init_slice('h79)),
+       .INIT_7A(init_slice('h7a)),
+       .INIT_7B(init_slice('h7b)),
+       .INIT_7C(init_slice('h7c)),
+       .INIT_7D(init_slice('h7d)),
+       .INIT_7E(init_slice('h7e)),
+       .INIT_7F(init_slice('h7f)),
+       .MODE("DP16K"),
+       .DATA_WIDTH_A($sformatf("%d", PORT_A_WIDTH)),
+       .DATA_WIDTH_B($sformatf("%d", PORT_B_WIDTH)),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .WRITEMODE_A(PORT_A_OPTION_WRITEMODE),
+       .WRITEMODE_B(PORT_B_OPTION_WRITEMODE),
+       .CLKAMUX(PORT_A_CLK_POL ? "SIG" : "INV"),
+       .CLKBMUX(PORT_B_CLK_POL ? "SIG" : "INV"),
+) _TECHMAP_REPLACE_ (
+       .clka(PORT_A_CLK),
+       .csa(PORT_A_CLK_EN),
+       .wea(|PORT_A_WR_EN),
+       .ocea(1'b1),
+       .rsta(1'b0),
+       .addra(PORT_A_ADDR[11:1]),
+       .bytea(BYTE_A),
+       .bytewea(BYTEWE_A),
+       .dia(DIA),
+       .doa(DOA),
+
+       .clkb(PORT_B_CLK),
+       .csb(PORT_B_CLK_EN),
+       .web(|PORT_B_WR_EN),
+       .ocea(1'b1),
+       .rsta(1'b0),
+       .addrb(PORT_B_ADDR[11:1]),
+       .byteb(BYTE_B),
+       .byteweb(BYTEWE_B),
+       .dib(DIB),
+       .dob(DOB),
+);
+
 endmodule
diff --git a/techlibs/anlogic/lutram_init_16x4.vh b/techlibs/anlogic/lutram_init_16x4.vh
deleted file mode 100644 (file)
index 32fb157..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-.INIT_D0({INIT[15*4+0], INIT[14*4+0], INIT[13*4+0], INIT[12*4+0],
-         INIT[11*4+0], INIT[10*4+0], INIT[9*4+0], INIT[8*4+0],
-         INIT[7*4+0], INIT[6*4+0], INIT[5*4+0], INIT[4*4+0],
-         INIT[3*4+0], INIT[2*4+0], INIT[1*4+0], INIT[0*4+0]}),
-.INIT_D1({INIT[15*4+1], INIT[14*4+1], INIT[13*4+1], INIT[12*4+1],
-         INIT[11*4+1], INIT[10*4+1], INIT[9*4+1], INIT[8*4+1],
-         INIT[7*4+1], INIT[6*4+1], INIT[5*4+1], INIT[4*4+1],
-         INIT[3*4+1], INIT[2*4+1], INIT[1*4+1], INIT[0*4+1]}),
-.INIT_D2({INIT[15*4+2], INIT[14*4+2], INIT[13*4+2], INIT[12*4+2],
-         INIT[11*4+2], INIT[10*4+2], INIT[9*4+2], INIT[8*4+2],
-         INIT[7*4+2], INIT[6*4+2], INIT[5*4+2], INIT[4*4+2],
-         INIT[3*4+2], INIT[2*4+2], INIT[1*4+2], INIT[0*4+2]}),
-.INIT_D3({INIT[15*4+3], INIT[14*4+3], INIT[13*4+3], INIT[12*4+3],
-         INIT[11*4+3], INIT[10*4+3], INIT[9*4+3], INIT[8*4+3],
-         INIT[7*4+3], INIT[6*4+3], INIT[5*4+3], INIT[4*4+3],
-         INIT[3*4+3], INIT[2*4+3], INIT[1*4+3], INIT[0*4+3]})
index 4e903c0a2a5746bc6cee81da34384dacd5079971..ef6fec24e306e7b29e1e070216052ffb46f1b440 100644 (file)
@@ -1,16 +1,12 @@
-bram $__ANLOGIC_DRAM16X4
-  init 1
-  abits 4
-  dbits 4
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 1
-endbram
-
-match $__ANLOGIC_DRAM16X4
-  make_outreg
-endmatch
+ram distributed $__ANLOGIC_DRAM16X4_ {
+       abits 4;
+       width 4;
+       cost 4;
+       init no_undef;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
index 5a464cafc3e8c693aa6cc6ad905fdbc2468bd6f9..6314da22a27c397bc677f8057170f004c1300af4 100644 (file)
@@ -1,22 +1,32 @@
-module \$__ANLOGIC_DRAM16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0]INIT = 64'bx;
-       input CLK1;
+module $__ANLOGIC_DRAM16X4_ (...);
+       parameter INIT = 64'b0;
 
-       input [3:0] A1ADDR;
-       output [3:0] A1DATA;
+       input PORT_W_CLK;
+       input [3:0] PORT_W_ADDR;
+       input [3:0] PORT_W_WR_DATA;
+       input PORT_W_WR_EN;
 
-       input [3:0] B1ADDR;
-       input [3:0] B1DATA;
-       input B1EN;
+       input [3:0] PORT_R_ADDR;
+       output [3:0] PORT_R_RD_DATA;
+
+       function [15:0] init_slice;
+               input integer idx;
+               integer i;
+               for (i = 0; i < 16; i = i + 1)
+                       init_slice[i] = INIT[i * 4 + idx];
+       endfunction
 
        EG_LOGIC_DRAM16X4 #(
-               `include "lutram_init_16x4.vh"
+               .INIT_D0(init_slice(0)),
+               .INIT_D1(init_slice(1)),
+               .INIT_D2(init_slice(2)),
+               .INIT_D3(init_slice(3))
        ) _TECHMAP_REPLACE_ (
-               .di(B1DATA),
-               .waddr(B1ADDR),
-               .wclk(CLK1),
-               .we(B1EN),
-               .raddr(A1ADDR),
-               .do(A1DATA)
+               .di(PORT_W_WR_DATA),
+               .waddr(PORT_W_ADDR),
+               .wclk(PORT_W_CLK),
+               .we(PORT_W_WR_EN),
+               .raddr(PORT_R_ADDR),
+               .do(PORT_R_RD_DATA)
        );
 endmodule
index 5da14c26b84ef783c201038454c8ae4996e1b3a0..a3c1e0434f2ba937b84ceb4cbc2f694e8f4b0be8 100644 (file)
@@ -166,19 +166,17 @@ struct SynthAnlogicPass : public ScriptPass
                        run("synth -run coarse");
                }
 
-               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
+               if (check_label("map_ram"))
                {
-                       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");
-                       run("techmap -map +/anlogic/lutrams_map.v");
-                       run("setundef -zero -params t:EG_LOGIC_DRAM16X4");
+                       std::string args = "";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (nolutram)
+                               args += " -no-auto-distributed";
+                       if (help_mode)
+                               args += " [-no-auto-block] [-no-auto-distributed]";
+                       run("memory_libmap -lib +/anlogic/lutrams.txt -lib +/anlogic/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
+                       run("techmap -map +/anlogic/lutrams_map.v -map +/anlogic/brams_map.v");
                }
 
                if (check_label("map_ffram"))
diff --git a/techlibs/ecp5/.gitignore b/techlibs/ecp5/.gitignore
deleted file mode 100644 (file)
index 9d47232..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-bram_init_1_2_4.vh
-bram_init_9_18_36.vh
-brams_init.mk
-bram_conn_1.vh
-bram_conn_2.vh
-bram_conn_4.vh
-bram_conn_9.vh
-bram_conn_18.vh
-bram_conn_36.vh
-brams_connect.mk
index 4c1bc23b544dabfba1d3a7b72eaf70bb00aabc68..f9fa79ab9ad9ce3db6930544220b36f615b186d3 100644 (file)
@@ -1,15 +1,6 @@
 
 OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_gsr.o
 
-GENFILES += techlibs/ecp5/bram_init_1_2_4.vh
-GENFILES += techlibs/ecp5/bram_init_9_18_36.vh
-GENFILES += techlibs/ecp5/bram_conn_1.vh
-GENFILES += techlibs/ecp5/bram_conn_2.vh
-GENFILES += techlibs/ecp5/bram_conn_4.vh
-GENFILES += techlibs/ecp5/bram_conn_9.vh
-GENFILES += techlibs/ecp5/bram_conn_18.vh
-GENFILES += techlibs/ecp5/bram_conn_36.vh
-
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh))
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh))
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v))
@@ -22,37 +13,3 @@ $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/brams.txt))
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/arith_map.v))
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/latches_map.v))
 $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/dsp_map.v))
-
-EXTRA_OBJS += techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
-.SECONDARY: techlibs/ecp5/brams_init.mk techlibs/ecp5/brams_connect.mk
-
-techlibs/ecp5/brams_init.mk: techlibs/ecp5/brams_init.py
-       $(Q) mkdir -p techlibs/ecp5
-       $(P) $(PYTHON_EXECUTABLE) $<
-       $(Q) touch $@
-
-techlibs/ecp5/brams_connect.mk: techlibs/ecp5/brams_connect.py
-       $(Q) mkdir -p techlibs/ecp5
-       $(P) $(PYTHON_EXECUTABLE) $<
-       $(Q) touch $@
-
-
-techlibs/ecp5/bram_init_1_2_4.vh: techlibs/ecp5/brams_init.mk
-techlibs/ecp5/bram_init_9_18_36.vh: techlibs/ecp5/brams_init.mk
-
-techlibs/ecp5/bram_conn_1.vh: techlibs/ecp5/brams_connect.mk
-techlibs/ecp5/bram_conn_2.vh: techlibs/ecp5/brams_connect.mk
-techlibs/ecp5/bram_conn_4.vh: techlibs/ecp5/brams_connect.mk
-techlibs/ecp5/bram_conn_9.vh: techlibs/ecp5/brams_connect.mk
-techlibs/ecp5/bram_conn_18.vh: techlibs/ecp5/brams_connect.mk
-techlibs/ecp5/bram_conn_36.vh: techlibs/ecp5/brams_connect.mk
-
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_1_2_4.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_init_9_18_36.vh))
-
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_1.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_2.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_4.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_9.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_18.vh))
-$(eval $(call add_gen_share_file,share/ecp5,techlibs/ecp5/bram_conn_36.vh))
index 615d8b2e518d711623fd546a2d6b857d356d9165..db28a40d71861e0010659ec7c661f8d612a2f4e7 100644 (file)
-bram $__ECP5_PDPW16KD
-  init 1
-
-  abits 9
-  dbits 36
-
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 4 1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__ECP5_DP16KD
-  init 1
-
-  abits 10 @a10d18
-  dbits 18 @a10d18
-  abits 11 @a11d9
-  dbits 9  @a11d9
-  abits 12 @a12d4
-  dbits 4  @a12d4
-  abits 13 @a13d2
-  dbits 2  @a13d2
-  abits 14 @a14d1
-  dbits 1  @a14d1
-
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 2 1 @a10d18
-  enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 2
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-# The syn_* attributes are described in:
-# https://www.latticesemi.com/view_document?document_id=51556
-attr_icase 1
-
-match $__ECP5_PDPW16KD
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 2048
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ECP5_PDPW16KD
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ECP5_PDPW16KD
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ECP5_DP16KD
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 2048
-  min efficiency 5
-  shuffle_enable A
-  or_next_if_better
-endmatch
-
-match $__ECP5_DP16KD
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  or_next_if_better
-endmatch
-
-match $__ECP5_DP16KD
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-endmatch
+ram block $__ECP5_DP16KD_ {
+       abits 14;
+       widths 1 2 4 9 18 per_port;
+       byte 9;
+       cost 128;
+       init no_undef;
+       port srsw "A" "B" {
+               clock anyedge;
+               clken;
+               wrbe_separate;
+               portoption "WRITEMODE" "NORMAL" {
+                       rdwr no_change;
+               }
+               portoption "WRITEMODE" "WRITETHROUGH" {
+                       rdwr new;
+               }
+               portoption "WRITEMODE" "READBEFOREWRITE" {
+                       rdwr old;
+               }
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated block_wr;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+}
+
+ram block $__ECP5_PDPW16KD_ {
+       abits 14;
+       widths 1 2 4 9 18 36 per_port;
+       byte 9;
+       cost 128;
+       init no_undef;
+       port sr "R" {
+               clock anyedge;
+               clken;
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+       port sw "W" {
+               width 36;
+               clock anyedge;
+               clken;
+       }
+}
diff --git a/techlibs/ecp5/brams_connect.py b/techlibs/ecp5/brams_connect.py
deleted file mode 100755 (executable)
index 098607c..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/env python3
-
-def write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits):
-    ada_conn = [".ADA%d(%s)" % (i, ada_bits[i]) for i in range(len(ada_bits))]
-    adb_conn = [".ADB%d(%s)" % (i, adb_bits[i]) for i in range(len(adb_bits))]
-    dia_conn = [".DIA%d(%s)" % (i, dia_bits[i]) for i in range(len(dia_bits))]
-    dob_conn = [".DOB%d(%s)" % (i, dob_bits[i]) for i in range(len(dob_bits))]
-    print("    %s," % ", ".join(ada_conn), file=f)
-    print("    %s," % ", ".join(adb_conn), file=f)
-    print("    %s," % ", ".join(dia_conn), file=f)
-    print("    %s," % ", ".join(dob_conn), file=f)
-
-def write_bus_ports_pdp(f, adw_bits, adr_bits, di_bits, do_bits, be_bits):
-    adw_conn = [".ADW%d(%s)" % (i, adw_bits[i]) for i in range(len(adw_bits))]
-    adr_conn = [".ADR%d(%s)" % (i, adr_bits[i]) for i in range(len(adr_bits))]
-    di_conn = [".DI%d(%s)" % (i, di_bits[i]) for i in range(len(di_bits))]
-    do_conn = [".DO%d(%s)" % (i, do_bits[i]) for i in range(len(do_bits))]
-    be_conn = [".BE%d(%s)" % (i, be_bits[i]) for i in range(len(be_bits))]
-    print("    %s," % ", ".join(adw_conn), file=f)
-    print("    %s," % ", ".join(adr_conn), file=f)
-    print("    %s," % ", ".join(di_conn), file=f)
-    print("    %s," % ", ".join(do_conn), file=f)
-    print("    %s," % ", ".join(be_conn), file=f)
-
-with open("techlibs/ecp5/bram_conn_1.vh", "w") as f:
-    ada_bits = ["A1ADDR[%d]" % i for i in range(14)]
-    adb_bits = ["B1ADDR[%d]" % i for i in range(14)]
-    dia_bits = ["A1DATA[0]"] + ["1'b0" for i in range(17)]
-    dob_bits = ["B1DATA[0]"]
-    write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
-
-with open("techlibs/ecp5/bram_conn_2.vh", "w") as f:
-    ada_bits = ["1'b0"] + ["A1ADDR[%d]" % i for i in range(13)]
-    adb_bits = ["1'b0"] + ["B1ADDR[%d]" % i for i in range(13)]
-    dia_bits = ["A1DATA[%d]" % i for i in range(2)] + ["1'b0" for i in range(16)]
-    dob_bits = ["B1DATA[%d]" % i for i in range(2)]
-    write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
-
-with open("techlibs/ecp5/bram_conn_4.vh", "w") as f:
-    ada_bits = ["1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(12)]
-    adb_bits = ["1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(12)]
-    dia_bits = ["A1DATA[%d]" % i for i in range(4)] + ["1'b0" for i in range(14)]
-    dob_bits = ["B1DATA[%d]" % i for i in range(4)]
-    write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
-
-with open("techlibs/ecp5/bram_conn_9.vh", "w") as f:
-    ada_bits = ["1'b0", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(11)]
-    adb_bits = ["1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(11)]
-    dia_bits = ["A1DATA[%d]" % i for i in range(9)] + ["1'b0" for i in range(9)]
-    dob_bits = ["B1DATA[%d]" % i for i in range(9)]
-    write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
-
-with open("techlibs/ecp5/bram_conn_18.vh", "w") as f:
-    ada_bits = ["A1EN[0]", "A1EN[1]", "1'b0", "1'b0"] + ["A1ADDR[%d]" % i for i in range(10)]
-    adb_bits = ["1'b0", "1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(10)]
-    dia_bits = ["A1DATA[%d]" % i for i in range(18)]
-    dob_bits = ["B1DATA[%d]" % i for i in range(18)]
-    write_bus_ports(f, ada_bits, adb_bits, dia_bits, dob_bits)
-
-with open("techlibs/ecp5/bram_conn_36.vh", "w") as f:
-    adw_bits = ["A1ADDR[%d]" % i for i in range(9)]
-    adr_bits = ["1'b0", "1'b0", "1'b0", "1'b0", "1'b0"] + ["B1ADDR[%d]" % i for i in range(9)]
-    di_bits = ["A1DATA[%d]" % i for i in range(36)]
-    do_bits = ["B1DATA[%d]" % (i + 18) for i in range(18)] + ["B1DATA[%d]" % i for i in range(18)]
-    be_bits = ["A1EN[%d]" % i for i in range(4)]
-    write_bus_ports_pdp(f, adw_bits, adr_bits, di_bits, do_bits, be_bits)
diff --git a/techlibs/ecp5/brams_init.py b/techlibs/ecp5/brams_init.py
deleted file mode 100755 (executable)
index 96a47bd..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/usr/bin/env python3
-with open("techlibs/ecp5/bram_init_1_2_4.vh", "w") as f:
-    for i in range(0, 0x40):
-        init_snippets = []
-        for j in range(32):
-            init_snippets.append("INIT[%4d*8 +: 8]" % (32 * i + j))
-            init_snippets.append("3'b000" if (j % 2 == 1) else "1'b0")
-        init_snippets = list(reversed(init_snippets))
-        for k in range(8, 64, 8):
-            init_snippets[k] = "\n          " + init_snippets[k]
-        print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
-
-with open("techlibs/ecp5/bram_init_9_18_36.vh", "w") as f:
-    for i in range(0, 0x40):
-        init_snippets = []
-        for j in range(16):
-            init_snippets.append("INIT[%3d*18 +: 18]" % (16 * i + j))
-            init_snippets.append("2'b00")
-        init_snippets = list(reversed(init_snippets))
-        for k in range(8, 32, 8):
-            init_snippets[k] = "\n          " + init_snippets[k]
-        print(".INITVAL_%02X({%s})," % (i, ", ".join(init_snippets)), file=f)
index edda17c02b1e2733ddfbd81382c89704dc05d32d..22e6e068e8d2634a88cfdb2b79e564fca5fa57a8 100644 (file)
-module \$__ECP5_DP16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 18;
-       parameter CFG_ENABLE_A = 2;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'bx;
-       parameter TRANSP2 = 0;
-
-       input CLK2;
-       input CLK3;
-
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;
-       input [CFG_ENABLE_A-1:0] A1EN;
-
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
-
-       localparam CLKAMUX = CLKPOL2 ? "CLKA" : "INV";
-       localparam CLKBMUX = CLKPOL3 ? "CLKB" : "INV";
-
-       localparam WRITEMODE_A = TRANSP2 ? "WRITETHROUGH" : "READBEFOREWRITE";
-
-       generate if (CFG_DBITS == 1) begin
-               DP16KD #(
-                       `include "bram_init_1_2_4.vh"
-                       .DATA_WIDTH_A(1),
-                       .DATA_WIDTH_B(1),
-                       .CLKAMUX(CLKAMUX),
-                       .CLKBMUX(CLKBMUX),
-                       .WRITEMODE_A(WRITEMODE_A),
-                       .WRITEMODE_B("READBEFOREWRITE"),
-                       .GSR("AUTO")
-               ) _TECHMAP_REPLACE_ (
-                       `include "bram_conn_1.vh"
-                       .CLKA(CLK2), .CLKB(CLK3),
-                       .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
-                       .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
-                       .RSTA(1'b0), .RSTB(1'b0)
-               );
-       end else if (CFG_DBITS == 2) begin
-               DP16KD #(
-                       `include "bram_init_1_2_4.vh"
-                       .DATA_WIDTH_A(2),
-                       .DATA_WIDTH_B(2),
-                       .CLKAMUX(CLKAMUX),
-                       .CLKBMUX(CLKBMUX),
-                       .WRITEMODE_A(WRITEMODE_A),
-                       .WRITEMODE_B("READBEFOREWRITE"),
-                       .GSR("AUTO")
-               ) _TECHMAP_REPLACE_ (
-                       `include "bram_conn_2.vh"
-                       .CLKA(CLK2), .CLKB(CLK3),
-                       .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
-                       .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
-                       .RSTA(1'b0), .RSTB(1'b0)
-               );
-       end else if (CFG_DBITS <= 4) begin
-               DP16KD #(
-                       `include "bram_init_1_2_4.vh"
-                       .DATA_WIDTH_A(4),
-                       .DATA_WIDTH_B(4),
-                       .CLKAMUX(CLKAMUX),
-                       .CLKBMUX(CLKBMUX),
-                       .WRITEMODE_A(WRITEMODE_A),
-                       .WRITEMODE_B("READBEFOREWRITE"),
-                       .GSR("AUTO")
-               ) _TECHMAP_REPLACE_ (
-                       `include "bram_conn_4.vh"
-                       .CLKA(CLK2), .CLKB(CLK3),
-                       .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
-                       .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
-                       .RSTA(1'b0), .RSTB(1'b0)
-               );
-       end else if (CFG_DBITS <= 9) begin
-               DP16KD #(
-                       `include "bram_init_9_18_36.vh"
-                       .DATA_WIDTH_A(9),
-                       .DATA_WIDTH_B(9),
-                       .CLKAMUX(CLKAMUX),
-                       .CLKBMUX(CLKBMUX),
-                       .WRITEMODE_A(WRITEMODE_A),
-                       .WRITEMODE_B("READBEFOREWRITE"),
-                       .GSR("AUTO")
-               ) _TECHMAP_REPLACE_ (
-                       `include "bram_conn_9.vh"
-                       .CLKA(CLK2), .CLKB(CLK3),
-                       .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
-                       .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
-                       .RSTA(1'b0), .RSTB(1'b0)
-               );
-       end else if (CFG_DBITS <= 18) begin
-               DP16KD #(
-                       `include "bram_init_9_18_36.vh"
-                       .DATA_WIDTH_A(18),
-                       .DATA_WIDTH_B(18),
-                       .CLKAMUX(CLKAMUX),
-                       .CLKBMUX(CLKBMUX),
-                       .WRITEMODE_A(WRITEMODE_A),
-                       .WRITEMODE_B("READBEFOREWRITE"),
-                       .GSR("AUTO")
-               ) _TECHMAP_REPLACE_ (
-                       `include "bram_conn_18.vh"
-                       .CLKA(CLK2), .CLKB(CLK3),
-                       .WEA(|A1EN), .CEA(1'b1), .OCEA(1'b1),
-                       .WEB(1'b0), .CEB(B1EN), .OCEB(1'b1),
-                       .RSTA(1'b0), .RSTB(1'b0)
-               );
-       end else begin
-               wire TECHMAP_FAIL = 1'b1;
-       end endgenerate
+module $__ECP5_DP16KD_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_A_WIDTH = 18;
+parameter PORT_A_WR_BE_WIDTH = 2;
+parameter PORT_A_CLK_POL = 1;
+parameter PORT_A_OPTION_WRITEMODE = "NORMAL";
+
+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_WR_BE_WIDTH-1:0] PORT_A_WR_BE;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+
+parameter PORT_B_WIDTH = 18;
+parameter PORT_B_WR_BE_WIDTH = 2;
+parameter PORT_B_CLK_POL = 1;
+parameter PORT_B_OPTION_WRITEMODE = "NORMAL";
+
+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_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [17:0] DOA;
+wire [17:0] DOB;
+wire [17:0] DIA = PORT_A_WR_DATA;
+wire [17:0] DIB = PORT_B_WR_DATA;
+
+assign PORT_A_RD_DATA = DOA;
+assign PORT_B_RD_DATA = DOB;
+
+DP16KD #(
+       .INITVAL_00(init_slice('h00)),
+       .INITVAL_01(init_slice('h01)),
+       .INITVAL_02(init_slice('h02)),
+       .INITVAL_03(init_slice('h03)),
+       .INITVAL_04(init_slice('h04)),
+       .INITVAL_05(init_slice('h05)),
+       .INITVAL_06(init_slice('h06)),
+       .INITVAL_07(init_slice('h07)),
+       .INITVAL_08(init_slice('h08)),
+       .INITVAL_09(init_slice('h09)),
+       .INITVAL_0A(init_slice('h0a)),
+       .INITVAL_0B(init_slice('h0b)),
+       .INITVAL_0C(init_slice('h0c)),
+       .INITVAL_0D(init_slice('h0d)),
+       .INITVAL_0E(init_slice('h0e)),
+       .INITVAL_0F(init_slice('h0f)),
+       .INITVAL_10(init_slice('h10)),
+       .INITVAL_11(init_slice('h11)),
+       .INITVAL_12(init_slice('h12)),
+       .INITVAL_13(init_slice('h13)),
+       .INITVAL_14(init_slice('h14)),
+       .INITVAL_15(init_slice('h15)),
+       .INITVAL_16(init_slice('h16)),
+       .INITVAL_17(init_slice('h17)),
+       .INITVAL_18(init_slice('h18)),
+       .INITVAL_19(init_slice('h19)),
+       .INITVAL_1A(init_slice('h1a)),
+       .INITVAL_1B(init_slice('h1b)),
+       .INITVAL_1C(init_slice('h1c)),
+       .INITVAL_1D(init_slice('h1d)),
+       .INITVAL_1E(init_slice('h1e)),
+       .INITVAL_1F(init_slice('h1f)),
+       .INITVAL_20(init_slice('h20)),
+       .INITVAL_21(init_slice('h21)),
+       .INITVAL_22(init_slice('h22)),
+       .INITVAL_23(init_slice('h23)),
+       .INITVAL_24(init_slice('h24)),
+       .INITVAL_25(init_slice('h25)),
+       .INITVAL_26(init_slice('h26)),
+       .INITVAL_27(init_slice('h27)),
+       .INITVAL_28(init_slice('h28)),
+       .INITVAL_29(init_slice('h29)),
+       .INITVAL_2A(init_slice('h2a)),
+       .INITVAL_2B(init_slice('h2b)),
+       .INITVAL_2C(init_slice('h2c)),
+       .INITVAL_2D(init_slice('h2d)),
+       .INITVAL_2E(init_slice('h2e)),
+       .INITVAL_2F(init_slice('h2f)),
+       .INITVAL_30(init_slice('h30)),
+       .INITVAL_31(init_slice('h31)),
+       .INITVAL_32(init_slice('h32)),
+       .INITVAL_33(init_slice('h33)),
+       .INITVAL_34(init_slice('h34)),
+       .INITVAL_35(init_slice('h35)),
+       .INITVAL_36(init_slice('h36)),
+       .INITVAL_37(init_slice('h37)),
+       .INITVAL_38(init_slice('h38)),
+       .INITVAL_39(init_slice('h39)),
+       .INITVAL_3A(init_slice('h3a)),
+       .INITVAL_3B(init_slice('h3b)),
+       .INITVAL_3C(init_slice('h3c)),
+       .INITVAL_3D(init_slice('h3d)),
+       .INITVAL_3E(init_slice('h3e)),
+       .INITVAL_3F(init_slice('h3f)),
+       .DATA_WIDTH_A(PORT_A_WIDTH),
+       .DATA_WIDTH_B(PORT_B_WIDTH),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CSDECODE_A("0b000"),
+       .CSDECODE_B("0b000"),
+       .CLKAMUX(PORT_A_CLK_POL ? "CLKA" : "INV"),
+       .CLKBMUX(PORT_B_CLK_POL ? "CLKB" : "INV"),
+       .WRITEMODE_A(PORT_A_OPTION_WRITEMODE),
+       .WRITEMODE_B(PORT_B_OPTION_WRITEMODE),
+       .GSR("AUTO")
+) _TECHMAP_REPLACE_ (
+       .CLKA(PORT_A_CLK),
+       .WEA(PORT_A_WIDTH == 18 ? PORT_A_WR_EN : (PORT_A_WR_EN | PORT_A_WR_BE[0])),
+       .CEA(PORT_A_CLK_EN),
+       .OCEA(1'b1),
+       .RSTA(OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+       .CSA0(1'b0),
+       .CSA1(1'b0),
+       .CSA2(1'b0),
+       .ADA0(PORT_A_WIDTH == 18 ? PORT_A_WR_BE[0] : PORT_A_ADDR[0]),
+       .ADA1(PORT_A_WIDTH == 18 ? PORT_A_WR_BE[1] : PORT_A_ADDR[1]),
+       .ADA2(PORT_A_ADDR[2]),
+       .ADA3(PORT_A_ADDR[3]),
+       .ADA4(PORT_A_ADDR[4]),
+       .ADA5(PORT_A_ADDR[5]),
+       .ADA6(PORT_A_ADDR[6]),
+       .ADA7(PORT_A_ADDR[7]),
+       .ADA8(PORT_A_ADDR[8]),
+       .ADA9(PORT_A_ADDR[9]),
+       .ADA10(PORT_A_ADDR[10]),
+       .ADA11(PORT_A_ADDR[11]),
+       .ADA12(PORT_A_ADDR[12]),
+       .ADA13(PORT_A_ADDR[13]),
+       .DIA0(DIA[0]),
+       .DIA1(DIA[1]),
+       .DIA2(DIA[2]),
+       .DIA3(DIA[3]),
+       .DIA4(DIA[4]),
+       .DIA5(DIA[5]),
+       .DIA6(DIA[6]),
+       .DIA7(DIA[7]),
+       .DIA8(DIA[8]),
+       .DIA9(DIA[9]),
+       .DIA10(DIA[10]),
+       .DIA11(DIA[11]),
+       .DIA12(DIA[12]),
+       .DIA13(DIA[13]),
+       .DIA14(DIA[14]),
+       .DIA15(DIA[15]),
+       .DIA16(DIA[16]),
+       .DIA17(DIA[17]),
+       .DOA0(DOA[0]),
+       .DOA1(DOA[1]),
+       .DOA2(DOA[2]),
+       .DOA3(DOA[3]),
+       .DOA4(DOA[4]),
+       .DOA5(DOA[5]),
+       .DOA6(DOA[6]),
+       .DOA7(DOA[7]),
+       .DOA8(DOA[8]),
+       .DOA9(DOA[9]),
+       .DOA10(DOA[10]),
+       .DOA11(DOA[11]),
+       .DOA12(DOA[12]),
+       .DOA13(DOA[13]),
+       .DOA14(DOA[14]),
+       .DOA15(DOA[15]),
+       .DOA16(DOA[16]),
+       .DOA17(DOA[17]),
+
+       .CLKB(PORT_B_CLK),
+       .WEB(PORT_B_WIDTH == 18 ? PORT_B_WR_EN : (PORT_B_WR_EN | PORT_B_WR_BE[0])),
+       .CEB(PORT_B_CLK_EN),
+       .OCEB(1'b1),
+       .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+       .CSB0(1'b0),
+       .CSB1(1'b0),
+       .CSB2(1'b0),
+       .ADB0(PORT_B_WIDTH == 18 ? PORT_B_WR_BE[0] : PORT_B_ADDR[0]),
+       .ADB1(PORT_B_WIDTH == 18 ? PORT_B_WR_BE[1] : PORT_B_ADDR[1]),
+       .ADB2(PORT_B_ADDR[2]),
+       .ADB3(PORT_B_ADDR[3]),
+       .ADB4(PORT_B_ADDR[4]),
+       .ADB5(PORT_B_ADDR[5]),
+       .ADB6(PORT_B_ADDR[6]),
+       .ADB7(PORT_B_ADDR[7]),
+       .ADB8(PORT_B_ADDR[8]),
+       .ADB9(PORT_B_ADDR[9]),
+       .ADB10(PORT_B_ADDR[10]),
+       .ADB11(PORT_B_ADDR[11]),
+       .ADB12(PORT_B_ADDR[12]),
+       .ADB13(PORT_B_ADDR[13]),
+       .DIB0(DIB[0]),
+       .DIB1(DIB[1]),
+       .DIB2(DIB[2]),
+       .DIB3(DIB[3]),
+       .DIB4(DIB[4]),
+       .DIB5(DIB[5]),
+       .DIB6(DIB[6]),
+       .DIB7(DIB[7]),
+       .DIB8(DIB[8]),
+       .DIB9(DIB[9]),
+       .DIB10(DIB[10]),
+       .DIB11(DIB[11]),
+       .DIB12(DIB[12]),
+       .DIB13(DIB[13]),
+       .DIB14(DIB[14]),
+       .DIB15(DIB[15]),
+       .DIB16(DIB[16]),
+       .DIB17(DIB[17]),
+       .DOB0(DOB[0]),
+       .DOB1(DOB[1]),
+       .DOB2(DOB[2]),
+       .DOB3(DOB[3]),
+       .DOB4(DOB[4]),
+       .DOB5(DOB[5]),
+       .DOB6(DOB[6]),
+       .DOB7(DOB[7]),
+       .DOB8(DOB[8]),
+       .DOB9(DOB[9]),
+       .DOB10(DOB[10]),
+       .DOB11(DOB[11]),
+       .DOB12(DOB[12]),
+       .DOB13(DOB[13]),
+       .DOB14(DOB[14]),
+       .DOB15(DOB[15]),
+       .DOB16(DOB[16]),
+       .DOB17(DOB[17]),
+);
+
 endmodule
 
-module \$__ECP5_PDPW16KD (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_A = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;
-       input [CFG_ENABLE_A-1:0] A1EN;
-
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
-
-       localparam CLKWMUX = CLKPOL2 ? "CLKA" : "INV";
-       localparam CLKRMUX = CLKPOL3 ? "CLKB" : "INV";
-
-       PDPW16KD #(
-               `include "bram_init_9_18_36.vh"
-               .DATA_WIDTH_W(36),
-               .DATA_WIDTH_R(36),
-               .CLKWMUX(CLKWMUX),
-               .CLKRMUX(CLKRMUX),
-               .GSR("AUTO")
-       ) _TECHMAP_REPLACE_ (
-               `include "bram_conn_36.vh"
-               .CLKW(CLK2), .CLKR(CLK3),
-               .CEW(1'b1),
-               .CER(B1EN), .OCER(1'b1),
-               .RST(1'b0)
-       );
+
+module $__ECP5_PDPW16KD_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_R_WIDTH = 36;
+parameter PORT_R_CLK_POL = 1;
+
+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;
+
+parameter PORT_W_WIDTH = 36;
+parameter PORT_W_WR_EN_WIDTH = 4;
+parameter PORT_W_CLK_POL = 1;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [13:0] PORT_W_ADDR;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [35:0] DI = PORT_W_WR_DATA;
+wire [35:0] DO;
+
+assign PORT_R_RD_DATA = PORT_R_WIDTH == 36 ? DO : DO[35:18];
+
+DP16KD #(
+       .INITVAL_00(init_slice('h00)),
+       .INITVAL_01(init_slice('h01)),
+       .INITVAL_02(init_slice('h02)),
+       .INITVAL_03(init_slice('h03)),
+       .INITVAL_04(init_slice('h04)),
+       .INITVAL_05(init_slice('h05)),
+       .INITVAL_06(init_slice('h06)),
+       .INITVAL_07(init_slice('h07)),
+       .INITVAL_08(init_slice('h08)),
+       .INITVAL_09(init_slice('h09)),
+       .INITVAL_0A(init_slice('h0a)),
+       .INITVAL_0B(init_slice('h0b)),
+       .INITVAL_0C(init_slice('h0c)),
+       .INITVAL_0D(init_slice('h0d)),
+       .INITVAL_0E(init_slice('h0e)),
+       .INITVAL_0F(init_slice('h0f)),
+       .INITVAL_10(init_slice('h10)),
+       .INITVAL_11(init_slice('h11)),
+       .INITVAL_12(init_slice('h12)),
+       .INITVAL_13(init_slice('h13)),
+       .INITVAL_14(init_slice('h14)),
+       .INITVAL_15(init_slice('h15)),
+       .INITVAL_16(init_slice('h16)),
+       .INITVAL_17(init_slice('h17)),
+       .INITVAL_18(init_slice('h18)),
+       .INITVAL_19(init_slice('h19)),
+       .INITVAL_1A(init_slice('h1a)),
+       .INITVAL_1B(init_slice('h1b)),
+       .INITVAL_1C(init_slice('h1c)),
+       .INITVAL_1D(init_slice('h1d)),
+       .INITVAL_1E(init_slice('h1e)),
+       .INITVAL_1F(init_slice('h1f)),
+       .INITVAL_20(init_slice('h20)),
+       .INITVAL_21(init_slice('h21)),
+       .INITVAL_22(init_slice('h22)),
+       .INITVAL_23(init_slice('h23)),
+       .INITVAL_24(init_slice('h24)),
+       .INITVAL_25(init_slice('h25)),
+       .INITVAL_26(init_slice('h26)),
+       .INITVAL_27(init_slice('h27)),
+       .INITVAL_28(init_slice('h28)),
+       .INITVAL_29(init_slice('h29)),
+       .INITVAL_2A(init_slice('h2a)),
+       .INITVAL_2B(init_slice('h2b)),
+       .INITVAL_2C(init_slice('h2c)),
+       .INITVAL_2D(init_slice('h2d)),
+       .INITVAL_2E(init_slice('h2e)),
+       .INITVAL_2F(init_slice('h2f)),
+       .INITVAL_30(init_slice('h30)),
+       .INITVAL_31(init_slice('h31)),
+       .INITVAL_32(init_slice('h32)),
+       .INITVAL_33(init_slice('h33)),
+       .INITVAL_34(init_slice('h34)),
+       .INITVAL_35(init_slice('h35)),
+       .INITVAL_36(init_slice('h36)),
+       .INITVAL_37(init_slice('h37)),
+       .INITVAL_38(init_slice('h38)),
+       .INITVAL_39(init_slice('h39)),
+       .INITVAL_3A(init_slice('h3a)),
+       .INITVAL_3B(init_slice('h3b)),
+       .INITVAL_3C(init_slice('h3c)),
+       .INITVAL_3D(init_slice('h3d)),
+       .INITVAL_3E(init_slice('h3e)),
+       .INITVAL_3F(init_slice('h3f)),
+       .DATA_WIDTH_A(PORT_W_WIDTH),
+       .DATA_WIDTH_B(PORT_R_WIDTH),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CSDECODE_A("0b000"),
+       .CSDECODE_B("0b000"),
+       .CLKAMUX(PORT_W_CLK_POL ? "CLKA" : "INV"),
+       .CLKBMUX(PORT_R_CLK_POL ? "CLKB" : "INV"),
+       .GSR("AUTO")
+) _TECHMAP_REPLACE_ (
+       .CLKA(PORT_W_CLK),
+       .WEA(PORT_W_WIDTH >= 18 ? 1'b1 : PORT_W_WR_EN[0]),
+       .CEA(PORT_W_CLK_EN),
+       .OCEA(1'b0),
+       .RSTA(1'b0),
+       .CSA0(1'b0),
+       .CSA1(1'b0),
+       .CSA2(1'b0),
+       .ADA0(PORT_W_WIDTH >= 18 ? PORT_W_WR_EN[0] : PORT_W_ADDR[0]),
+       .ADA1(PORT_W_WIDTH >= 18 ? PORT_W_WR_EN[1] : PORT_W_ADDR[1]),
+       .ADA2(PORT_W_WIDTH >= 36 ? PORT_W_WR_EN[2] : PORT_W_ADDR[2]),
+       .ADA3(PORT_W_WIDTH >= 36 ? PORT_W_WR_EN[3] : PORT_W_ADDR[3]),
+       .ADA4(PORT_W_ADDR[4]),
+       .ADA5(PORT_W_ADDR[5]),
+       .ADA6(PORT_W_ADDR[6]),
+       .ADA7(PORT_W_ADDR[7]),
+       .ADA8(PORT_W_ADDR[8]),
+       .ADA9(PORT_W_ADDR[9]),
+       .ADA10(PORT_W_ADDR[10]),
+       .ADA11(PORT_W_ADDR[11]),
+       .ADA12(PORT_W_ADDR[12]),
+       .ADA13(PORT_W_ADDR[13]),
+       .DIA0(DI[0]),
+       .DIA1(DI[1]),
+       .DIA2(DI[2]),
+       .DIA3(DI[3]),
+       .DIA4(DI[4]),
+       .DIA5(DI[5]),
+       .DIA6(DI[6]),
+       .DIA7(DI[7]),
+       .DIA8(DI[8]),
+       .DIA9(DI[9]),
+       .DIA10(DI[10]),
+       .DIA11(DI[11]),
+       .DIA12(DI[12]),
+       .DIA13(DI[13]),
+       .DIA14(DI[14]),
+       .DIA15(DI[15]),
+       .DIA16(DI[16]),
+       .DIA17(DI[17]),
+       .DIB0(DI[18]),
+       .DIB1(DI[19]),
+       .DIB2(DI[20]),
+       .DIB3(DI[21]),
+       .DIB4(DI[22]),
+       .DIB5(DI[23]),
+       .DIB6(DI[24]),
+       .DIB7(DI[25]),
+       .DIB8(DI[26]),
+       .DIB9(DI[27]),
+       .DIB10(DI[28]),
+       .DIB11(DI[29]),
+       .DIB12(DI[30]),
+       .DIB13(DI[31]),
+       .DIB14(DI[32]),
+       .DIB15(DI[33]),
+       .DIB16(DI[34]),
+       .DIB17(DI[35]),
+
+       .CLKB(PORT_R_CLK),
+       .WEB(1'b0),
+       .CEB(PORT_R_CLK_EN),
+       .OCEB(1'b1),
+       .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
+       .CSB0(1'b0),
+       .CSB1(1'b0),
+       .CSB2(1'b0),
+       .ADB0(PORT_R_ADDR[0]),
+       .ADB1(PORT_R_ADDR[1]),
+       .ADB2(PORT_R_ADDR[2]),
+       .ADB3(PORT_R_ADDR[3]),
+       .ADB4(PORT_R_ADDR[4]),
+       .ADB5(PORT_R_ADDR[5]),
+       .ADB6(PORT_R_ADDR[6]),
+       .ADB7(PORT_R_ADDR[7]),
+       .ADB8(PORT_R_ADDR[8]),
+       .ADB9(PORT_R_ADDR[9]),
+       .ADB10(PORT_R_ADDR[10]),
+       .ADB11(PORT_R_ADDR[11]),
+       .ADB12(PORT_R_ADDR[12]),
+       .ADB13(PORT_R_ADDR[13]),
+       .DOA0(DO[0]),
+       .DOA1(DO[1]),
+       .DOA2(DO[2]),
+       .DOA3(DO[3]),
+       .DOA4(DO[4]),
+       .DOA5(DO[5]),
+       .DOA6(DO[6]),
+       .DOA7(DO[7]),
+       .DOA8(DO[8]),
+       .DOA9(DO[9]),
+       .DOA10(DO[10]),
+       .DOA11(DO[11]),
+       .DOA12(DO[12]),
+       .DOA13(DO[13]),
+       .DOA14(DO[14]),
+       .DOA15(DO[15]),
+       .DOA16(DO[16]),
+       .DOA17(DO[17]),
+       .DOB0(DO[18]),
+       .DOB1(DO[19]),
+       .DOB2(DO[20]),
+       .DOB3(DO[21]),
+       .DOB4(DO[22]),
+       .DOB5(DO[23]),
+       .DOB6(DO[24]),
+       .DOB7(DO[25]),
+       .DOB8(DO[26]),
+       .DOB9(DO[27]),
+       .DOB10(DO[28]),
+       .DOB11(DO[29]),
+       .DOB12(DO[30]),
+       .DOB13(DO[31]),
+       .DOB14(DO[32]),
+       .DOB15(DO[33]),
+       .DOB16(DO[34]),
+       .DOB17(DO[35]),
+);
 
 endmodule
index 5370a1ddbd0b28f6bc40e3c6189d72fbd1fb5d3b..ea42d4fcb5ef9e2073466d1c817cbef080eb76b4 100644 (file)
@@ -1,26 +1,12 @@
-bram $__TRELLIS_DPR16X4
-  init 1
-  abits 4
-  dbits 4
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-# The syn_* attributes are described in:
-# https://www.latticesemi.com/view_document?document_id=51556
-attr_icase 1
-
-match $__TRELLIS_DPR16X4
-       attribute !syn_ramstyle syn_ramstyle=auto syn_ramstyle=distributed
-       attribute !syn_romstyle syn_romstyle=auto
-       attribute !ram_block
-       attribute !rom_block
-       attribute !logic_block
-  make_outreg
-  min wports 1
-endmatch
+ram distributed $__TRELLIS_DPR16X4_ {
+       abits 4;
+       width 4;
+       cost 4;
+       init any;
+       prune_rom;
+       port sw "W" {
+               clock anyedge;
+       }
+       port ar "R" {
+       }
+}
index 3b3de831f64aca94a94d110c20f59b45cb556317..3cb325f041e0383661e3d8425829134f9beb6aed 100644 (file)
@@ -1,28 +1,30 @@
-module \$__TRELLIS_DPR16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0] INIT = 64'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
+module $__TRELLIS_DPR16X4_(...);
 
-       input [3:0] A1ADDR;
-       output [3:0] A1DATA;
+parameter INIT = 64'bx;
+parameter PORT_W_CLK_POL = 1;
 
-       input [3:0] B1ADDR;
-       input [3:0] B1DATA;
-       input B1EN;
+input PORT_W_CLK;
+input [3:0] PORT_W_ADDR;
+input [3:0] PORT_W_WR_DATA;
+input PORT_W_WR_EN;
 
-       localparam WCKMUX = CLKPOL2 ? "WCK" : "INV";
+input [3:0] PORT_R_ADDR;
+output [3:0] PORT_R_RD_DATA;
 
-       TRELLIS_DPR16X4 #(
-               .INITVAL(INIT),
-               .WCKMUX(WCKMUX),
-               .WREMUX("WRE")
-       ) _TECHMAP_REPLACE_ (
-               .RAD(A1ADDR),
-               .DO(A1DATA),
+localparam WCKMUX = PORT_W_CLK_POL ? "WCK" : "INV";
+
+TRELLIS_DPR16X4 #(
+       .INITVAL(INIT),
+       .WCKMUX(WCKMUX),
+       .WREMUX("WRE")
+) _TECHMAP_REPLACE_ (
+       .RAD(PORT_R_ADDR),
+       .DO(PORT_R_RD_DATA),
+
+       .WAD(PORT_W_ADDR),
+       .DI(PORT_W_WR_DATA),
+       .WCK(PORT_W_CLK),
+       .WRE(PORT_W_WR_EN)
+);
 
-               .WAD(B1ADDR),
-               .DI(B1DATA),
-               .WCK(CLK1),
-               .WRE(B1EN)
-       );
 endmodule
index eb8ba8b9d11d272cd22e4c16bb630e3848f4e1bf..8c7ea5b396b9796f35bac0441dd26246d8779486 100644 (file)
@@ -277,24 +277,23 @@ struct SynthEcp5Pass : public ScriptPass
                        run("opt_clean");
                }
 
-               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
+               if (check_label("map_ram"))
                {
-                       run("memory_bram -rules +/ecp5/brams.txt");
-                       run("techmap -map +/ecp5/brams_map.v");
-               }
-
-               if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
-               {
-                       run("memory_bram -rules +/ecp5/lutrams.txt");
-                       run("techmap -map +/ecp5/lutrams_map.v");
+                       std::string args = "";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (nolutram)
+                               args += " -no-auto-distributed";
+                       if (help_mode)
+                               args += " [-no-auto-block] [-no-auto-distributed]";
+                       run("memory_libmap -lib +/ecp5/lutrams.txt -lib +/ecp5/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
+                       run("techmap -map +/ecp5/lutrams_map.v -map +/ecp5/brams_map.v");
                }
 
                if (check_label("map_ffram"))
                {
                        run("opt -fast -mux_undef -undriven -fine");
-                       run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
-                           "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
-                           "-attr syn_romstyle=auto -attr syn_romstyle=logic");
+                       run("memory_map");
                        run("opt -undriven -fine");
                }
 
index 0b3fd93080dca67f1b4cc4d092bcdaa6ac0110e4..271fc4fc4dd7b269d5eb078084f7455c54ea72bb 100644 (file)
@@ -1,32 +1,19 @@
-bram $__EFINIX_5K
-  init 1
-
-  abits 8  @a8d16
-  dbits 16 @a8d16
-  abits 9  @a9d8
-  dbits 8  @a9d8
-  abits 10 @a10d4
-  dbits 4  @a10d4
-  abits 11 @a11d2
-  dbits 2  @a11d2
-  abits 12 @a12d1
-  dbits 1  @a12d1
-  abits 8  @a8d20
-  dbits 20 @a8d20
-  abits 9  @a9d10
-  dbits 10 @a9d10
-
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 1 1
-  transp 0 2
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__EFINIX_5K
-  min bits 256
-  min efficiency 5
-  shuffle_enable B
-endmatch
+ram block $__EFINIX_5K_ {
+       abits 12;
+       widths 1 2 5 10 20 per_port;
+       cost 32;
+       init no_undef;
+       port sr "R" {
+               clock anyedge;
+               rden;
+       }
+       port sw "W" {
+               clock anyedge;
+               option "WRITE_MODE" "READ_FIRST" {
+                       wrtrans "R" old;
+               }
+               option "WRITE_MODE" "WRITE_FIRST" {
+                       wrtrans "R" new;
+               }
+       }
+}
index 6786ae76970bc886db9b68328b0615831f39b16c..752010f45ec1d290294bd0e00c83955f95021399 100644 (file)
-module \$__EFINIX_5K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 8;
-       parameter CFG_DBITS = 20;
-       parameter CFG_ENABLE_A = 1;
+module $__EFINIX_5K_ (...);
+       parameter INIT = 0;
+       parameter OPTION_WRITE_MODE = "READ_FIRST";
 
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [5119:0] INIT = 5119'bx;
-       parameter TRANSP2 = 0;
+       parameter PORT_R_WIDTH = 20;
+       parameter PORT_R_CLK_POL = 1;
+       parameter PORT_W_WIDTH = 20;
+       parameter PORT_W_CLK_POL = 1;
 
-       input CLK2;
-       input CLK3;
+       input PORT_R_CLK;
+       input PORT_R_RD_EN;
+       input [11:0] PORT_R_ADDR;
+       output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
 
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;
-       input [CFG_ENABLE_A-1:0] A1EN;
+       input PORT_W_CLK;
+       input PORT_W_WR_EN;
+       input [11:0] PORT_W_ADDR;
+       input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
 
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
+       localparam IS_5BIT = PORT_R_WIDTH >= 5 && PORT_W_WIDTH >= 5;
 
-       localparam WRITEMODE_A = TRANSP2 ? "WRITE_FIRST" : "READ_FIRST";
+       localparam RADDR_WIDTH =
+               PORT_R_WIDTH == 1 ? 12 :
+               PORT_R_WIDTH == 2 ? 11 :
+               PORT_R_WIDTH == 5 ? 10 :
+               PORT_R_WIDTH == 10 ? 9 :
+               8;
+
+       localparam WADDR_WIDTH =
+               PORT_W_WIDTH == 1 ? 12 :
+               PORT_W_WIDTH == 2 ? 11 :
+               PORT_W_WIDTH == 5 ? 10 :
+               PORT_W_WIDTH == 10 ? 9 :
+               8;
+
+       localparam READ_WIDTH = 
+               PORT_R_WIDTH == 1 ? 1 :
+               PORT_R_WIDTH == 2 ? 2 :
+               PORT_R_WIDTH == 5 ? (IS_5BIT ? 5 : 4) :
+               PORT_R_WIDTH == 10 ? (IS_5BIT ? 10 : 8) :
+               (IS_5BIT ? 20 : 16);
+
+       localparam WRITE_WIDTH = 
+               PORT_W_WIDTH == 1 ? 1 :
+               PORT_W_WIDTH == 2 ? 2 :
+               PORT_W_WIDTH == 5 ? (IS_5BIT ? 5 : 4) :
+               PORT_W_WIDTH == 10 ? (IS_5BIT ? 10 : 8) :
+               (IS_5BIT ? 20 : 16);
+
+       wire [RADDR_WIDTH-1:0] RADDR = PORT_R_ADDR[11:12-RADDR_WIDTH];
+       wire [WADDR_WIDTH-1:0] WADDR = PORT_W_ADDR[11:12-WADDR_WIDTH];
+
+       wire [WRITE_WIDTH-1:0] WDATA;
+       wire [READ_WIDTH-1:0] RDATA;
+
+       generate
+               case (WRITE_WIDTH)
+               1:      assign WDATA = PORT_W_WR_DATA;
+               2:      assign WDATA = PORT_W_WR_DATA;
+               4:      assign WDATA = PORT_W_WR_DATA[3:0];
+               5:      assign WDATA = PORT_W_WR_DATA;
+               8:      assign WDATA = {
+                       PORT_W_WR_DATA[8:5],
+                       PORT_W_WR_DATA[3:0]
+               };
+               10:     assign WDATA = PORT_W_WR_DATA;
+               16:     assign WDATA = {
+                       PORT_W_WR_DATA[18:15],
+                       PORT_W_WR_DATA[13:10],
+                       PORT_W_WR_DATA[8:5],
+                       PORT_W_WR_DATA[3:0]
+               };
+               20:     assign WDATA = PORT_W_WR_DATA;
+               endcase
+               case (READ_WIDTH)
+               1:      assign PORT_R_RD_DATA = RDATA;
+               2:      assign PORT_R_RD_DATA = RDATA;
+               4:      assign PORT_R_RD_DATA[3:0] = RDATA;
+               5:      assign PORT_R_RD_DATA = RDATA;
+               8:      assign {
+                       PORT_R_RD_DATA[8:5],
+                       PORT_R_RD_DATA[3:0]
+               } = RDATA;
+               10:     assign PORT_R_RD_DATA = RDATA;
+               16:     assign {
+                       PORT_R_RD_DATA[18:15],
+                       PORT_R_RD_DATA[13:10],
+                       PORT_R_RD_DATA[8:5],
+                       PORT_R_RD_DATA[3:0]
+               } = RDATA;
+               20:     assign PORT_R_RD_DATA = RDATA;
+               endcase
+       endgenerate
+
+       function [255:0] init_slice;
+               input integer idx;
+               integer i;
+               if (IS_5BIT)
+                       init_slice = INIT[idx * 256 +: 256];
+               else if (idx > 16)
+                       init_slice = 0;
+               else
+                       for (i = 0; i < 64; i = i + 1)
+                               init_slice[i*4+:4] = INIT[(idx * 64 + i) * 5+:4];
+       endfunction
 
        EFX_RAM_5K #(
-               .READ_WIDTH(CFG_DBITS),
-               .WRITE_WIDTH(CFG_DBITS),
-               .OUTPUT_REG(1'b0),
-               .RCLK_POLARITY(1'b1),
-               .RE_POLARITY(1'b1),
-               .WCLK_POLARITY(1'b1),
-               .WE_POLARITY(1'b1),
-               .WCLKE_POLARITY(1'b1),
-               .WRITE_MODE(WRITEMODE_A),
-               .INIT_0(INIT[ 0*256 +: 256]),
-               .INIT_1(INIT[ 1*256 +: 256]),
-               .INIT_2(INIT[ 2*256 +: 256]),
-               .INIT_3(INIT[ 3*256 +: 256]),
-               .INIT_4(INIT[ 4*256 +: 256]),
-               .INIT_5(INIT[ 5*256 +: 256]),
-               .INIT_6(INIT[ 6*256 +: 256]),
-               .INIT_7(INIT[ 7*256 +: 256]),
-               .INIT_8(INIT[ 8*256 +: 256]),
-               .INIT_9(INIT[ 9*256 +: 256]),
-               .INIT_A(INIT[10*256 +: 256]),
-               .INIT_B(INIT[11*256 +: 256]),
-               .INIT_C(INIT[12*256 +: 256]),
-               .INIT_D(INIT[13*256 +: 256]),
-               .INIT_E(INIT[14*256 +: 256]),
-               .INIT_F(INIT[15*256 +: 256]),
-               .INIT_10(INIT[16*256 +: 256]),
-               .INIT_11(INIT[17*256 +: 256]),
-               .INIT_12(INIT[18*256 +: 256]),
-               .INIT_13(INIT[19*256 +: 256])
+               .READ_WIDTH(READ_WIDTH),
+               .WRITE_WIDTH(WRITE_WIDTH),
+               .OUTPUT_REG(1'b0),
+               .RCLK_POLARITY(PORT_R_CLK_POL),
+               .RE_POLARITY(1'b1),
+               .WCLK_POLARITY(PORT_W_CLK_POL),
+               .WE_POLARITY(1'b1),
+               .WCLKE_POLARITY(1'b1),
+               .WRITE_MODE(OPTION_WRITE_MODE),
+               .INIT_0(init_slice('h00)),
+               .INIT_1(init_slice('h01)),
+               .INIT_2(init_slice('h02)),
+               .INIT_3(init_slice('h03)),
+               .INIT_4(init_slice('h04)),
+               .INIT_5(init_slice('h05)),
+               .INIT_6(init_slice('h06)),
+               .INIT_7(init_slice('h07)),
+               .INIT_8(init_slice('h08)),
+               .INIT_9(init_slice('h09)),
+               .INIT_A(init_slice('h0a)),
+               .INIT_B(init_slice('h0b)),
+               .INIT_C(init_slice('h0c)),
+               .INIT_D(init_slice('h0d)),
+               .INIT_E(init_slice('h0e)),
+               .INIT_F(init_slice('h0f)),
+               .INIT_10(init_slice('h10)),
+               .INIT_11(init_slice('h11)),
+               .INIT_12(init_slice('h12)),
+               .INIT_13(init_slice('h13)),
        ) _TECHMAP_REPLACE_ (
-               .WDATA(A1DATA),
-               .WADDR(A1ADDR),
-               .WE(A1EN),
-               .WCLK(CLK2),
-               .WCLKE(1'b1),
-               .RDATA(B1DATA),
-               .RADDR(B1ADDR),
-               .RE(B1EN),
-               .RCLK(CLK3)
+               .WDATA(WDATA),
+               .WADDR(WADDR),
+               .WE(PORT_W_WR_EN),
+               .WCLK(PORT_W_CLK),
+               .WCLKE(1'b1),
+               .RDATA(RDATA),
+               .RADDR(RADDR),
+               .RE(PORT_R_RD_EN),
+               .RCLK(PORT_R_CLK)
        );
+
 endmodule
index ace56bee928c1d217b7b6bda9c75daf2d7d5db0c..bbc389444882a560c6aff9768b497d510820bab4 100644 (file)
@@ -158,11 +158,13 @@ struct SynthEfinixPass : public ScriptPass
                        run("synth -run coarse");
                }
 
-               if (!nobram || check_label("map_bram", "(skip if -nobram)"))
+               if (check_label("map_ram"))
                {
-                       run("memory_bram -rules +/efinix/brams.txt");
+                       std::string args = "";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       run("memory_libmap -lib +/efinix/brams.txt" + args);
                        run("techmap -map +/efinix/brams_map.v");
-                       run("setundef -zero -params t:EFX_RAM_5K");
                }
 
                if (check_label("map_ffram"))
index 9e0bebba66d571fa9c9524f913de00d69f70f5b6..a0b500060a7fb83eb368661766e5fc4e1869057a 100644 (file)
-bram $__CC_BRAM_CASCADE
-  init 1
-  abits 16 @a16d1
-  dbits 1  @a16d1
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 1 1 @a16d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__CC_BRAM_40K_SDP
-  init 1
-  abits 9  @a9d80
-  dbits 80 @a9d80
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 80 1 @a9d80
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__CC_BRAM_20K_SDP
-  init 1
-  abits 9  @a9d40
-  dbits 40 @a9d40
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 40 1 @a9d40
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__CC_BRAM_40K_TDP
-  init 1
-  abits 10 @a10d40
-  dbits 40 @a10d40
-  abits 11 @a11d20
-  dbits 20 @a11d20
-  abits 12 @a12d10
-  dbits 10 @a12d10
-  abits 13 @a13d5
-  dbits 5  @a13d5
-  abits 14 @a14d2
-  dbits 2  @a14d2
-  abits 15 @a15d1
-  dbits 1  @a15d1
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 40 1 @a10d40
-  enable 20 1 @a11d20
-  enable 10 1 @a12d10
-  enable 5 1  @a13d5
-  enable 2 1  @a14d2
-  enable 1 1  @a15d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__CC_BRAM_20K_TDP
-  init 1
-  abits 10 @a10d20
-  dbits 20 @a10d20
-  abits 11 @a11d10
-  dbits 10 @a11d10
-  abits 12 @a12d5
-  dbits 5  @a12d5
-  abits 13 @a13d2
-  dbits 2  @a13d2
-  abits 14 @a14d1
-  dbits 1  @a14d1
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 20 1 @a10d20
-  enable 10 1 @a11d10
-  enable 5 1  @a12d5
-  enable 2 1  @a13d2
-  enable 1 1  @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__CC_BRAM_CASCADE
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 512
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_CASCADE
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_CASCADE
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_SDP
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 512
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_SDP
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_SDP
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_SDP
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 512
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_SDP
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_SDP
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_TDP
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 512
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_TDP
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_40K_TDP
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_TDP
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 512
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_TDP
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__CC_BRAM_20K_TDP
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  shuffle_enable A
-  make_transp
-endmatch
+ram block $__CC_BRAM_TDP_ {
+       option "MODE" "20K" {
+               abits 14;
+               widths 1 2 5 10 20 per_port;
+               cost 129;
+       }
+       option "MODE" "40K" {
+               abits 15;
+               widths 1 2 5 10 20 40 per_port;
+               cost 257;
+       }
+       option "MODE" "CASCADE" {
+               abits 16;
+               # hack to enforce same INIT layout as in the other modes
+               widths 1 2 5 per_port;
+               cost 513;
+       }
+       byte 1;
+       init no_undef;
+       port srsw "A" "B" {
+               clock anyedge;
+               clken;
+               option "MODE" "20K" {
+                       width mix;
+               }
+               option "MODE" "40K" {
+                       width mix;
+               }
+               option "MODE" "CASCADE" {
+                       width mix 1;
+               }
+               portoption "WR_MODE" "NO_CHANGE" {
+                       rdwr no_change;
+               }
+               portoption "WR_MODE" "WRITE_THROUGH" {
+                       rdwr new;
+               }
+               wrbe_separate;
+       }
+}
+
+ram block $__CC_BRAM_SDP_ {
+       option "MODE" "20K" {
+               abits 14;
+               widths 1 2 5 10 20 40 per_port;
+               cost 129;
+       }
+       option "MODE" "40K" {
+               abits 15;
+               widths 1 2 5 10 20 40 80 per_port;
+               cost 257;
+       }
+       byte 1;
+       init no_undef;
+       port sr "R" {
+               option "MODE" "20K" {
+                       width 40;
+               }
+               option "MODE" "40K" {
+                       width 80;
+               }
+               clock anyedge;
+               clken;
+       }
+       port sw "W" {
+               option "MODE" "20K" {
+                       width 40;
+               }
+               option "MODE" "40K" {
+                       width 80;
+               }
+               clock anyedge;
+               clken;
+               wrbe_separate;
+       }
+}
index f36f05212d3f0b3425283241311794d1ffd4b6f1..7023f5ef29e793b054b7960efe6d45b8f03c502b 100644 (file)
-/*\r
- *  yosys -- Yosys Open SYnthesis Suite\r
- *\r
- *  Copyright (C) 2021  Cologne Chip AG <support@colognechip.com>\r
- *\r
- *  Permission to use, copy, modify, and/or distribute this software for any\r
- *  purpose with or without fee is hereby granted, provided that the above\r
- *  copyright notice and this permission notice appear in all copies.\r
- *\r
- *  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\r
- *  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\r
- *  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\r
- *  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\r
- *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\r
- *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\r
- *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\r
- *\r
- */\r
-\r
-module \$__CC_BRAM_20K_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);\r
-\r
-       parameter CFG_ABITS = 14;\r
-       parameter CFG_DBITS = 40;\r
-       parameter CFG_ENABLE_A = 1;\r
-       parameter CFG_ENABLE_B = 1;\r
-\r
-       parameter CLKPOL2 = 1;\r
-       parameter CLKPOL3 = 1;\r
-\r
-       // 512 x 40 bit\r
-       parameter [20479:0] INIT = 20480'b0;\r
-\r
-       input CLK2;\r
-       input CLK3;\r
-\r
-       // write side of the memory\r
-       input [15:0] A1ADDR;\r
-       input [39:0] A1DATA;\r
-       input [39:0] A1EN;\r
-\r
-       // read side of the memory\r
-       input [15:0] B1ADDR;\r
-       output [39:0] B1DATA;\r
-       input [0:0] B1EN;\r
-\r
-       // unconnected signals\r
-       wire ECC_1B_ERR, ECC_2B_ERR;\r
-\r
-       // internal signals\r
-       wire [15:0] ADDRA = {A1ADDR, 7'b0};\r
-       wire [15:0] ADDRB = {B1ADDR, 7'b0};\r
-\r
-       localparam INIT_CHUNK_SIZE = 320;\r
-\r
-       function [319:0] permute_init;\r
-               input [INIT_CHUNK_SIZE-1:0] chunk;\r
-               integer i;\r
-               begin\r
-                       permute_init = chunk;\r
-               end\r
-       endfunction\r
-\r
-       CC_BRAM_20K #(\r
-               `include "brams_init_20.vh"\r
-               .LOC("UNPLACED"),\r
-               .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-               .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
-               .RAM_MODE("SDP"),\r
-               .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-               .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-               .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-               .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-               .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-               .ECC_EN(1'b0)\r
-       ) _TECHMAP_REPLACE_ (\r
-               .A_DO(B1DATA[19:0]),\r
-               .B_DO(B1DATA[39:20]),\r
-               .ECC_1B_ERR(ECC_1B_ERR),\r
-               .ECC_2B_ERR(ECC_2B_ERR),\r
-               .A_CLK(CLK2),\r
-               .B_CLK(CLK3),\r
-               .A_EN(1'b1),\r
-               .B_EN(B1EN),\r
-               .A_WE(|A1EN),\r
-               .B_WE(1'b0),\r
-               .A_ADDR(ADDRA),\r
-               .B_ADDR(ADDRB),\r
-               .A_DI(A1DATA[19:0]),\r
-               .B_DI(A1DATA[39:20]),\r
-               .A_BM(A1EN[19:0]),\r
-               .B_BM(A1EN[39:20])\r
-       );\r
-\r
-endmodule\r
-\r
-\r
-module \$__CC_BRAM_40K_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);\r
-\r
-       parameter CFG_ABITS = 15;\r
-       parameter CFG_DBITS = 80;\r
-       parameter CFG_ENABLE_A = 1;\r
-       parameter CFG_ENABLE_B = 1;\r
-\r
-       parameter CLKPOL2 = 1;\r
-       parameter CLKPOL3 = 1;\r
-\r
-       // 512 x 80 bit\r
-       parameter [40959:0] INIT = 40960'b0;\r
-\r
-       input CLK2;\r
-       input CLK3;\r
-\r
-       // write side of the memory\r
-       input [15:0] A1ADDR;\r
-       input [79:0] A1DATA;\r
-       input [79:0] A1EN;\r
-\r
-       // read side of the memory\r
-       input [15:0] B1ADDR;\r
-       output [79:0] B1DATA;\r
-       input [0:0] B1EN;\r
-\r
-       // unconnected signals\r
-       wire A_ECC_1B_ERR, B_ECC_1B_ERR, A_ECC_2B_ERR, B_ECC_2B_ERR;\r
-\r
-       // internal signals\r
-       wire [15:0] ADDRA = {A1ADDR, 7'b0};\r
-       wire [15:0] ADDRB = {B1ADDR, 7'b0};\r
-\r
-       localparam INIT_CHUNK_SIZE = 320;\r
-\r
-       function [319:0] permute_init;\r
-               input [INIT_CHUNK_SIZE-1:0] chunk;\r
-               integer i;\r
-               begin\r
-                       permute_init = chunk;\r
-               end\r
-       endfunction\r
-\r
-       CC_BRAM_40K #(\r
-               `define INIT_LOWER\r
-               `include "brams_init_40.vh"\r
-               `undef INIT_LOWER\r
-               .LOC("UNPLACED"),\r
-               .CAS("NONE"),\r
-               .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-               .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
-               .RAM_MODE("SDP"),\r
-               .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-               .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-               .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-               .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-               .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-               .A_ECC_EN(1'b0), .B_ECC_EN(1'b0)\r
-       ) _TECHMAP_REPLACE_ (\r
-               .A_DO(B1DATA[39:0]),\r
-               .B_DO(B1DATA[79:40]),\r
-               .A_ECC_1B_ERR(A_ECC_1B_ERR),\r
-               .B_ECC_1B_ERR(B_ECC_1B_ERR),\r
-               .A_ECC_2B_ERR(A_ECC_2B_ERR),\r
-               .B_ECC_2B_ERR(B_ECC_2B_ERR),\r
-               .A_CLK(CLK2),\r
-               .B_CLK(CLK3),\r
-               .A_EN(1'b1),\r
-               .B_EN(B1EN),\r
-               .A_WE(|A1EN),\r
-               .B_WE(1'b0),\r
-               .A_ADDR(ADDRA),\r
-               .B_ADDR(ADDRB),\r
-               .A_DI(A1DATA[39:0]),\r
-               .B_DI(A1DATA[79:40]),\r
-               .A_BM(A1EN[39:0]),\r
-               .B_BM(A1EN[79:40])\r
-       );\r
-\r
-endmodule\r
-\r
-\r
-module \$__CC_BRAM_20K_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);\r
-\r
-       parameter CFG_ABITS = 14;\r
-       parameter CFG_DBITS = 20;\r
-       parameter CFG_ENABLE_A = 1;\r
-       parameter CFG_ENABLE_B = 1;\r
-\r
-       parameter CLKPOL2 = 1;\r
-       parameter CLKPOL3 = 1;\r
-\r
-       // 512 x 40 bit\r
-       parameter [20479:0] INIT = 20480'b0;\r
-\r
-       input CLK2;\r
-       input CLK3;\r
-\r
-       // write side of the memory\r
-       input [15:0] A1ADDR;\r
-       input [19:0] A1DATA;\r
-       input [19:0] A1EN;\r
-\r
-       // read side of the memory\r
-       input [15:0] B1ADDR;\r
-       output [19:0] B1DATA;\r
-       input [0:0] B1EN;\r
-\r
-       // unconnected signals\r
-       wire [19:0] A_DO;\r
-       wire ECC_1B_ERR, ECC_2B_ERR;\r
-\r
-       localparam INIT_CHUNK_SIZE = (CFG_DBITS <= 2) ? 256 : 320;\r
-\r
-       function [319:0] permute_init;\r
-               input [INIT_CHUNK_SIZE-1:0] chunk;\r
-               integer i;\r
-               begin\r
-                       if (CFG_DBITS <= 2) begin\r
-                               for (i = 0; i < 64; i = i + 1) begin\r
-                                       permute_init[i * 5 +: 5] = {1'b0, chunk[i * 4 +: 4]};\r
-                               end\r
-                       end else begin\r
-                               permute_init = chunk;\r
-                       end\r
-               end\r
-       endfunction\r
-\r
-       // internal signals\r
-       generate\r
-               wire [15:0] ADDRA;\r
-               wire [15:0] ADDRB;\r
-\r
-               if (CFG_DBITS == 1) begin: blk\r
-                       assign ADDRA = {A1ADDR[13:5], 1'b0, A1ADDR[4:0], 1'b0};\r
-                       assign ADDRB = {B1ADDR[13:5], 1'b0, B1ADDR[4:0], 1'b0};\r
-               end\r
-               else if (CFG_DBITS == 2) begin: blk\r
-                       assign ADDRA = {A1ADDR[12:4], 1'b0, A1ADDR[3:0], 2'b0};\r
-                       assign ADDRB = {B1ADDR[12:4], 1'b0, B1ADDR[3:0], 2'b0};\r
-               end\r
-               else if (CFG_DBITS == 5) begin: blk\r
-                       assign ADDRA = {A1ADDR[11:3], 1'b0, A1ADDR[2:0], 3'b0};\r
-                       assign ADDRB = {B1ADDR[11:3], 1'b0, B1ADDR[2:0], 3'b0};\r
-               end\r
-               else if (CFG_DBITS == 10) begin: blk\r
-                       assign ADDRA = {A1ADDR[10:2], 1'b0, A1ADDR[1:0], 4'b0};\r
-                       assign ADDRB = {B1ADDR[10:2], 1'b0, B1ADDR[1:0], 4'b0};\r
-               end\r
-               else if (CFG_DBITS == 20) begin: blk\r
-                       assign ADDRA = {A1ADDR[9:1], 1'b0, A1ADDR[0], 5'b0};\r
-                       assign ADDRB = {B1ADDR[9:1], 1'b0, B1ADDR[0], 5'b0};\r
-               end\r
-\r
+module $__CC_BRAM_TDP_(...);\r
+\r
+parameter INIT = 0;\r
+parameter OPTION_MODE = "20K";\r
+\r
+parameter PORT_A_CLK_POL = 1;\r
+parameter PORT_A_RD_WIDTH = 1;\r
+parameter PORT_A_WR_WIDTH = 1;\r
+parameter PORT_A_WR_BE_WIDTH = 1;\r
+parameter PORT_A_OPTION_WR_MODE = "NO_CHANGE";\r
+\r
+parameter PORT_B_CLK_POL = 1;\r
+parameter PORT_B_RD_WIDTH = 1;\r
+parameter PORT_B_WR_WIDTH = 1;\r
+parameter PORT_B_WR_BE_WIDTH = 1;\r
+parameter PORT_B_OPTION_WR_MODE = "NO_CHANGE";\r
+\r
+input PORT_A_CLK;\r
+input PORT_A_CLK_EN;\r
+input PORT_A_WR_EN;\r
+input [15:0] PORT_A_ADDR;\r
+input [PORT_A_WR_BE_WIDTH-1:0] PORT_A_WR_BE;\r
+input [PORT_A_WR_WIDTH-1:0] PORT_A_WR_DATA;\r
+output [PORT_A_RD_WIDTH-1:0] PORT_A_RD_DATA;\r
+\r
+input PORT_B_CLK;\r
+input PORT_B_CLK_EN;\r
+input PORT_B_WR_EN;\r
+input [15:0] PORT_B_ADDR;\r
+input [PORT_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE;\r
+input [PORT_B_WR_WIDTH-1:0] PORT_B_WR_DATA;\r
+output [PORT_B_RD_WIDTH-1:0] PORT_B_RD_DATA;\r
+\r
+generate\r
+       if (OPTION_MODE == "20K") begin\r
                CC_BRAM_20K #(\r
-                       `include "brams_init_20.vh"\r
-                       .LOC("UNPLACED"),\r
-                       .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-                       .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
+                       .INIT_00(INIT['h00*320+:320]),\r
+                       .INIT_01(INIT['h01*320+:320]),\r
+                       .INIT_02(INIT['h02*320+:320]),\r
+                       .INIT_03(INIT['h03*320+:320]),\r
+                       .INIT_04(INIT['h04*320+:320]),\r
+                       .INIT_05(INIT['h05*320+:320]),\r
+                       .INIT_06(INIT['h06*320+:320]),\r
+                       .INIT_07(INIT['h07*320+:320]),\r
+                       .INIT_08(INIT['h08*320+:320]),\r
+                       .INIT_09(INIT['h09*320+:320]),\r
+                       .INIT_0A(INIT['h0a*320+:320]),\r
+                       .INIT_0B(INIT['h0b*320+:320]),\r
+                       .INIT_0C(INIT['h0c*320+:320]),\r
+                       .INIT_0D(INIT['h0d*320+:320]),\r
+                       .INIT_0E(INIT['h0e*320+:320]),\r
+                       .INIT_0F(INIT['h0f*320+:320]),\r
+                       .INIT_10(INIT['h10*320+:320]),\r
+                       .INIT_11(INIT['h11*320+:320]),\r
+                       .INIT_12(INIT['h12*320+:320]),\r
+                       .INIT_13(INIT['h13*320+:320]),\r
+                       .INIT_14(INIT['h14*320+:320]),\r
+                       .INIT_15(INIT['h15*320+:320]),\r
+                       .INIT_16(INIT['h16*320+:320]),\r
+                       .INIT_17(INIT['h17*320+:320]),\r
+                       .INIT_18(INIT['h18*320+:320]),\r
+                       .INIT_19(INIT['h19*320+:320]),\r
+                       .INIT_1A(INIT['h1a*320+:320]),\r
+                       .INIT_1B(INIT['h1b*320+:320]),\r
+                       .INIT_1C(INIT['h1c*320+:320]),\r
+                       .INIT_1D(INIT['h1d*320+:320]),\r
+                       .INIT_1E(INIT['h1e*320+:320]),\r
+                       .INIT_1F(INIT['h1f*320+:320]),\r
+                       .INIT_20(INIT['h20*320+:320]),\r
+                       .INIT_21(INIT['h21*320+:320]),\r
+                       .INIT_22(INIT['h22*320+:320]),\r
+                       .INIT_23(INIT['h23*320+:320]),\r
+                       .INIT_24(INIT['h24*320+:320]),\r
+                       .INIT_25(INIT['h25*320+:320]),\r
+                       .INIT_26(INIT['h26*320+:320]),\r
+                       .INIT_27(INIT['h27*320+:320]),\r
+                       .INIT_28(INIT['h28*320+:320]),\r
+                       .INIT_29(INIT['h29*320+:320]),\r
+                       .INIT_2A(INIT['h2a*320+:320]),\r
+                       .INIT_2B(INIT['h2b*320+:320]),\r
+                       .INIT_2C(INIT['h2c*320+:320]),\r
+                       .INIT_2D(INIT['h2d*320+:320]),\r
+                       .INIT_2E(INIT['h2e*320+:320]),\r
+                       .INIT_2F(INIT['h2f*320+:320]),\r
+                       .INIT_30(INIT['h30*320+:320]),\r
+                       .INIT_31(INIT['h31*320+:320]),\r
+                       .INIT_32(INIT['h32*320+:320]),\r
+                       .INIT_33(INIT['h33*320+:320]),\r
+                       .INIT_34(INIT['h34*320+:320]),\r
+                       .INIT_35(INIT['h35*320+:320]),\r
+                       .INIT_36(INIT['h36*320+:320]),\r
+                       .INIT_37(INIT['h37*320+:320]),\r
+                       .INIT_38(INIT['h38*320+:320]),\r
+                       .INIT_39(INIT['h39*320+:320]),\r
+                       .INIT_3A(INIT['h3a*320+:320]),\r
+                       .INIT_3B(INIT['h3b*320+:320]),\r
+                       .INIT_3C(INIT['h3c*320+:320]),\r
+                       .INIT_3D(INIT['h3d*320+:320]),\r
+                       .INIT_3E(INIT['h3e*320+:320]),\r
+                       .INIT_3F(INIT['h3f*320+:320]),\r
+                       .A_RD_WIDTH(PORT_A_RD_WIDTH),\r
+                       .A_WR_WIDTH(PORT_A_WR_WIDTH),\r
+                       .B_RD_WIDTH(PORT_B_RD_WIDTH),\r
+                       .B_WR_WIDTH(PORT_B_WR_WIDTH),\r
                        .RAM_MODE("TDP"),\r
-                       .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-                       .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-                       .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-                       .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-                       .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-                       .ECC_EN(1'b0)\r
+                       .A_WR_MODE(PORT_A_OPTION_WR_MODE),\r
+                       .B_WR_MODE(PORT_B_OPTION_WR_MODE),\r
+                       .A_CLK_INV(!PORT_A_CLK_POL),\r
+                       .B_CLK_INV(!PORT_B_CLK_POL),\r
                ) _TECHMAP_REPLACE_ (\r
-                       .A_DO(A_DO),\r
-                       .B_DO(B1DATA),\r
-                       .ECC_1B_ERR(ECC_1B_ERR),\r
-                       .ECC_2B_ERR(ECC_2B_ERR),\r
-                       .A_CLK(CLK2),\r
-                       .B_CLK(CLK3),\r
-                       .A_EN(1'b1),\r
-                       .B_EN(B1EN),\r
-                       .A_WE(|A1EN),\r
-                       .B_WE(1'b0),\r
-                       .A_ADDR(ADDRA),\r
-                       .B_ADDR(ADDRB),\r
-                       .A_DI(A1DATA),\r
-                       .B_DI(20'b0),\r
-                       .A_BM(A1EN),\r
-                       .B_BM(20'b0)\r
+                       .A_CLK(PORT_A_CLK),\r
+                       .A_EN(PORT_A_CLK_EN),\r
+                       .A_WE(PORT_A_WR_EN),\r
+                       .A_BM(PORT_A_WR_BE),\r
+                       .A_DI(PORT_A_WR_DATA),\r
+                       .A_ADDR({PORT_A_ADDR[13:5], 1'b0, PORT_A_ADDR[4:0], 1'b0}),\r
+                       .A_DO(PORT_A_RD_DATA),\r
+                       .B_CLK(PORT_B_CLK),\r
+                       .B_EN(PORT_B_CLK_EN),\r
+                       .B_WE(PORT_B_WR_EN),\r
+                       .B_BM(PORT_B_WR_BE),\r
+                       .B_DI(PORT_A_WR_DATA),\r
+                       .B_ADDR({PORT_B_ADDR[13:5], 1'b0, PORT_B_ADDR[4:0], 1'b0}),\r
+                       .B_DO(PORT_B_RD_DATA),\r
                );\r
-       endgenerate\r
-\r
-endmodule\r
-\r
-\r
-module \$__CC_BRAM_40K_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);\r
-\r
-       parameter CFG_ABITS = 15;\r
-       parameter CFG_DBITS = 40;\r
-       parameter CFG_ENABLE_A = 1;\r
-       parameter CFG_ENABLE_B = 1;\r
-\r
-       parameter CLKPOL2 = 1;\r
-       parameter CLKPOL3 = 1;\r
-\r
-       // 512 x 80 bit\r
-       parameter [40959:0] INIT = 40960'b0;\r
-\r
-       input CLK2;\r
-       input CLK3;\r
-\r
-       // write side of the memory\r
-       input [15:0] A1ADDR;\r
-       input [39:0] A1DATA;\r
-       input [39:0] A1EN;\r
-\r
-       // read side of the memory\r
-       input [15:0] B1ADDR;\r
-       output [39:0] B1DATA;\r
-       input [0:0] B1EN;\r
-\r
-       // unconnected signals\r
-       wire [39:0] A_DO;\r
-       wire A_ECC_1B_ERR, B_ECC_1B_ERR, A_ECC_2B_ERR, B_ECC_2B_ERR;\r
-\r
-       localparam INIT_CHUNK_SIZE = (CFG_DBITS <= 2) ? 256 : 320;\r
-\r
-       function [319:0] permute_init;\r
-               input [INIT_CHUNK_SIZE-1:0] chunk;\r
-               integer i;\r
-               begin\r
-                       if (CFG_DBITS <= 2) begin\r
-                               for (i = 0; i < 64; i = i + 1) begin\r
-                                       permute_init[i * 5 +: 5] = {1'b0, chunk[i * 4 +: 4]};\r
-                               end\r
-                       end else begin\r
-                               permute_init = chunk;\r
-                       end\r
-               end\r
-       endfunction\r
-\r
-       generate\r
-               wire [15:0] ADDRA;\r
-               wire [15:0] ADDRB;\r
-\r
-               if (CFG_DBITS == 1) begin\r
-                       assign ADDRA = {A1ADDR, 1'b0};\r
-                       assign ADDRB = {B1ADDR, 1'b0};\r
-               end\r
-               else if (CFG_DBITS == 2) begin\r
-                       assign ADDRA = {A1ADDR, 2'b0};\r
-                       assign ADDRB = {B1ADDR, 2'b0};\r
-               end\r
-               else if (CFG_DBITS == 5) begin\r
-                       assign ADDRA = {A1ADDR, 3'b0};\r
-                       assign ADDRB = {B1ADDR, 3'b0};\r
-               end\r
-               else if (CFG_DBITS == 10) begin\r
-                       assign ADDRA = {A1ADDR, 4'b0};\r
-                       assign ADDRB = {B1ADDR, 4'b0};\r
-               end\r
-               else if (CFG_DBITS == 20) begin\r
-                       assign ADDRA = {A1ADDR, 5'b0};\r
-                       assign ADDRB = {B1ADDR, 5'b0};\r
-               end\r
-               else if (CFG_DBITS == 40) begin\r
-                       assign ADDRA = {A1ADDR, 6'b0};\r
-                       assign ADDRB = {B1ADDR, 6'b0};\r
-               end\r
-\r
+       end else if (OPTION_MODE == "40K") begin\r
                CC_BRAM_40K #(\r
-                       `define INIT_LOWER\r
-                       `include "brams_init_40.vh"\r
-                       `undef INIT_LOWER\r
-                       .LOC("UNPLACED"),\r
-                       .CAS("NONE"),\r
-                       .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-                       .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
+                       .INIT_00(INIT['h00*320+:320]),\r
+                       .INIT_01(INIT['h01*320+:320]),\r
+                       .INIT_02(INIT['h02*320+:320]),\r
+                       .INIT_03(INIT['h03*320+:320]),\r
+                       .INIT_04(INIT['h04*320+:320]),\r
+                       .INIT_05(INIT['h05*320+:320]),\r
+                       .INIT_06(INIT['h06*320+:320]),\r
+                       .INIT_07(INIT['h07*320+:320]),\r
+                       .INIT_08(INIT['h08*320+:320]),\r
+                       .INIT_09(INIT['h09*320+:320]),\r
+                       .INIT_0A(INIT['h0a*320+:320]),\r
+                       .INIT_0B(INIT['h0b*320+:320]),\r
+                       .INIT_0C(INIT['h0c*320+:320]),\r
+                       .INIT_0D(INIT['h0d*320+:320]),\r
+                       .INIT_0E(INIT['h0e*320+:320]),\r
+                       .INIT_0F(INIT['h0f*320+:320]),\r
+                       .INIT_10(INIT['h10*320+:320]),\r
+                       .INIT_11(INIT['h11*320+:320]),\r
+                       .INIT_12(INIT['h12*320+:320]),\r
+                       .INIT_13(INIT['h13*320+:320]),\r
+                       .INIT_14(INIT['h14*320+:320]),\r
+                       .INIT_15(INIT['h15*320+:320]),\r
+                       .INIT_16(INIT['h16*320+:320]),\r
+                       .INIT_17(INIT['h17*320+:320]),\r
+                       .INIT_18(INIT['h18*320+:320]),\r
+                       .INIT_19(INIT['h19*320+:320]),\r
+                       .INIT_1A(INIT['h1a*320+:320]),\r
+                       .INIT_1B(INIT['h1b*320+:320]),\r
+                       .INIT_1C(INIT['h1c*320+:320]),\r
+                       .INIT_1D(INIT['h1d*320+:320]),\r
+                       .INIT_1E(INIT['h1e*320+:320]),\r
+                       .INIT_1F(INIT['h1f*320+:320]),\r
+                       .INIT_20(INIT['h20*320+:320]),\r
+                       .INIT_21(INIT['h21*320+:320]),\r
+                       .INIT_22(INIT['h22*320+:320]),\r
+                       .INIT_23(INIT['h23*320+:320]),\r
+                       .INIT_24(INIT['h24*320+:320]),\r
+                       .INIT_25(INIT['h25*320+:320]),\r
+                       .INIT_26(INIT['h26*320+:320]),\r
+                       .INIT_27(INIT['h27*320+:320]),\r
+                       .INIT_28(INIT['h28*320+:320]),\r
+                       .INIT_29(INIT['h29*320+:320]),\r
+                       .INIT_2A(INIT['h2a*320+:320]),\r
+                       .INIT_2B(INIT['h2b*320+:320]),\r
+                       .INIT_2C(INIT['h2c*320+:320]),\r
+                       .INIT_2D(INIT['h2d*320+:320]),\r
+                       .INIT_2E(INIT['h2e*320+:320]),\r
+                       .INIT_2F(INIT['h2f*320+:320]),\r
+                       .INIT_30(INIT['h30*320+:320]),\r
+                       .INIT_31(INIT['h31*320+:320]),\r
+                       .INIT_32(INIT['h32*320+:320]),\r
+                       .INIT_33(INIT['h33*320+:320]),\r
+                       .INIT_34(INIT['h34*320+:320]),\r
+                       .INIT_35(INIT['h35*320+:320]),\r
+                       .INIT_36(INIT['h36*320+:320]),\r
+                       .INIT_37(INIT['h37*320+:320]),\r
+                       .INIT_38(INIT['h38*320+:320]),\r
+                       .INIT_39(INIT['h39*320+:320]),\r
+                       .INIT_3A(INIT['h3a*320+:320]),\r
+                       .INIT_3B(INIT['h3b*320+:320]),\r
+                       .INIT_3C(INIT['h3c*320+:320]),\r
+                       .INIT_3D(INIT['h3d*320+:320]),\r
+                       .INIT_3E(INIT['h3e*320+:320]),\r
+                       .INIT_3F(INIT['h3f*320+:320]),\r
+                       .INIT_40(INIT['h40*320+:320]),\r
+                       .INIT_41(INIT['h41*320+:320]),\r
+                       .INIT_42(INIT['h42*320+:320]),\r
+                       .INIT_43(INIT['h43*320+:320]),\r
+                       .INIT_44(INIT['h44*320+:320]),\r
+                       .INIT_45(INIT['h45*320+:320]),\r
+                       .INIT_46(INIT['h46*320+:320]),\r
+                       .INIT_47(INIT['h47*320+:320]),\r
+                       .INIT_48(INIT['h48*320+:320]),\r
+                       .INIT_49(INIT['h49*320+:320]),\r
+                       .INIT_4A(INIT['h4a*320+:320]),\r
+                       .INIT_4B(INIT['h4b*320+:320]),\r
+                       .INIT_4C(INIT['h4c*320+:320]),\r
+                       .INIT_4D(INIT['h4d*320+:320]),\r
+                       .INIT_4E(INIT['h4e*320+:320]),\r
+                       .INIT_4F(INIT['h4f*320+:320]),\r
+                       .INIT_50(INIT['h50*320+:320]),\r
+                       .INIT_51(INIT['h51*320+:320]),\r
+                       .INIT_52(INIT['h52*320+:320]),\r
+                       .INIT_53(INIT['h53*320+:320]),\r
+                       .INIT_54(INIT['h54*320+:320]),\r
+                       .INIT_55(INIT['h55*320+:320]),\r
+                       .INIT_56(INIT['h56*320+:320]),\r
+                       .INIT_57(INIT['h57*320+:320]),\r
+                       .INIT_58(INIT['h58*320+:320]),\r
+                       .INIT_59(INIT['h59*320+:320]),\r
+                       .INIT_5A(INIT['h5a*320+:320]),\r
+                       .INIT_5B(INIT['h5b*320+:320]),\r
+                       .INIT_5C(INIT['h5c*320+:320]),\r
+                       .INIT_5D(INIT['h5d*320+:320]),\r
+                       .INIT_5E(INIT['h5e*320+:320]),\r
+                       .INIT_5F(INIT['h5f*320+:320]),\r
+                       .INIT_60(INIT['h60*320+:320]),\r
+                       .INIT_61(INIT['h61*320+:320]),\r
+                       .INIT_62(INIT['h62*320+:320]),\r
+                       .INIT_63(INIT['h63*320+:320]),\r
+                       .INIT_64(INIT['h64*320+:320]),\r
+                       .INIT_65(INIT['h65*320+:320]),\r
+                       .INIT_66(INIT['h66*320+:320]),\r
+                       .INIT_67(INIT['h67*320+:320]),\r
+                       .INIT_68(INIT['h68*320+:320]),\r
+                       .INIT_69(INIT['h69*320+:320]),\r
+                       .INIT_6A(INIT['h6a*320+:320]),\r
+                       .INIT_6B(INIT['h6b*320+:320]),\r
+                       .INIT_6C(INIT['h6c*320+:320]),\r
+                       .INIT_6D(INIT['h6d*320+:320]),\r
+                       .INIT_6E(INIT['h6e*320+:320]),\r
+                       .INIT_6F(INIT['h6f*320+:320]),\r
+                       .INIT_70(INIT['h70*320+:320]),\r
+                       .INIT_71(INIT['h71*320+:320]),\r
+                       .INIT_72(INIT['h72*320+:320]),\r
+                       .INIT_73(INIT['h73*320+:320]),\r
+                       .INIT_74(INIT['h74*320+:320]),\r
+                       .INIT_75(INIT['h75*320+:320]),\r
+                       .INIT_76(INIT['h76*320+:320]),\r
+                       .INIT_77(INIT['h77*320+:320]),\r
+                       .INIT_78(INIT['h78*320+:320]),\r
+                       .INIT_79(INIT['h79*320+:320]),\r
+                       .INIT_7A(INIT['h7a*320+:320]),\r
+                       .INIT_7B(INIT['h7b*320+:320]),\r
+                       .INIT_7C(INIT['h7c*320+:320]),\r
+                       .INIT_7D(INIT['h7d*320+:320]),\r
+                       .INIT_7E(INIT['h7e*320+:320]),\r
+                       .INIT_7F(INIT['h7f*320+:320]),\r
+                       .A_RD_WIDTH(PORT_A_RD_WIDTH),\r
+                       .A_WR_WIDTH(PORT_A_WR_WIDTH),\r
+                       .B_RD_WIDTH(PORT_B_RD_WIDTH),\r
+                       .B_WR_WIDTH(PORT_B_WR_WIDTH),\r
                        .RAM_MODE("TDP"),\r
-                       .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-                       .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-                       .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-                       .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-                       .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-                       .A_ECC_EN(1'b0), .B_ECC_EN(1'b0)\r
+                       .A_WR_MODE(PORT_A_OPTION_WR_MODE),\r
+                       .B_WR_MODE(PORT_B_OPTION_WR_MODE),\r
+                       .A_CLK_INV(!PORT_A_CLK_POL),\r
+                       .B_CLK_INV(!PORT_B_CLK_POL),\r
                ) _TECHMAP_REPLACE_ (\r
-                       .A_DO(A_DO),\r
-                       .B_DO(B1DATA),\r
-                       .A_ECC_1B_ERR(A_ECC_1B_ERR),\r
-                       .B_ECC_1B_ERR(B_ECC_1B_ERR),\r
-                       .A_ECC_2B_ERR(A_ECC_2B_ERR),\r
-                       .B_ECC_2B_ERR(B_ECC_2B_ERR),\r
-                       .A_CLK(CLK2),\r
-                       .B_CLK(CLK3),\r
-                       .A_EN(1'b1),\r
-                       .B_EN(B1EN),\r
-                       .A_WE(|A1EN),\r
-                       .B_WE(1'b0),\r
-                       .A_ADDR(ADDRA),\r
-                       .B_ADDR(ADDRB),\r
-                       .A_DI(A1DATA),\r
-                       .B_DI(40'b0),\r
-                       .A_BM(A1EN),\r
-                       .B_BM(40'b0)\r
+                       .A_CLK(PORT_A_CLK),\r
+                       .A_EN(PORT_A_CLK_EN),\r
+                       .A_WE(PORT_A_WR_EN),\r
+                       .A_BM(PORT_A_WR_BE),\r
+                       .A_DI(PORT_A_WR_DATA),\r
+                       .A_ADDR({PORT_A_ADDR[14:0], 1'b0}),\r
+                       .A_DO(PORT_A_RD_DATA),\r
+                       .B_CLK(PORT_B_CLK),\r
+                       .B_EN(PORT_B_CLK_EN),\r
+                       .B_WE(PORT_B_WR_EN),\r
+                       .B_BM(PORT_B_WR_BE),\r
+                       .B_DI(PORT_A_WR_DATA),\r
+                       .B_ADDR({PORT_B_ADDR[14:0], 1'b0}),\r
+                       .B_DO(PORT_B_RD_DATA),\r
                );\r
-       endgenerate\r
+       end else begin\r
+               wire CAS_A, CAS_B;\r
+               CC_BRAM_40K #(\r
+                       .INIT_00(INIT['h00*320+:320]),\r
+                       .INIT_01(INIT['h01*320+:320]),\r
+                       .INIT_02(INIT['h02*320+:320]),\r
+                       .INIT_03(INIT['h03*320+:320]),\r
+                       .INIT_04(INIT['h04*320+:320]),\r
+                       .INIT_05(INIT['h05*320+:320]),\r
+                       .INIT_06(INIT['h06*320+:320]),\r
+                       .INIT_07(INIT['h07*320+:320]),\r
+                       .INIT_08(INIT['h08*320+:320]),\r
+                       .INIT_09(INIT['h09*320+:320]),\r
+                       .INIT_0A(INIT['h0a*320+:320]),\r
+                       .INIT_0B(INIT['h0b*320+:320]),\r
+                       .INIT_0C(INIT['h0c*320+:320]),\r
+                       .INIT_0D(INIT['h0d*320+:320]),\r
+                       .INIT_0E(INIT['h0e*320+:320]),\r
+                       .INIT_0F(INIT['h0f*320+:320]),\r
+                       .INIT_10(INIT['h10*320+:320]),\r
+                       .INIT_11(INIT['h11*320+:320]),\r
+                       .INIT_12(INIT['h12*320+:320]),\r
+                       .INIT_13(INIT['h13*320+:320]),\r
+                       .INIT_14(INIT['h14*320+:320]),\r
+                       .INIT_15(INIT['h15*320+:320]),\r
+                       .INIT_16(INIT['h16*320+:320]),\r
+                       .INIT_17(INIT['h17*320+:320]),\r
+                       .INIT_18(INIT['h18*320+:320]),\r
+                       .INIT_19(INIT['h19*320+:320]),\r
+                       .INIT_1A(INIT['h1a*320+:320]),\r
+                       .INIT_1B(INIT['h1b*320+:320]),\r
+                       .INIT_1C(INIT['h1c*320+:320]),\r
+                       .INIT_1D(INIT['h1d*320+:320]),\r
+                       .INIT_1E(INIT['h1e*320+:320]),\r
+                       .INIT_1F(INIT['h1f*320+:320]),\r
+                       .INIT_20(INIT['h20*320+:320]),\r
+                       .INIT_21(INIT['h21*320+:320]),\r
+                       .INIT_22(INIT['h22*320+:320]),\r
+                       .INIT_23(INIT['h23*320+:320]),\r
+                       .INIT_24(INIT['h24*320+:320]),\r
+                       .INIT_25(INIT['h25*320+:320]),\r
+                       .INIT_26(INIT['h26*320+:320]),\r
+                       .INIT_27(INIT['h27*320+:320]),\r
+                       .INIT_28(INIT['h28*320+:320]),\r
+                       .INIT_29(INIT['h29*320+:320]),\r
+                       .INIT_2A(INIT['h2a*320+:320]),\r
+                       .INIT_2B(INIT['h2b*320+:320]),\r
+                       .INIT_2C(INIT['h2c*320+:320]),\r
+                       .INIT_2D(INIT['h2d*320+:320]),\r
+                       .INIT_2E(INIT['h2e*320+:320]),\r
+                       .INIT_2F(INIT['h2f*320+:320]),\r
+                       .INIT_30(INIT['h30*320+:320]),\r
+                       .INIT_31(INIT['h31*320+:320]),\r
+                       .INIT_32(INIT['h32*320+:320]),\r
+                       .INIT_33(INIT['h33*320+:320]),\r
+                       .INIT_34(INIT['h34*320+:320]),\r
+                       .INIT_35(INIT['h35*320+:320]),\r
+                       .INIT_36(INIT['h36*320+:320]),\r
+                       .INIT_37(INIT['h37*320+:320]),\r
+                       .INIT_38(INIT['h38*320+:320]),\r
+                       .INIT_39(INIT['h39*320+:320]),\r
+                       .INIT_3A(INIT['h3a*320+:320]),\r
+                       .INIT_3B(INIT['h3b*320+:320]),\r
+                       .INIT_3C(INIT['h3c*320+:320]),\r
+                       .INIT_3D(INIT['h3d*320+:320]),\r
+                       .INIT_3E(INIT['h3e*320+:320]),\r
+                       .INIT_3F(INIT['h3f*320+:320]),\r
+                       .INIT_40(INIT['h40*320+:320]),\r
+                       .INIT_41(INIT['h41*320+:320]),\r
+                       .INIT_42(INIT['h42*320+:320]),\r
+                       .INIT_43(INIT['h43*320+:320]),\r
+                       .INIT_44(INIT['h44*320+:320]),\r
+                       .INIT_45(INIT['h45*320+:320]),\r
+                       .INIT_46(INIT['h46*320+:320]),\r
+                       .INIT_47(INIT['h47*320+:320]),\r
+                       .INIT_48(INIT['h48*320+:320]),\r
+                       .INIT_49(INIT['h49*320+:320]),\r
+                       .INIT_4A(INIT['h4a*320+:320]),\r
+                       .INIT_4B(INIT['h4b*320+:320]),\r
+                       .INIT_4C(INIT['h4c*320+:320]),\r
+                       .INIT_4D(INIT['h4d*320+:320]),\r
+                       .INIT_4E(INIT['h4e*320+:320]),\r
+                       .INIT_4F(INIT['h4f*320+:320]),\r
+                       .INIT_50(INIT['h50*320+:320]),\r
+                       .INIT_51(INIT['h51*320+:320]),\r
+                       .INIT_52(INIT['h52*320+:320]),\r
+                       .INIT_53(INIT['h53*320+:320]),\r
+                       .INIT_54(INIT['h54*320+:320]),\r
+                       .INIT_55(INIT['h55*320+:320]),\r
+                       .INIT_56(INIT['h56*320+:320]),\r
+                       .INIT_57(INIT['h57*320+:320]),\r
+                       .INIT_58(INIT['h58*320+:320]),\r
+                       .INIT_59(INIT['h59*320+:320]),\r
+                       .INIT_5A(INIT['h5a*320+:320]),\r
+                       .INIT_5B(INIT['h5b*320+:320]),\r
+                       .INIT_5C(INIT['h5c*320+:320]),\r
+                       .INIT_5D(INIT['h5d*320+:320]),\r
+                       .INIT_5E(INIT['h5e*320+:320]),\r
+                       .INIT_5F(INIT['h5f*320+:320]),\r
+                       .INIT_60(INIT['h60*320+:320]),\r
+                       .INIT_61(INIT['h61*320+:320]),\r
+                       .INIT_62(INIT['h62*320+:320]),\r
+                       .INIT_63(INIT['h63*320+:320]),\r
+                       .INIT_64(INIT['h64*320+:320]),\r
+                       .INIT_65(INIT['h65*320+:320]),\r
+                       .INIT_66(INIT['h66*320+:320]),\r
+                       .INIT_67(INIT['h67*320+:320]),\r
+                       .INIT_68(INIT['h68*320+:320]),\r
+                       .INIT_69(INIT['h69*320+:320]),\r
+                       .INIT_6A(INIT['h6a*320+:320]),\r
+                       .INIT_6B(INIT['h6b*320+:320]),\r
+                       .INIT_6C(INIT['h6c*320+:320]),\r
+                       .INIT_6D(INIT['h6d*320+:320]),\r
+                       .INIT_6E(INIT['h6e*320+:320]),\r
+                       .INIT_6F(INIT['h6f*320+:320]),\r
+                       .INIT_70(INIT['h70*320+:320]),\r
+                       .INIT_71(INIT['h71*320+:320]),\r
+                       .INIT_72(INIT['h72*320+:320]),\r
+                       .INIT_73(INIT['h73*320+:320]),\r
+                       .INIT_74(INIT['h74*320+:320]),\r
+                       .INIT_75(INIT['h75*320+:320]),\r
+                       .INIT_76(INIT['h76*320+:320]),\r
+                       .INIT_77(INIT['h77*320+:320]),\r
+                       .INIT_78(INIT['h78*320+:320]),\r
+                       .INIT_79(INIT['h79*320+:320]),\r
+                       .INIT_7A(INIT['h7a*320+:320]),\r
+                       .INIT_7B(INIT['h7b*320+:320]),\r
+                       .INIT_7C(INIT['h7c*320+:320]),\r
+                       .INIT_7D(INIT['h7d*320+:320]),\r
+                       .INIT_7E(INIT['h7e*320+:320]),\r
+                       .INIT_7F(INIT['h7f*320+:320]),\r
+                       .A_RD_WIDTH(PORT_A_RD_WIDTH),\r
+                       .A_WR_WIDTH(PORT_A_WR_WIDTH),\r
+                       .B_RD_WIDTH(PORT_B_RD_WIDTH),\r
+                       .B_WR_WIDTH(PORT_B_WR_WIDTH),\r
+                       .RAM_MODE("TDP"),\r
+                       .A_WR_MODE(PORT_A_OPTION_WR_MODE),\r
+                       .B_WR_MODE(PORT_B_OPTION_WR_MODE),\r
+                       .A_CLK_INV(!PORT_A_CLK_POL),\r
+                       .B_CLK_INV(!PORT_B_CLK_POL),\r
+                       .CAS("LOWER"),\r
+               ) lower (\r
+                       .A_CO(CAS_A),\r
+                       .B_CO(CAS_B),\r
+                       .A_CLK(PORT_A_CLK),\r
+                       .A_EN(PORT_A_CLK_EN),\r
+                       .A_WE(PORT_A_WR_EN),\r
+                       .A_BM(PORT_A_WR_BE),\r
+                       .A_DI(PORT_A_WR_DATA),\r
+                       .A_ADDR({PORT_A_ADDR[14:0], PORT_A_ADDR[15]}),\r
+                       .B_CLK(PORT_B_CLK),\r
+                       .B_EN(PORT_B_CLK_EN),\r
+                       .B_WE(PORT_B_WR_EN),\r
+                       .B_BM(PORT_B_WR_BE),\r
+                       .B_DI(PORT_A_WR_DATA),\r
+                       .B_ADDR({PORT_B_ADDR[14:0], PORT_B_ADDR[15]}),\r
+               );\r
+               CC_BRAM_40K #(\r
+                       .INIT_00(INIT['h80*320+:320]),\r
+                       .INIT_01(INIT['h81*320+:320]),\r
+                       .INIT_02(INIT['h82*320+:320]),\r
+                       .INIT_03(INIT['h83*320+:320]),\r
+                       .INIT_04(INIT['h84*320+:320]),\r
+                       .INIT_05(INIT['h85*320+:320]),\r
+                       .INIT_06(INIT['h86*320+:320]),\r
+                       .INIT_07(INIT['h87*320+:320]),\r
+                       .INIT_08(INIT['h88*320+:320]),\r
+                       .INIT_09(INIT['h89*320+:320]),\r
+                       .INIT_0A(INIT['h8a*320+:320]),\r
+                       .INIT_0B(INIT['h8b*320+:320]),\r
+                       .INIT_0C(INIT['h8c*320+:320]),\r
+                       .INIT_0D(INIT['h8d*320+:320]),\r
+                       .INIT_0E(INIT['h8e*320+:320]),\r
+                       .INIT_0F(INIT['h8f*320+:320]),\r
+                       .INIT_10(INIT['h90*320+:320]),\r
+                       .INIT_11(INIT['h91*320+:320]),\r
+                       .INIT_12(INIT['h92*320+:320]),\r
+                       .INIT_13(INIT['h93*320+:320]),\r
+                       .INIT_14(INIT['h94*320+:320]),\r
+                       .INIT_15(INIT['h95*320+:320]),\r
+                       .INIT_16(INIT['h96*320+:320]),\r
+                       .INIT_17(INIT['h97*320+:320]),\r
+                       .INIT_18(INIT['h98*320+:320]),\r
+                       .INIT_19(INIT['h99*320+:320]),\r
+                       .INIT_1A(INIT['h9a*320+:320]),\r
+                       .INIT_1B(INIT['h9b*320+:320]),\r
+                       .INIT_1C(INIT['h9c*320+:320]),\r
+                       .INIT_1D(INIT['h9d*320+:320]),\r
+                       .INIT_1E(INIT['h9e*320+:320]),\r
+                       .INIT_1F(INIT['h9f*320+:320]),\r
+                       .INIT_20(INIT['ha0*320+:320]),\r
+                       .INIT_21(INIT['ha1*320+:320]),\r
+                       .INIT_22(INIT['ha2*320+:320]),\r
+                       .INIT_23(INIT['ha3*320+:320]),\r
+                       .INIT_24(INIT['ha4*320+:320]),\r
+                       .INIT_25(INIT['ha5*320+:320]),\r
+                       .INIT_26(INIT['ha6*320+:320]),\r
+                       .INIT_27(INIT['ha7*320+:320]),\r
+                       .INIT_28(INIT['ha8*320+:320]),\r
+                       .INIT_29(INIT['ha9*320+:320]),\r
+                       .INIT_2A(INIT['haa*320+:320]),\r
+                       .INIT_2B(INIT['hab*320+:320]),\r
+                       .INIT_2C(INIT['hac*320+:320]),\r
+                       .INIT_2D(INIT['had*320+:320]),\r
+                       .INIT_2E(INIT['hae*320+:320]),\r
+                       .INIT_2F(INIT['haf*320+:320]),\r
+                       .INIT_30(INIT['hb0*320+:320]),\r
+                       .INIT_31(INIT['hb1*320+:320]),\r
+                       .INIT_32(INIT['hb2*320+:320]),\r
+                       .INIT_33(INIT['hb3*320+:320]),\r
+                       .INIT_34(INIT['hb4*320+:320]),\r
+                       .INIT_35(INIT['hb5*320+:320]),\r
+                       .INIT_36(INIT['hb6*320+:320]),\r
+                       .INIT_37(INIT['hb7*320+:320]),\r
+                       .INIT_38(INIT['hb8*320+:320]),\r
+                       .INIT_39(INIT['hb9*320+:320]),\r
+                       .INIT_3A(INIT['hba*320+:320]),\r
+                       .INIT_3B(INIT['hbb*320+:320]),\r
+                       .INIT_3C(INIT['hbc*320+:320]),\r
+                       .INIT_3D(INIT['hbd*320+:320]),\r
+                       .INIT_3E(INIT['hbe*320+:320]),\r
+                       .INIT_3F(INIT['hbf*320+:320]),\r
+                       .INIT_40(INIT['hc0*320+:320]),\r
+                       .INIT_41(INIT['hc1*320+:320]),\r
+                       .INIT_42(INIT['hc2*320+:320]),\r
+                       .INIT_43(INIT['hc3*320+:320]),\r
+                       .INIT_44(INIT['hc4*320+:320]),\r
+                       .INIT_45(INIT['hc5*320+:320]),\r
+                       .INIT_46(INIT['hc6*320+:320]),\r
+                       .INIT_47(INIT['hc7*320+:320]),\r
+                       .INIT_48(INIT['hc8*320+:320]),\r
+                       .INIT_49(INIT['hc9*320+:320]),\r
+                       .INIT_4A(INIT['hca*320+:320]),\r
+                       .INIT_4B(INIT['hcb*320+:320]),\r
+                       .INIT_4C(INIT['hcc*320+:320]),\r
+                       .INIT_4D(INIT['hcd*320+:320]),\r
+                       .INIT_4E(INIT['hce*320+:320]),\r
+                       .INIT_4F(INIT['hcf*320+:320]),\r
+                       .INIT_50(INIT['hd0*320+:320]),\r
+                       .INIT_51(INIT['hd1*320+:320]),\r
+                       .INIT_52(INIT['hd2*320+:320]),\r
+                       .INIT_53(INIT['hd3*320+:320]),\r
+                       .INIT_54(INIT['hd4*320+:320]),\r
+                       .INIT_55(INIT['hd5*320+:320]),\r
+                       .INIT_56(INIT['hd6*320+:320]),\r
+                       .INIT_57(INIT['hd7*320+:320]),\r
+                       .INIT_58(INIT['hd8*320+:320]),\r
+                       .INIT_59(INIT['hd9*320+:320]),\r
+                       .INIT_5A(INIT['hda*320+:320]),\r
+                       .INIT_5B(INIT['hdb*320+:320]),\r
+                       .INIT_5C(INIT['hdc*320+:320]),\r
+                       .INIT_5D(INIT['hdd*320+:320]),\r
+                       .INIT_5E(INIT['hde*320+:320]),\r
+                       .INIT_5F(INIT['hdf*320+:320]),\r
+                       .INIT_60(INIT['he0*320+:320]),\r
+                       .INIT_61(INIT['he1*320+:320]),\r
+                       .INIT_62(INIT['he2*320+:320]),\r
+                       .INIT_63(INIT['he3*320+:320]),\r
+                       .INIT_64(INIT['he4*320+:320]),\r
+                       .INIT_65(INIT['he5*320+:320]),\r
+                       .INIT_66(INIT['he6*320+:320]),\r
+                       .INIT_67(INIT['he7*320+:320]),\r
+                       .INIT_68(INIT['he8*320+:320]),\r
+                       .INIT_69(INIT['he9*320+:320]),\r
+                       .INIT_6A(INIT['hea*320+:320]),\r
+                       .INIT_6B(INIT['heb*320+:320]),\r
+                       .INIT_6C(INIT['hec*320+:320]),\r
+                       .INIT_6D(INIT['hed*320+:320]),\r
+                       .INIT_6E(INIT['hee*320+:320]),\r
+                       .INIT_6F(INIT['hef*320+:320]),\r
+                       .INIT_70(INIT['hf0*320+:320]),\r
+                       .INIT_71(INIT['hf1*320+:320]),\r
+                       .INIT_72(INIT['hf2*320+:320]),\r
+                       .INIT_73(INIT['hf3*320+:320]),\r
+                       .INIT_74(INIT['hf4*320+:320]),\r
+                       .INIT_75(INIT['hf5*320+:320]),\r
+                       .INIT_76(INIT['hf6*320+:320]),\r
+                       .INIT_77(INIT['hf7*320+:320]),\r
+                       .INIT_78(INIT['hf8*320+:320]),\r
+                       .INIT_79(INIT['hf9*320+:320]),\r
+                       .INIT_7A(INIT['hfa*320+:320]),\r
+                       .INIT_7B(INIT['hfb*320+:320]),\r
+                       .INIT_7C(INIT['hfc*320+:320]),\r
+                       .INIT_7D(INIT['hfd*320+:320]),\r
+                       .INIT_7E(INIT['hfe*320+:320]),\r
+                       .INIT_7F(INIT['hff*320+:320]),\r
+                       .A_RD_WIDTH(PORT_A_RD_WIDTH),\r
+                       .A_WR_WIDTH(PORT_A_WR_WIDTH),\r
+                       .B_RD_WIDTH(PORT_B_RD_WIDTH),\r
+                       .B_WR_WIDTH(PORT_B_WR_WIDTH),\r
+                       .RAM_MODE("TDP"),\r
+                       .A_WR_MODE(PORT_A_OPTION_WR_MODE),\r
+                       .B_WR_MODE(PORT_B_OPTION_WR_MODE),\r
+                       .A_CLK_INV(!PORT_A_CLK_POL),\r
+                       .B_CLK_INV(!PORT_B_CLK_POL),\r
+                       .CAS("UPPER"),\r
+               ) upper (\r
+                       .A_CI(CAS_A),\r
+                       .B_CI(CAS_B),\r
+                       .A_CLK(PORT_A_CLK),\r
+                       .A_EN(PORT_A_CLK_EN),\r
+                       .A_WE(PORT_A_WR_EN),\r
+                       .A_BM(PORT_A_WR_BE),\r
+                       .A_DI(PORT_A_WR_DATA),\r
+                       .A_DO(PORT_A_RD_DATA),\r
+                       .A_ADDR({PORT_A_ADDR[14:0], PORT_A_ADDR[15]}),\r
+                       .B_CLK(PORT_B_CLK),\r
+                       .B_EN(PORT_B_CLK_EN),\r
+                       .B_WE(PORT_B_WR_EN),\r
+                       .B_BM(PORT_B_WR_BE),\r
+                       .B_DI(PORT_A_WR_DATA),\r
+                       .B_DO(PORT_B_RD_DATA),\r
+                       .B_ADDR({PORT_B_ADDR[14:0], PORT_B_ADDR[15]}),\r
+               );\r
+       end\r
+endgenerate\r
 \r
 endmodule\r
 \r
 \r
-module \$__CC_BRAM_CASCADE (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);\r
-\r
-       parameter CFG_ABITS = 16;\r
-       parameter CFG_DBITS = 1;\r
-       parameter CFG_ENABLE_A = 1;\r
-       parameter CFG_ENABLE_B = 1;\r
-\r
-       parameter CLKPOL2 = 1;\r
-       parameter CLKPOL3 = 1;\r
-\r
-       // 64K x 1\r
-       parameter [65535:0] INIT = 65535'b0;\r
-\r
-       input CLK2;\r
-       input CLK3;\r
+module $__CC_BRAM_SDP_(...);\r
 \r
-       // write side of the memory\r
-       input [15:0] A1ADDR;\r
-       input [39:0] A1DATA;\r
-       input [39:0] A1EN;\r
+parameter INIT = 0;\r
+parameter OPTION_MODE = "20K";\r
 \r
-       // read side of the memory\r
-       input [15:0] B1ADDR;\r
-       output [39:0] B1DATA;\r
-       input [0:0] B1EN;\r
+parameter PORT_W_CLK_POL = 1;\r
+parameter PORT_W_WIDTH = 40;\r
+parameter PORT_W_WR_BE_WIDTH = 40;\r
 \r
-       // cascade signals\r
-       wire A_CAS, B_CAS;\r
+parameter PORT_R_CLK_POL = 1;\r
+parameter PORT_R_WIDTH = 40;\r
 \r
-       // unconnected signals\r
-       wire [39:0] A_UP_DO;\r
-       wire A_ECC_1B_ERR, B_ECC_1B_ERR, A_ECC_2B_ERR, B_ECC_2B_ERR;\r
+input PORT_W_CLK;\r
+input PORT_W_CLK_EN;\r
+input PORT_W_WR_EN;\r
+input [15:0] PORT_W_ADDR;\r
+input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE;\r
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;\r
 \r
-       localparam INIT_CHUNK_SIZE = 256;\r
+input PORT_R_CLK;\r
+input PORT_R_CLK_EN;\r
+input [15:0] PORT_R_ADDR;\r
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;\r
 \r
-       function [319:0] permute_init;\r
-               input [INIT_CHUNK_SIZE-1:0] chunk;\r
-               integer i;\r
-               begin\r
-                       for (i = 0; i < 64; i = i + 1) begin\r
-                               permute_init[i * 5 +: 5] = {1'b0, chunk[i * 4 +: 4]};\r
-                       end\r
-               end\r
-       endfunction\r
-\r
-       generate\r
-               CC_BRAM_40K #(\r
-                       `define INIT_UPPER\r
-                       `include "brams_init_40.vh" // INIT_80 .. INIT_FF\r
-                       `undef INIT_UPPER\r
-                       .LOC("UNPLACED"),\r
-                       .CAS("UPPER"),\r
-                       .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-                       .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
-                       .RAM_MODE("TDP"),\r
-                       .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-                       .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-                       .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-                       .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-                       .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-                       .A_ECC_EN(1'b0), .B_ECC_EN(1'b0)\r
-               ) upper_cell (\r
-                       .A_CI(A_CAS),\r
-                       .B_CI(B_CAS),\r
-                       .A_DO(A_UP_DO),\r
-                       .B_DO(B1DATA),\r
-                       .A_ECC_1B_ERR(A_ECC_1B_ERR),\r
-                       .B_ECC_1B_ERR(B_ECC_1B_ERR),\r
-                       .A_ECC_2B_ERR(A_ECC_2B_ERR),\r
-                       .B_ECC_2B_ERR(B_ECC_2B_ERR),\r
-                       .A_CLK(CLK2),\r
-                       .B_CLK(CLK3),\r
-                       .A_EN(1'b1),\r
-                       .B_EN(B1EN),\r
-                       .A_WE(|A1EN),\r
+generate\r
+       if (OPTION_MODE == "20K") begin\r
+               CC_BRAM_20K #(\r
+                       .INIT_00(INIT['h00*320+:320]),\r
+                       .INIT_01(INIT['h01*320+:320]),\r
+                       .INIT_02(INIT['h02*320+:320]),\r
+                       .INIT_03(INIT['h03*320+:320]),\r
+                       .INIT_04(INIT['h04*320+:320]),\r
+                       .INIT_05(INIT['h05*320+:320]),\r
+                       .INIT_06(INIT['h06*320+:320]),\r
+                       .INIT_07(INIT['h07*320+:320]),\r
+                       .INIT_08(INIT['h08*320+:320]),\r
+                       .INIT_09(INIT['h09*320+:320]),\r
+                       .INIT_0A(INIT['h0a*320+:320]),\r
+                       .INIT_0B(INIT['h0b*320+:320]),\r
+                       .INIT_0C(INIT['h0c*320+:320]),\r
+                       .INIT_0D(INIT['h0d*320+:320]),\r
+                       .INIT_0E(INIT['h0e*320+:320]),\r
+                       .INIT_0F(INIT['h0f*320+:320]),\r
+                       .INIT_10(INIT['h10*320+:320]),\r
+                       .INIT_11(INIT['h11*320+:320]),\r
+                       .INIT_12(INIT['h12*320+:320]),\r
+                       .INIT_13(INIT['h13*320+:320]),\r
+                       .INIT_14(INIT['h14*320+:320]),\r
+                       .INIT_15(INIT['h15*320+:320]),\r
+                       .INIT_16(INIT['h16*320+:320]),\r
+                       .INIT_17(INIT['h17*320+:320]),\r
+                       .INIT_18(INIT['h18*320+:320]),\r
+                       .INIT_19(INIT['h19*320+:320]),\r
+                       .INIT_1A(INIT['h1a*320+:320]),\r
+                       .INIT_1B(INIT['h1b*320+:320]),\r
+                       .INIT_1C(INIT['h1c*320+:320]),\r
+                       .INIT_1D(INIT['h1d*320+:320]),\r
+                       .INIT_1E(INIT['h1e*320+:320]),\r
+                       .INIT_1F(INIT['h1f*320+:320]),\r
+                       .INIT_20(INIT['h20*320+:320]),\r
+                       .INIT_21(INIT['h21*320+:320]),\r
+                       .INIT_22(INIT['h22*320+:320]),\r
+                       .INIT_23(INIT['h23*320+:320]),\r
+                       .INIT_24(INIT['h24*320+:320]),\r
+                       .INIT_25(INIT['h25*320+:320]),\r
+                       .INIT_26(INIT['h26*320+:320]),\r
+                       .INIT_27(INIT['h27*320+:320]),\r
+                       .INIT_28(INIT['h28*320+:320]),\r
+                       .INIT_29(INIT['h29*320+:320]),\r
+                       .INIT_2A(INIT['h2a*320+:320]),\r
+                       .INIT_2B(INIT['h2b*320+:320]),\r
+                       .INIT_2C(INIT['h2c*320+:320]),\r
+                       .INIT_2D(INIT['h2d*320+:320]),\r
+                       .INIT_2E(INIT['h2e*320+:320]),\r
+                       .INIT_2F(INIT['h2f*320+:320]),\r
+                       .INIT_30(INIT['h30*320+:320]),\r
+                       .INIT_31(INIT['h31*320+:320]),\r
+                       .INIT_32(INIT['h32*320+:320]),\r
+                       .INIT_33(INIT['h33*320+:320]),\r
+                       .INIT_34(INIT['h34*320+:320]),\r
+                       .INIT_35(INIT['h35*320+:320]),\r
+                       .INIT_36(INIT['h36*320+:320]),\r
+                       .INIT_37(INIT['h37*320+:320]),\r
+                       .INIT_38(INIT['h38*320+:320]),\r
+                       .INIT_39(INIT['h39*320+:320]),\r
+                       .INIT_3A(INIT['h3a*320+:320]),\r
+                       .INIT_3B(INIT['h3b*320+:320]),\r
+                       .INIT_3C(INIT['h3c*320+:320]),\r
+                       .INIT_3D(INIT['h3d*320+:320]),\r
+                       .INIT_3E(INIT['h3e*320+:320]),\r
+                       .INIT_3F(INIT['h3f*320+:320]),\r
+                       .A_RD_WIDTH(0),\r
+                       .A_WR_WIDTH(PORT_W_WIDTH),\r
+                       .B_RD_WIDTH(PORT_R_WIDTH),\r
+                       .B_WR_WIDTH(0),\r
+                       .RAM_MODE("SDP"),\r
+                       .A_WR_MODE("NO_CHANGE"),\r
+                       .B_WR_MODE("NO_CHANGE"),\r
+                       .A_CLK_INV(!PORT_W_CLK_POL),\r
+                       .B_CLK_INV(!PORT_R_CLK_POL),\r
+               ) _TECHMAP_REPLACE_ (\r
+                       .A_CLK(PORT_W_CLK),\r
+                       .A_EN(PORT_W_CLK_EN),\r
+                       .A_WE(PORT_W_WR_EN),\r
+                       .A_BM(PORT_W_WR_BE[19:0]),\r
+                       .B_BM(PORT_W_WR_BE[39:20]),\r
+                       .A_DI(PORT_W_WR_DATA[19:0]),\r
+                       .B_DI(PORT_W_WR_DATA[39:20]),\r
+                       .A_ADDR({PORT_W_ADDR[13:5], 1'b0, PORT_W_ADDR[4:0], 1'b0}),\r
+                       .B_CLK(PORT_R_CLK),\r
+                       .B_EN(PORT_R_CLK_EN),\r
                        .B_WE(1'b0),\r
-                       .A_ADDR(A1ADDR),\r
-                       .B_ADDR(B1ADDR),\r
-                       .A_DI(A1DATA),\r
-                       .B_DI(40'b0),\r
-                       .A_BM(A1EN),\r
-                       .B_BM(40'b0)\r
+                       .B_ADDR({PORT_R_ADDR[13:5], 1'b0, PORT_R_ADDR[4:0], 1'b0}),\r
+                       .A_DO(PORT_R_RD_DATA[19:0]),\r
+                       .B_DO(PORT_R_RD_DATA[39:20]),\r
                );\r
-\r
+       end else if (OPTION_MODE == "40K") begin\r
                CC_BRAM_40K #(\r
-                       `define INIT_LOWER\r
-                       `include "brams_init_40.vh" // INIT_00 .. INIT_7F\r
-                       `undef INIT_LOWER\r
-                       .LOC("UNPLACED"),\r
-                       .CAS("LOWER"),\r
-                       .A_RD_WIDTH(0), .B_RD_WIDTH(CFG_DBITS),\r
-                       .A_WR_WIDTH(CFG_DBITS), .B_WR_WIDTH(0),\r
-                       .RAM_MODE("TDP"),\r
-                       .A_WR_MODE("NO_CHANGE"), .B_WR_MODE("NO_CHANGE"),\r
-                       .A_CLK_INV(!CLKPOL2), .B_CLK_INV(!CLKPOL3),\r
-                       .A_EN_INV(1'b0), .B_EN_INV(1'b0),\r
-                       .A_WE_INV(1'b0), .B_WE_INV(1'b0),\r
-                       .A_DO_REG(1'b0), .B_DO_REG(1'b0),\r
-                       .A_ECC_EN(1'b0), .B_ECC_EN(1'b0)\r
-               ) lower_cell (\r
-                       .A_CI(),\r
-                       .B_CI(),\r
-                       .A_CO(A_CAS),\r
-                       .B_CO(B_CAS),\r
-                       .A_CLK(CLK2),\r
-                       .B_CLK(CLK3),\r
-                       .A_EN(1'b1),\r
-                       .B_EN(B1EN),\r
-                       .A_WE(|A1EN),\r
+                       .INIT_00(INIT['h00*320+:320]),\r
+                       .INIT_01(INIT['h01*320+:320]),\r
+                       .INIT_02(INIT['h02*320+:320]),\r
+                       .INIT_03(INIT['h03*320+:320]),\r
+                       .INIT_04(INIT['h04*320+:320]),\r
+                       .INIT_05(INIT['h05*320+:320]),\r
+                       .INIT_06(INIT['h06*320+:320]),\r
+                       .INIT_07(INIT['h07*320+:320]),\r
+                       .INIT_08(INIT['h08*320+:320]),\r
+                       .INIT_09(INIT['h09*320+:320]),\r
+                       .INIT_0A(INIT['h0a*320+:320]),\r
+                       .INIT_0B(INIT['h0b*320+:320]),\r
+                       .INIT_0C(INIT['h0c*320+:320]),\r
+                       .INIT_0D(INIT['h0d*320+:320]),\r
+                       .INIT_0E(INIT['h0e*320+:320]),\r
+                       .INIT_0F(INIT['h0f*320+:320]),\r
+                       .INIT_10(INIT['h10*320+:320]),\r
+                       .INIT_11(INIT['h11*320+:320]),\r
+                       .INIT_12(INIT['h12*320+:320]),\r
+                       .INIT_13(INIT['h13*320+:320]),\r
+                       .INIT_14(INIT['h14*320+:320]),\r
+                       .INIT_15(INIT['h15*320+:320]),\r
+                       .INIT_16(INIT['h16*320+:320]),\r
+                       .INIT_17(INIT['h17*320+:320]),\r
+                       .INIT_18(INIT['h18*320+:320]),\r
+                       .INIT_19(INIT['h19*320+:320]),\r
+                       .INIT_1A(INIT['h1a*320+:320]),\r
+                       .INIT_1B(INIT['h1b*320+:320]),\r
+                       .INIT_1C(INIT['h1c*320+:320]),\r
+                       .INIT_1D(INIT['h1d*320+:320]),\r
+                       .INIT_1E(INIT['h1e*320+:320]),\r
+                       .INIT_1F(INIT['h1f*320+:320]),\r
+                       .INIT_20(INIT['h20*320+:320]),\r
+                       .INIT_21(INIT['h21*320+:320]),\r
+                       .INIT_22(INIT['h22*320+:320]),\r
+                       .INIT_23(INIT['h23*320+:320]),\r
+                       .INIT_24(INIT['h24*320+:320]),\r
+                       .INIT_25(INIT['h25*320+:320]),\r
+                       .INIT_26(INIT['h26*320+:320]),\r
+                       .INIT_27(INIT['h27*320+:320]),\r
+                       .INIT_28(INIT['h28*320+:320]),\r
+                       .INIT_29(INIT['h29*320+:320]),\r
+                       .INIT_2A(INIT['h2a*320+:320]),\r
+                       .INIT_2B(INIT['h2b*320+:320]),\r
+                       .INIT_2C(INIT['h2c*320+:320]),\r
+                       .INIT_2D(INIT['h2d*320+:320]),\r
+                       .INIT_2E(INIT['h2e*320+:320]),\r
+                       .INIT_2F(INIT['h2f*320+:320]),\r
+                       .INIT_30(INIT['h30*320+:320]),\r
+                       .INIT_31(INIT['h31*320+:320]),\r
+                       .INIT_32(INIT['h32*320+:320]),\r
+                       .INIT_33(INIT['h33*320+:320]),\r
+                       .INIT_34(INIT['h34*320+:320]),\r
+                       .INIT_35(INIT['h35*320+:320]),\r
+                       .INIT_36(INIT['h36*320+:320]),\r
+                       .INIT_37(INIT['h37*320+:320]),\r
+                       .INIT_38(INIT['h38*320+:320]),\r
+                       .INIT_39(INIT['h39*320+:320]),\r
+                       .INIT_3A(INIT['h3a*320+:320]),\r
+                       .INIT_3B(INIT['h3b*320+:320]),\r
+                       .INIT_3C(INIT['h3c*320+:320]),\r
+                       .INIT_3D(INIT['h3d*320+:320]),\r
+                       .INIT_3E(INIT['h3e*320+:320]),\r
+                       .INIT_3F(INIT['h3f*320+:320]),\r
+                       .INIT_40(INIT['h40*320+:320]),\r
+                       .INIT_41(INIT['h41*320+:320]),\r
+                       .INIT_42(INIT['h42*320+:320]),\r
+                       .INIT_43(INIT['h43*320+:320]),\r
+                       .INIT_44(INIT['h44*320+:320]),\r
+                       .INIT_45(INIT['h45*320+:320]),\r
+                       .INIT_46(INIT['h46*320+:320]),\r
+                       .INIT_47(INIT['h47*320+:320]),\r
+                       .INIT_48(INIT['h48*320+:320]),\r
+                       .INIT_49(INIT['h49*320+:320]),\r
+                       .INIT_4A(INIT['h4a*320+:320]),\r
+                       .INIT_4B(INIT['h4b*320+:320]),\r
+                       .INIT_4C(INIT['h4c*320+:320]),\r
+                       .INIT_4D(INIT['h4d*320+:320]),\r
+                       .INIT_4E(INIT['h4e*320+:320]),\r
+                       .INIT_4F(INIT['h4f*320+:320]),\r
+                       .INIT_50(INIT['h50*320+:320]),\r
+                       .INIT_51(INIT['h51*320+:320]),\r
+                       .INIT_52(INIT['h52*320+:320]),\r
+                       .INIT_53(INIT['h53*320+:320]),\r
+                       .INIT_54(INIT['h54*320+:320]),\r
+                       .INIT_55(INIT['h55*320+:320]),\r
+                       .INIT_56(INIT['h56*320+:320]),\r
+                       .INIT_57(INIT['h57*320+:320]),\r
+                       .INIT_58(INIT['h58*320+:320]),\r
+                       .INIT_59(INIT['h59*320+:320]),\r
+                       .INIT_5A(INIT['h5a*320+:320]),\r
+                       .INIT_5B(INIT['h5b*320+:320]),\r
+                       .INIT_5C(INIT['h5c*320+:320]),\r
+                       .INIT_5D(INIT['h5d*320+:320]),\r
+                       .INIT_5E(INIT['h5e*320+:320]),\r
+                       .INIT_5F(INIT['h5f*320+:320]),\r
+                       .INIT_60(INIT['h60*320+:320]),\r
+                       .INIT_61(INIT['h61*320+:320]),\r
+                       .INIT_62(INIT['h62*320+:320]),\r
+                       .INIT_63(INIT['h63*320+:320]),\r
+                       .INIT_64(INIT['h64*320+:320]),\r
+                       .INIT_65(INIT['h65*320+:320]),\r
+                       .INIT_66(INIT['h66*320+:320]),\r
+                       .INIT_67(INIT['h67*320+:320]),\r
+                       .INIT_68(INIT['h68*320+:320]),\r
+                       .INIT_69(INIT['h69*320+:320]),\r
+                       .INIT_6A(INIT['h6a*320+:320]),\r
+                       .INIT_6B(INIT['h6b*320+:320]),\r
+                       .INIT_6C(INIT['h6c*320+:320]),\r
+                       .INIT_6D(INIT['h6d*320+:320]),\r
+                       .INIT_6E(INIT['h6e*320+:320]),\r
+                       .INIT_6F(INIT['h6f*320+:320]),\r
+                       .INIT_70(INIT['h70*320+:320]),\r
+                       .INIT_71(INIT['h71*320+:320]),\r
+                       .INIT_72(INIT['h72*320+:320]),\r
+                       .INIT_73(INIT['h73*320+:320]),\r
+                       .INIT_74(INIT['h74*320+:320]),\r
+                       .INIT_75(INIT['h75*320+:320]),\r
+                       .INIT_76(INIT['h76*320+:320]),\r
+                       .INIT_77(INIT['h77*320+:320]),\r
+                       .INIT_78(INIT['h78*320+:320]),\r
+                       .INIT_79(INIT['h79*320+:320]),\r
+                       .INIT_7A(INIT['h7a*320+:320]),\r
+                       .INIT_7B(INIT['h7b*320+:320]),\r
+                       .INIT_7C(INIT['h7c*320+:320]),\r
+                       .INIT_7D(INIT['h7d*320+:320]),\r
+                       .INIT_7E(INIT['h7e*320+:320]),\r
+                       .INIT_7F(INIT['h7f*320+:320]),\r
+                       .A_RD_WIDTH(0),\r
+                       .A_WR_WIDTH(PORT_W_WIDTH),\r
+                       .B_RD_WIDTH(PORT_R_WIDTH),\r
+                       .B_WR_WIDTH(0),\r
+                       .RAM_MODE("SDP"),\r
+                       .A_WR_MODE("NO_CHANGE"),\r
+                       .B_WR_MODE("NO_CHANGE"),\r
+                       .A_CLK_INV(!PORT_W_CLK_POL),\r
+                       .B_CLK_INV(!PORT_R_CLK_POL),\r
+               ) _TECHMAP_REPLACE_ (\r
+                       .A_CLK(PORT_W_CLK),\r
+                       .A_EN(PORT_W_CLK_EN),\r
+                       .A_WE(PORT_W_WR_EN),\r
+                       .A_BM(PORT_W_WR_BE[39:0]),\r
+                       .B_BM(PORT_W_WR_BE[79:40]),\r
+                       .A_DI(PORT_W_WR_DATA[39:0]),\r
+                       .B_DI(PORT_W_WR_DATA[79:40]),\r
+                       .A_ADDR({PORT_W_ADDR[14:0], 1'b0}),\r
+                       .B_CLK(PORT_R_CLK),\r
+                       .B_EN(PORT_R_CLK_EN),\r
                        .B_WE(1'b0),\r
-                       .A_ADDR(A1ADDR),\r
-                       .B_ADDR(B1ADDR),\r
-                       .A_DI(A1DATA),\r
-                       .B_DI(40'b0),\r
-                       .A_BM(A1EN),\r
-                       .B_BM(40'b0)\r
+                       .B_ADDR({PORT_R_ADDR[14:0], 1'b0}),\r
+                       .A_DO(PORT_R_RD_DATA[39:0]),\r
+                       .B_DO(PORT_R_RD_DATA[79:40]),\r
                );\r
-       endgenerate\r
+       end\r
+endgenerate\r
 \r
 endmodule\r
index 0131cdcdfbf5aaf4192fa646068b089403c9237e..93b16b2e074457b606aab261fb9dcf24487729f9 100644 (file)
@@ -237,12 +237,7 @@ struct SynthGateMatePass : public ScriptPass
 \r
                if (check_label("map_bram", "(skip if '-nobram')") && !nobram)\r
                {\r
-                       run("memory_bram -rules +/gatemate/brams.txt");\r
-                       run("setundef -zero -params "\r
-                               "t:$__CC_BRAM_CASCADE "\r
-                               "t:$__CC_BRAM_40K_SDP t:$__CC_BRAM_20K_SDP "\r
-                               "t:$__CC_BRAM_20K_TDP t:$__CC_BRAM_40K_TDP "\r
-                       );\r
+                       run("memory_libmap -lib +/gatemate/brams.txt");\r
                        run("techmap -map +/gatemate/brams_map.v");\r
                }\r
 \r
diff --git a/techlibs/gowin/.gitignore b/techlibs/gowin/.gitignore
deleted file mode 100644 (file)
index d6c48e9..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-brams_init.mk
-bram_init_*.vh
index e6a6be970add6bfa6ebe12337090f5049bd5a578..4f3a33f369ed660d5916ddddb19ff68cd1c4a086 100644 (file)
@@ -1,8 +1,6 @@
 
 OBJS += techlibs/gowin/synth_gowin.o
 
-GENFILES += techlibs/gowin/bram_init_16.vh
-
 $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_map.v))
 $(eval $(call add_share_file,share/gowin,techlibs/gowin/cells_sim.v))
 $(eval $(call add_share_file,share/gowin,techlibs/gowin/arith_map.v))
@@ -10,16 +8,3 @@ $(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_map.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))
-
-$(eval $(call add_share_file,share/gowin,techlibs/gowin/brams_init3.vh))
-
-EXTRA_OBJS += techlibs/gowin/brams_init.mk
-.SECONDARY: techlibs/gowin/brams_init.mk
-
-techlibs/gowin/brams_init.mk: techlibs/gowin/brams_init.py
-       $(Q) mkdir -p techlibs/gowin
-       $(P) python3 $<
-       $(Q) touch $@
-
-techlibs/gowin/bram_init_16.vh: techlibs/gowin/brams_init.mk
-$(eval $(call add_gen_share_file,share/gowin,techlibs/gowin/bram_init_16.vh))
index e406f9c5175fffd019b08d7d9677ba351628468e..0c0d8fa3e3e988391dacf4294bcc68aa50c70763 100644 (file)
@@ -1,31 +1,81 @@
-bram $__GW1NR_SDP
-  init 1
-  abits 9 @a9d36
-  dbits 32 @a9d36
-  abits 10 @a10d18
-  dbits 16 @a10d18
-  abits 11 @a11d9
-  dbits 8  @a11d9
-  abits 12 @a12d4
-  dbits 4  @a12d4
-  abits 13 @a13d2
-  dbits 2  @a13d2
-  abits 14 @a14d1
-  dbits 1  @a14d1
-  groups 2
-  ports  1 1
-  wrmode 1 0
-  enable 4 1 @a9d36
-  enable 2 1 @a10d18
-  enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
+ram block $__GOWIN_SP_ {
+       abits 14;
+       widths 1 2 4 9 18 36 per_port;
+       byte 9;
+       cost 128;
+       init no_undef;
+       port srsw "A" {
+               clock posedge;
+               clken;
+               wrbe_separate;
+               option "RESET_MODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESET_MODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+               portoption "WRITE_MODE" 0 {
+                       rdwr no_change;
+               }
+               portoption "WRITE_MODE" 1 {
+                       rdwr new;
+               }
+               portoption "WRITE_MODE" 2 {
+                       rdwr old;
+               }
+       }
+}
 
-match $__GW1NR_SDP
-  min bits 2048
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-endmatch
+ram block $__GOWIN_DP_ {
+       abits 14;
+       widths 1 2 4 9 18 per_port;
+       byte 9;
+       cost 128;
+       init no_undef;
+       port srsw "A" "B" {
+               clock posedge;
+               clken;
+               wrbe_separate;
+               option "RESET_MODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESET_MODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+               portoption "WRITE_MODE" 0 {
+                       rdwr no_change;
+               }
+               portoption "WRITE_MODE" 1 {
+                       rdwr new;
+               }
+               portoption "WRITE_MODE" 2 {
+                       rdwr old;
+               }
+       }
+}
+
+ram block $__GOWIN_SDP_ {
+       abits 14;
+       widths 1 2 4 9 18 36 per_port;
+       byte 9;
+       cost 128;
+       init no_undef;
+       port sr "R" {
+               clock posedge;
+               clken;
+               option "RESET_MODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESET_MODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+       port sw "W" {
+               clock posedge;
+               clken;
+               wrbe_separate;
+       }
+}
diff --git a/techlibs/gowin/brams_init.py b/techlibs/gowin/brams_init.py
deleted file mode 100755 (executable)
index b78eb8d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/usr/bin/env python3
-
-with open("techlibs/gowin/bram_init_16.vh", "w") as f:
-    for i in range(0, 0x40):
-        low = i << 8
-        hi = ((i+1) << 8)-1
-        snippet = "INIT[%d:%d]" % (hi, low)
-        print(".INIT_RAM_%02X({%s})," % (i, snippet), file=f)
diff --git a/techlibs/gowin/brams_init3.vh b/techlibs/gowin/brams_init3.vh
deleted file mode 100644 (file)
index 84397fa..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-localparam [15:0] INIT_0 = {
-  INIT[  60], INIT[  56], INIT[  52], INIT[  48], INIT[  44], INIT[  40], INIT[  36], INIT[  32], INIT[  28], INIT[  24], INIT[  20], INIT[  16], INIT[  12], INIT[   8], INIT[   4], INIT[   0]
-};
-localparam [15:0] INIT_1 = {
-  INIT[  61], INIT[  57], INIT[  53], INIT[  49], INIT[  45], INIT[  41], INIT[  37], INIT[  33], INIT[  29], INIT[  25], INIT[  21], INIT[  17], INIT[  13], INIT[   9], INIT[   5], INIT[   1]
-};
-localparam [15:0] INIT_2 = {
-  INIT[  62], INIT[  58], INIT[  54], INIT[  50], INIT[  46], INIT[  42], INIT[  38], INIT[  34], INIT[  30], INIT[  26], INIT[  22], INIT[  18], INIT[  14], INIT[  10], INIT[   6], INIT[   2]
-};
-localparam [15:0] INIT_3 = {
-  INIT[  63], INIT[  59], INIT[  55], INIT[  51], INIT[  47], INIT[  43], INIT[  39], INIT[  35], INIT[  31], INIT[  27], INIT[  23], INIT[  19], INIT[  15], INIT[  11], INIT[   7], INIT[   3]
-};
index fbebc4af88c89ca4465a91aa10b183ae2ef7a93f..7ffc91bacc15f735c8fadf0cd10b31962dc49bf5 100644 (file)
-/* Semi Dual Port (SDP) memory have the following configurations:
- * Memory Config    RAM(BIT)   Port Mode   Memory Depth   Data Depth
- * ----------------|---------| ----------|--------------|------------|
- * B-SRAM_16K_SD1      16K      16Kx1       16,384           1
- * B-SRAM_8K_SD2       16K       8Kx2        8,192           2
- * B-SRAM_4K_SD4       16K       4Kx2        4,096           4
- */
-module \$__GW1NR_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 16;
-       parameter CFG_ENABLE_A = 1;
-       parameter [16383:0] INIT = 16384'hx;
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-
-       input CLK2;
-       input CLK3;
-
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;   
-       input [CFG_ENABLE_A-1:0] A1EN;
-
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
-
-       wire [31-CFG_DBITS:0] open;
-
-       
-       generate if (CFG_DBITS == 1) begin
-               SDP   #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(1),
-                       .BIT_WIDTH_1(1),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
-                       .WREB(1'b0),   .CEB(B1EN),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
-                       .DO({open, B1DATA}),
-                       .ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else if (CFG_DBITS == 2) begin
-               SDP    #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(2),
-                       .BIT_WIDTH_1(2),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
-                       .WREB(1'b0),   .CEB(B1EN),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
-                       .DO({open, B1DATA}),
-                       .ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else if (CFG_DBITS <= 4) begin
-               SDP    #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(4),
-                       .BIT_WIDTH_1(4),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(A1EN),   .OCE(1'b0),
-                       .WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
-                       .DO({open, B1DATA}),
-                       .ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else if (CFG_DBITS <= 8) begin
-               SDP    #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(8),
-                       .BIT_WIDTH_1(8),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(A1EN),   .OCE(1'b0), .CEA(1'b1),
-                       .WREB(1'b0),   .CEB(B1EN),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
-                       .DO({open, B1DATA}),
-                       .ADA({A1ADDR, {(14-CFG_ABITS){1'b0}}}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else if (CFG_DBITS <= 16) begin
-               SDP    #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(16),
-                       .BIT_WIDTH_1(16),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(|A1EN),   .OCE(1'b0),
-                       .WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI({{(32-CFG_DBITS){1'b0}}, A1DATA}),
-                       .DO({open, B1DATA}),
-                       .ADA({A1ADDR, {(12-CFG_ABITS){1'b0}}, A1EN}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else if (CFG_DBITS <= 32) begin
-               SDP    #(
-      `include "bram_init_16.vh"
-                       .READ_MODE(0),
-                       .BIT_WIDTH_0(32),
-                       .BIT_WIDTH_1(32),
-                       .BLK_SEL(3'b000),
-                       .RESET_MODE("SYNC")
-               ) _TECHMAP_REPLACE_ (
-                       .CLKA(CLK2),   .CLKB(CLK3),
-                       .WREA(|A1EN),   .OCE(1'b0),
-                       .WREB(1'b0),   .CEB(B1EN), .CEA(1'b1),
-                       .RESETA(1'b0), .RESETB(1'b0), .BLKSEL(3'b000),
-                       .DI(A1DATA),
-                       .DO(B1DATA),
-                       .ADA({A1ADDR, {(10-CFG_ABITS){1'b0}}, A1EN}),
-                       .ADB({B1ADDR, {(14-CFG_ABITS){1'b0}}})
-               );
-       end else begin
-               wire TECHMAP_FAIL = 1'b1;
-       end endgenerate
-       
+`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 wre(width, wr_en, wr_be) (width < 18 ? wr_en | wr_be[0] : wr_en)
+`define addrbe(width, addr, wr_be) (width < 18 ? addr : {addr[13:4], wr_be})
+
+
+`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_WR_BE_WIDTH = 4;
+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_WR_BE_WIDTH-1:0] PORT_A_WR_BE;
+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 WRE = `wre(PORT_A_WIDTH, PORT_A_WR_EN, PORT_A_WR_BE);
+wire [13:0] AD = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE);
+
+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(WRE),
+               .RESET(RST),
+               .OCE(1'b0),
+               .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(WRE),
+               .RESET(RST),
+               .OCE(1'b0),
+               .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_WR_BE_WIDTH = 2;
+parameter PORT_A_OPTION_WRITE_MODE = 0;
+
+parameter PORT_B_WIDTH = 18;
+parameter PORT_B_WR_BE_WIDTH = 2;
+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_WR_BE_WIDTH-1:0] PORT_A_WR_BE;
+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_WR_BE_WIDTH-1:0] PORT_B_WR_BE;
+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 WREA = `wre(PORT_A_WIDTH, PORT_A_WR_EN, PORT_A_WR_BE);
+wire WREB = `wre(PORT_B_WIDTH, PORT_B_WR_EN, PORT_B_WR_BE);
+wire [13:0] ADA = `addrbe(PORT_A_WIDTH, PORT_A_ADDR, PORT_A_WR_BE);
+wire [13:0] ADB = `addrbe(PORT_B_WIDTH, PORT_B_ADDR, PORT_B_WR_BE);
+
+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);
+
+       DP #(
+               `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(3'b000),
+               .RESET_MODE(OPTION_RESET_MODE),
+       ) _TECHMAP_REPLACE_ (
+               .BLKSEL(3'b000),
+
+               .CLKA(PORT_A_CLK),
+               .CEA(PORT_A_CLK_EN),
+               .WREA(WREA),
+               .RESETA(RSTA),
+               .OCEA(1'b0),
+               .ADA(ADA),
+               .DIA(DIA),
+               .DOA(DOA),
+
+               .CLKB(PORT_B_CLK),
+               .CEB(PORT_B_CLK_EN),
+               .WREB(WREB),
+               .RESETB(RSTB),
+               .OCEB(1'b0),
+               .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;
+
+       DPX9 #(
+               `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(3'b000),
+               .RESET_MODE(OPTION_RESET_MODE),
+       ) _TECHMAP_REPLACE_ (
+               .BLKSEL(3'b000),
+
+               .CLKA(PORT_A_CLK),
+               .CEA(PORT_A_CLK_EN),
+               .WREA(WREA),
+               .RESETA(RSTA),
+               .OCEA(1'b0),
+               .ADA(ADA),
+               .DIA(DIA),
+               .DOA(DOA),
+
+               .CLKB(PORT_B_CLK),
+               .CEB(PORT_B_CLK_EN),
+               .WREB(WREB),
+               .RESETB(RSTB),
+               .OCEB(1'b0),
+               .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;
+parameter PORT_W_WR_BE_WIDTH = 2;
+
+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_WR_BE_WIDTH-1:0] PORT_W_WR_BE;
+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 WRE = `wre(PORT_W_WIDTH, PORT_W_WR_EN, PORT_W_WR_BE);
+wire [13:0] ADW = `addrbe(PORT_W_WIDTH, PORT_W_ADDR, PORT_W_WR_BE);
+
+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);
+
+       SDP #(
+               `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(3'b000),
+               .RESET_MODE(OPTION_RESET_MODE),
+       ) _TECHMAP_REPLACE_ (
+               .BLKSEL(3'b000),
+
+               .CLKA(PORT_W_CLK),
+               .CEA(PORT_W_CLK_EN),
+               .WREA(WRE),
+               .RESETA(1'b0),
+               .ADA(ADW),
+               .DI(DI),
+
+               .CLKB(PORT_R_CLK),
+               .CEB(PORT_R_CLK_EN),
+               .WREB(1'b0),
+               .RESETB(RST),
+               .OCE(1'b0),
+               .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;
+
+       SDPX9 #(
+               `INIT(init_slice_x9)
+               .READ_MODE(1'b0),
+               .BIT_WIDTH_0(PORT_W_WIDTH),
+               .BIT_WIDTH_1(PORT_R_WIDTH),
+               .BLK_SEL(3'b000),
+               .RESET_MODE(OPTION_RESET_MODE),
+       ) _TECHMAP_REPLACE_ (
+               .BLKSEL(3'b000),
+
+               .CLKA(PORT_W_CLK),
+               .CEA(PORT_W_CLK_EN),
+               .WREA(WRE),
+               .RESETA(1'b0),
+               .ADA(ADW),
+               .DI(DI),
+
+               .CLKB(PORT_R_CLK),
+               .CEB(PORT_R_CLK_EN),
+               .WREB(1'b0),
+               .RESETB(RST),
+               .OCE(1'b0),
+               .ADB(PORT_R_ADDR),
+               .DO(DO),
+       );
+
+end
+
+endgenerate
+
 endmodule
index 9db5302511dbea163eb28eb853abfb922b180bbe..76c4cd5841c70f1e19db907beeeaa746b731b881 100644 (file)
@@ -1,17 +1,13 @@
-bram $__GW1NR_RAM16S4
-  init 1
-  abits 4
-  dbits 4
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 1
-  clocks 0 1
-  clkpol 0 1
-endbram
-
-match $__GW1NR_RAM16S4
-  make_outreg
-  min wports 1
-endmatch
+ram distributed $__GOWIN_LUTRAM_ {
+       abits 4;
+       width 4;
+       cost 4;
+       widthscale;
+       init no_undef;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
index e5daab6ae74e47e7ecabd2ca73ede3e0f386af2e..6396ef7c6188e84c7b9bf0b7c9ffc66ff75a2708 100644 (file)
@@ -1,32 +1,65 @@
-module \$__GW1NR_RAM16S4 (CLK1, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 4;
-       parameter CFG_DBITS = 4;
-
-        parameter [63:0] INIT = 64'bx;
-       input CLK1;
-
-       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;
-
-        `include "brams_init3.vh"
-
-  RAM16SDP4
-   #(.INIT_0(INIT_0),
-     .INIT_1(INIT_1),
-     .INIT_2(INIT_2),
-     .INIT_3(INIT_3))
-   _TECHMAP_REPLACE_
-     (.WAD(B1ADDR),
-      .RAD(A1ADDR),
-      .DI(B1DATA),
-      .DO(A1DATA),
-      .CLK(CLK1),
-      .WRE(B1EN));
-
-       
+module $__GOWIN_LUTRAM_(...);
+
+parameter INIT = 64'bx;
+parameter BITS_USED = 0;
+
+input PORT_W_CLK;
+input [3:0] PORT_W_ADDR;
+input PORT_W_WR_EN;
+input [3:0] PORT_W_WR_DATA;
+
+input [3:0] PORT_R_ADDR;
+output [3:0] PORT_R_RD_DATA;
+
+function [15:0] init_slice;
+input integer idx;
+integer i;
+for (i = 0; i < 16; i = i + 1)
+       init_slice[i] = INIT[4*i+idx];
+endfunction
+
+generate
+
+casez(BITS_USED)
+4'b000z:
+RAM16SDP1 #(
+       .INIT_0(init_slice(0)),
+) _TECHMAP_REPLACE_ (
+       .WAD(PORT_W_ADDR),
+       .RAD(PORT_R_ADDR),
+       .DI(PORT_W_WR_DATA[0]),
+       .DO(PORT_R_RD_DATA[0]),
+       .CLK(PORT_W_CLK),
+       .WRE(PORT_W_WR_EN)
+);
+4'b00zz:
+RAM16SDP2 #(
+       .INIT_0(init_slice(0)),
+       .INIT_1(init_slice(1)),
+) _TECHMAP_REPLACE_ (
+       .WAD(PORT_W_ADDR),
+       .RAD(PORT_R_ADDR),
+       .DI(PORT_W_WR_DATA[1:0]),
+       .DO(PORT_R_RD_DATA[1:0]),
+       .CLK(PORT_W_CLK),
+       .WRE(PORT_W_WR_EN)
+);
+default:
+RAM16SDP4 #(
+       .INIT_0(init_slice(0)),
+       .INIT_1(init_slice(1)),
+       .INIT_2(init_slice(2)),
+       .INIT_3(init_slice(3)),
+) _TECHMAP_REPLACE_ (
+       .WAD(PORT_W_ADDR),
+       .RAD(PORT_R_ADDR),
+       .DI(PORT_W_WR_DATA),
+       .DO(PORT_R_RD_DATA),
+       .CLK(PORT_W_CLK),
+       .WRE(PORT_W_WR_EN)
+);
+endcase
+
+endgenerate
+
 endmodule
index cfbc9b9a63e8b264d79a238a29722a4b3a8c7894..d900bd255670fe353078a65bce1ae0de5f21e2f7 100644 (file)
@@ -208,17 +208,17 @@ struct SynthGowinPass : public ScriptPass
                        run("synth -run coarse");
                }
 
-               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
+               if (check_label("map_ram"))
                {
-                       run("memory_bram -rules +/gowin/brams.txt");
-                       run("techmap -map +/gowin/brams_map.v");
-               }
-
-               if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
-               {
-                       run("memory_bram -rules +/gowin/lutrams.txt");
-                       run("techmap -map +/gowin/lutrams_map.v");
-                       run("setundef -params -zero t:RAM16S4");
+                       std::string args = "";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (nolutram)
+                               args += " -no-auto-distributed";
+                       if (help_mode)
+                               args += " [-no-auto-block] [-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");
                }
 
                if (check_label("map_ffram"))
diff --git a/techlibs/ice40/.gitignore b/techlibs/ice40/.gitignore
deleted file mode 100644 (file)
index 6bf3b67..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-brams_init.mk
-brams_init1.vh
-brams_init2.vh
-brams_init3.vh
index 8ce3cb024573c5c253ef785254ab263aa7d11fb9..4bf8e4e86f08275139cb5c973dd04229e59c0758 100644 (file)
@@ -3,22 +3,6 @@ OBJS += techlibs/ice40/synth_ice40.o
 OBJS += techlibs/ice40/ice40_braminit.o
 OBJS += techlibs/ice40/ice40_opt.o
 
-GENFILES += techlibs/ice40/brams_init1.vh
-GENFILES += techlibs/ice40/brams_init2.vh
-GENFILES += techlibs/ice40/brams_init3.vh
-
-EXTRA_OBJS += techlibs/ice40/brams_init.mk
-.SECONDARY: techlibs/ice40/brams_init.mk
-
-techlibs/ice40/brams_init.mk: techlibs/ice40/brams_init.py
-       $(Q) mkdir -p techlibs/ice40
-       $(P) $(PYTHON_EXECUTABLE) $<
-       $(Q) touch techlibs/ice40/brams_init.mk
-
-techlibs/ice40/brams_init1.vh: techlibs/ice40/brams_init.mk
-techlibs/ice40/brams_init2.vh: techlibs/ice40/brams_init.mk
-techlibs/ice40/brams_init3.vh: techlibs/ice40/brams_init.mk
-
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/arith_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/ff_map.v))
@@ -26,10 +10,7 @@ $(eval $(call add_share_file,share/ice40,techlibs/ice40/cells_sim.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/latches_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams.txt))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/brams_map.v))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/spram.txt))
+$(eval $(call add_share_file,share/ice40,techlibs/ice40/spram_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/dsp_map.v))
 $(eval $(call add_share_file,share/ice40,techlibs/ice40/abc9_model.v))
-
-$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init1.vh))
-$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init2.vh))
-$(eval $(call add_gen_share_file,share/ice40,techlibs/ice40/brams_init3.vh))
-
index 36dfddab25bbe87f2f4058c6c8c6bb984bebec7e..518972c2ae9f711cf29f1d64a6a95cd96937cdc3 100644 (file)
-bram $__ICE40_RAM4K_M0
-  init 1
-  abits 8
-  dbits 16
-  groups 2
-  ports  1  1
-  wrmode 0  1
-  enable 1 16
-  transp 0  0
-  clocks 2  3
-  clkpol 2  3
-endbram
-
-bram $__ICE40_RAM4K_M123
-  init 1
-  abits  9 @M1
-  dbits  8 @M1
-  abits 10 @M2
-  dbits  4 @M2
-  abits 11 @M3
-  dbits  2 @M3
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-# The syn_* attributes are described in:
-# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx
-attr_icase 1
-
-match $__ICE40_RAM4K_M0
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min efficiency 2
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ICE40_RAM4K_M0
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ICE40_RAM4K_M0
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ICE40_RAM4K_M123
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min efficiency 2
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ICE40_RAM4K_M123
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__ICE40_RAM4K_M123
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  make_transp
-endmatch
+ram block $__ICE40_RAM4K_ {
+       abits 11;
+       widths 2 4 8 16 per_port;
+       cost 64;
+       option "HAS_BE" 1 {
+               byte 1;
+       }
+       init any;
+       port sw "W" {
+               option "HAS_BE" 0 {
+                       width 2 4 8;
+               }
+               option "HAS_BE" 1 {
+                       width 16;
+                       wrbe_separate;
+               }
+               clock anyedge;
+       }
+       port sr "R" {
+               clock anyedge;
+               rden;
+       }
+}
diff --git a/techlibs/ice40/brams_init.py b/techlibs/ice40/brams_init.py
deleted file mode 100644 (file)
index 4a14851..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/usr/bin/env python3
-
-def write_init_vh(filename, initbits):
-    with open(filename, "w") as f:
-        for i in range(16):
-            print("localparam [255:0] INIT_%X = {" % i, file=f)
-            for k in range(32):
-                print("  %s%s" % (", ".join(["INIT[%4d]" % initbits[i*256 + 255 - k*8 - l] for l in range(8)]), "," if k != 31 else ""), file=f)
-            print("};", file=f);
-
-write_init_vh("techlibs/ice40/brams_init1.vh", [i//2 + 2048*(i%2) for i in range(4096)])
-write_init_vh("techlibs/ice40/brams_init2.vh", [i//4 + 1024*(i%4) for i in range(4096)])
-write_init_vh("techlibs/ice40/brams_init3.vh", [i//8 +  512*(i%8) for i in range(4096)])
-
index db9f5d8ce5965cd74a4d1d9515b79b6ca12fa865..9d7b793e1e89b28195bf3a6c92363a4dd71a64d6 100644 (file)
-
-module \$__ICE40_RAM4K (
-       output [15:0] RDATA,
-       input         RCLK, RCLKE, RE,
-       input  [10:0] RADDR,
-       input         WCLK, WCLKE, WE,
-       input  [10:0] WADDR,
-       input  [15:0] MASK, WDATA
-);
-       parameter [1:0] READ_MODE = 0;
-       parameter [1:0] WRITE_MODE = 0;
-       parameter [0:0] NEGCLK_R = 0;
-       parameter [0:0] NEGCLK_W = 0;
-
-       parameter [255:0] INIT_0 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_1 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_2 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_3 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_4 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_5 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_6 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_7 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_8 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_9 = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_A = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_B = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_C = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_D = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-       parameter [255:0] INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000;
-
-       generate
-               case ({NEGCLK_R, NEGCLK_W})
-                       2'b00:
-                               SB_RAM40_4K #(
-                                       .READ_MODE(READ_MODE),
-                                       .WRITE_MODE(WRITE_MODE),
-                                       .INIT_0(INIT_0),
-                                       .INIT_1(INIT_1),
-                                       .INIT_2(INIT_2),
-                                       .INIT_3(INIT_3),
-                                       .INIT_4(INIT_4),
-                                       .INIT_5(INIT_5),
-                                       .INIT_6(INIT_6),
-                                       .INIT_7(INIT_7),
-                                       .INIT_8(INIT_8),
-                                       .INIT_9(INIT_9),
-                                       .INIT_A(INIT_A),
-                                       .INIT_B(INIT_B),
-                                       .INIT_C(INIT_C),
-                                       .INIT_D(INIT_D),
-                                       .INIT_E(INIT_E),
-                                       .INIT_F(INIT_F)
-                               ) _TECHMAP_REPLACE_ (
-                                       .RDATA(RDATA),
-                                       .RCLK (RCLK ),
-                                       .RCLKE(RCLKE),
-                                       .RE   (RE   ),
-                                       .RADDR(RADDR),
-                                       .WCLK (WCLK ),
-                                       .WCLKE(WCLKE),
-                                       .WE   (WE   ),
-                                       .WADDR(WADDR),
-                                       .MASK (MASK ),
-                                       .WDATA(WDATA)
-                               );
-                       2'b01:
-                               SB_RAM40_4KNW #(
-                                       .READ_MODE(READ_MODE),
-                                       .WRITE_MODE(WRITE_MODE),
-                                       .INIT_0(INIT_0),
-                                       .INIT_1(INIT_1),
-                                       .INIT_2(INIT_2),
-                                       .INIT_3(INIT_3),
-                                       .INIT_4(INIT_4),
-                                       .INIT_5(INIT_5),
-                                       .INIT_6(INIT_6),
-                                       .INIT_7(INIT_7),
-                                       .INIT_8(INIT_8),
-                                       .INIT_9(INIT_9),
-                                       .INIT_A(INIT_A),
-                                       .INIT_B(INIT_B),
-                                       .INIT_C(INIT_C),
-                                       .INIT_D(INIT_D),
-                                       .INIT_E(INIT_E),
-                                       .INIT_F(INIT_F)
-                               ) _TECHMAP_REPLACE_ (
-                                       .RDATA(RDATA),
-                                       .RCLK (RCLK ),
-                                       .RCLKE(RCLKE),
-                                       .RE   (RE   ),
-                                       .RADDR(RADDR),
-                                       .WCLKN(WCLK ),
-                                       .WCLKE(WCLKE),
-                                       .WE   (WE   ),
-                                       .WADDR(WADDR),
-                                       .MASK (MASK ),
-                                       .WDATA(WDATA)
-                               );
-                       2'b10:
-                               SB_RAM40_4KNR #(
-                                       .READ_MODE(READ_MODE),
-                                       .WRITE_MODE(WRITE_MODE),
-                                       .INIT_0(INIT_0),
-                                       .INIT_1(INIT_1),
-                                       .INIT_2(INIT_2),
-                                       .INIT_3(INIT_3),
-                                       .INIT_4(INIT_4),
-                                       .INIT_5(INIT_5),
-                                       .INIT_6(INIT_6),
-                                       .INIT_7(INIT_7),
-                                       .INIT_8(INIT_8),
-                                       .INIT_9(INIT_9),
-                                       .INIT_A(INIT_A),
-                                       .INIT_B(INIT_B),
-                                       .INIT_C(INIT_C),
-                                       .INIT_D(INIT_D),
-                                       .INIT_E(INIT_E),
-                                       .INIT_F(INIT_F)
-                               ) _TECHMAP_REPLACE_ (
-                                       .RDATA(RDATA),
-                                       .RCLKN(RCLK ),
-                                       .RCLKE(RCLKE),
-                                       .RE   (RE   ),
-                                       .RADDR(RADDR),
-                                       .WCLK (WCLK ),
-                                       .WCLKE(WCLKE),
-                                       .WE   (WE   ),
-                                       .WADDR(WADDR),
-                                       .MASK (MASK ),
-                                       .WDATA(WDATA)
-                               );
-                       2'b11:
-                               SB_RAM40_4KNRNW #(
-                                       .READ_MODE(READ_MODE),
-                                       .WRITE_MODE(WRITE_MODE),
-                                       .INIT_0(INIT_0),
-                                       .INIT_1(INIT_1),
-                                       .INIT_2(INIT_2),
-                                       .INIT_3(INIT_3),
-                                       .INIT_4(INIT_4),
-                                       .INIT_5(INIT_5),
-                                       .INIT_6(INIT_6),
-                                       .INIT_7(INIT_7),
-                                       .INIT_8(INIT_8),
-                                       .INIT_9(INIT_9),
-                                       .INIT_A(INIT_A),
-                                       .INIT_B(INIT_B),
-                                       .INIT_C(INIT_C),
-                                       .INIT_D(INIT_D),
-                                       .INIT_E(INIT_E),
-                                       .INIT_F(INIT_F)
-                               ) _TECHMAP_REPLACE_ (
-                                       .RDATA(RDATA),
-                                       .RCLKN(RCLK ),
-                                       .RCLKE(RCLKE),
-                                       .RE   (RE   ),
-                                       .RADDR(RADDR),
-                                       .WCLKN(WCLK ),
-                                       .WCLKE(WCLKE),
-                                       .WE   (WE   ),
-                                       .WADDR(WADDR),
-                                       .MASK (MASK ),
-                                       .WDATA(WDATA)
-                               );
-               endcase
-       endgenerate
-endmodule
-
-
-module \$__ICE40_RAM4K_M0 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter [0:0] CLKPOL2 = 1;
-       parameter [0:0] CLKPOL3 = 1;
-
-       parameter [4095:0] INIT = 4096'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [7:0] A1ADDR;
-       output [15:0] A1DATA;
-       input A1EN;
-
-       input [7:0] B1ADDR;
-       input [15:0] B1DATA;
-       input [15:0] B1EN;
-
-       wire [10:0] A1ADDR_11 = A1ADDR;
-       wire [10:0] B1ADDR_11 = B1ADDR;
-
-       \$__ICE40_RAM4K #(
-               .READ_MODE(0),
-               .WRITE_MODE(0),
-               .NEGCLK_R(!CLKPOL2),
-               .NEGCLK_W(!CLKPOL3),
-               .INIT_0(INIT[ 0*256 +: 256]),
-               .INIT_1(INIT[ 1*256 +: 256]),
-               .INIT_2(INIT[ 2*256 +: 256]),
-               .INIT_3(INIT[ 3*256 +: 256]),
-               .INIT_4(INIT[ 4*256 +: 256]),
-               .INIT_5(INIT[ 5*256 +: 256]),
-               .INIT_6(INIT[ 6*256 +: 256]),
-               .INIT_7(INIT[ 7*256 +: 256]),
-               .INIT_8(INIT[ 8*256 +: 256]),
-               .INIT_9(INIT[ 9*256 +: 256]),
-               .INIT_A(INIT[10*256 +: 256]),
-               .INIT_B(INIT[11*256 +: 256]),
-               .INIT_C(INIT[12*256 +: 256]),
-               .INIT_D(INIT[13*256 +: 256]),
-               .INIT_E(INIT[14*256 +: 256]),
-               .INIT_F(INIT[15*256 +: 256])
-       ) _TECHMAP_REPLACE_ (
-               .RDATA(A1DATA),
-               .RADDR(A1ADDR_11),
-               .RCLK(CLK2),
-               .RCLKE(A1EN),
-               .RE(1'b1),
-               .WDATA(B1DATA),
-               .WADDR(B1ADDR_11),
-               .MASK(~B1EN),
-               .WCLK(CLK3),
-               .WCLKE(|B1EN),
-               .WE(1'b1)
-       );
-endmodule
-
-module \$__ICE40_RAM4K_M123 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 8;
-
-       parameter [0:0] CLKPOL2 = 1;
-       parameter [0:0] CLKPOL3 = 1;
-
-       parameter [4095:0] INIT = 4096'bx;
-
-       localparam MODE =
-               CFG_ABITS ==  9 ? 1 :
-               CFG_ABITS == 10 ? 2 :
-               CFG_ABITS == 11 ? 3 : '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 B1EN;
-
-       wire [10:0] A1ADDR_11 = A1ADDR;
-       wire [10:0] B1ADDR_11 = B1ADDR;
-
-       wire [15:0] A1DATA_16, B1DATA_16;
-
-`define INSTANCE \
-       \$__ICE40_RAM4K #( \
-               .READ_MODE(MODE), \
-               .WRITE_MODE(MODE), \
-               .NEGCLK_R(!CLKPOL2), \
-               .NEGCLK_W(!CLKPOL3), \
-               .INIT_0(INIT_0), \
-               .INIT_1(INIT_1), \
-               .INIT_2(INIT_2), \
-               .INIT_3(INIT_3), \
-               .INIT_4(INIT_4), \
-               .INIT_5(INIT_5), \
-               .INIT_6(INIT_6), \
-               .INIT_7(INIT_7), \
-               .INIT_8(INIT_8), \
-               .INIT_9(INIT_9), \
-               .INIT_A(INIT_A), \
-               .INIT_B(INIT_B), \
-               .INIT_C(INIT_C), \
-               .INIT_D(INIT_D), \
-               .INIT_E(INIT_E), \
-               .INIT_F(INIT_F) \
+module $__ICE40_RAM4K_ (...);
+
+parameter INIT = 0;
+parameter OPTION_HAS_BE = 1;
+parameter PORT_R_WIDTH = 16;
+parameter PORT_W_WIDTH = 16;
+parameter PORT_W_WR_BE_WIDTH = 16;
+parameter PORT_R_CLK_POL = 1;
+parameter PORT_W_CLK_POL = 1;
+
+input PORT_R_CLK;
+input PORT_R_RD_EN;
+input [10:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+
+input PORT_W_CLK;
+input PORT_W_WR_EN;
+input [15:0] PORT_W_WR_BE;
+input [10:0] PORT_W_ADDR;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+
+wire [15:0] RDATA;
+wire [15:0] WDATA;
+wire [15:0] MASK;
+wire [10:0] RADDR = {PORT_R_ADDR[0], PORT_R_ADDR[1], PORT_R_ADDR[2], PORT_R_ADDR[10:3]};
+wire [10:0] WADDR = {PORT_W_ADDR[0], PORT_W_ADDR[1], PORT_W_ADDR[2], PORT_W_ADDR[10:3]};
+
+function [1:0] mode;
+       input integer width;
+       case (width)
+       16: mode = 0;
+       8: mode = 1;
+       4: mode = 2;
+       2: mode = 3;
+       endcase
+endfunction
+
+function [255:0] slice_init;
+       input [3:0] idx;
+       integer i;
+       reg [7:0] ri;
+       reg [11:0] a;
+       for (i = 0; i < 256; i = i + 1) begin
+               ri = i;
+               a = {idx, ri[7:4], ri[0], ri[1], ri[2], ri[3]};
+               slice_init[i] = INIT[a];
+       end
+endfunction
+
+`define INSTANCE(type, rclk, wclk) \
+       type #( \
+               .INIT_0(slice_init(0)), \
+               .INIT_1(slice_init(1)), \
+               .INIT_2(slice_init(2)), \
+               .INIT_3(slice_init(3)), \
+               .INIT_4(slice_init(4)), \
+               .INIT_5(slice_init(5)), \
+               .INIT_6(slice_init(6)), \
+               .INIT_7(slice_init(7)), \
+               .INIT_8(slice_init(8)), \
+               .INIT_9(slice_init(9)), \
+               .INIT_A(slice_init(10)), \
+               .INIT_B(slice_init(11)), \
+               .INIT_C(slice_init(12)), \
+               .INIT_D(slice_init(13)), \
+               .INIT_E(slice_init(14)), \
+               .INIT_F(slice_init(15)), \
+               .READ_MODE(mode(PORT_R_WIDTH)), \
+               .WRITE_MODE(mode(PORT_W_WIDTH)) \
        ) _TECHMAP_REPLACE_ ( \
-               .RDATA(A1DATA_16), \
-               .RADDR(A1ADDR_11), \
-               .RCLK(CLK2), \
-               .RCLKE(A1EN), \
+               .RDATA(RDATA), \
+               .rclk(PORT_R_CLK), \
+               .RCLKE(PORT_R_RD_EN), \
                .RE(1'b1), \
-               .WDATA(B1DATA_16), \
-               .WADDR(B1ADDR_11), \
-               .WCLK(CLK3), \
-               .WCLKE(|B1EN), \
-               .WE(1'b1) \
+               .RADDR(RADDR), \
+               .WDATA(WDATA), \
+               .wclk(PORT_W_CLK), \
+               .WCLKE(PORT_W_WR_EN), \
+               .WE(1'b1), \
+               .WADDR(WADDR), \
+               .MASK(MASK), \
        );
 
-       generate
-               if (MODE == 1) begin
-                       assign A1DATA = {A1DATA_16[14], A1DATA_16[12], A1DATA_16[10], A1DATA_16[ 8],
-                                        A1DATA_16[ 6], A1DATA_16[ 4], A1DATA_16[ 2], A1DATA_16[ 0]};
-                       assign {B1DATA_16[14], B1DATA_16[12], B1DATA_16[10], B1DATA_16[ 8],
-                               B1DATA_16[ 6], B1DATA_16[ 4], B1DATA_16[ 2], B1DATA_16[ 0]} = B1DATA;
-                       `include "brams_init1.vh"
-                       `INSTANCE
-               end
-               if (MODE == 2) begin
-                       assign A1DATA = {A1DATA_16[13], A1DATA_16[9], A1DATA_16[5], A1DATA_16[1]};
-                       assign {B1DATA_16[13], B1DATA_16[9], B1DATA_16[5], B1DATA_16[1]} = B1DATA;
-                       `include "brams_init2.vh"
-                       `INSTANCE
-               end
-               if (MODE == 3) begin
-                       assign A1DATA = {A1DATA_16[11], A1DATA_16[3]};
-                       assign {B1DATA_16[11], B1DATA_16[3]} = B1DATA;
-                       `include "brams_init3.vh"
-                       `INSTANCE
-               end
-       endgenerate
-
-`undef INSTANCE
+generate
+
+case(PORT_R_WIDTH)
+       2: begin
+               assign PORT_R_RD_DATA = {
+                       RDATA[11],
+                       RDATA[3]
+               };
+       end
+       4: begin
+               assign PORT_R_RD_DATA = {
+                       RDATA[13],
+                       RDATA[5],
+                       RDATA[9],
+                       RDATA[1]
+               };
+       end
+       8: begin
+               assign PORT_R_RD_DATA = {
+                       RDATA[14],
+                       RDATA[6],
+                       RDATA[10],
+                       RDATA[2],
+                       RDATA[12],
+                       RDATA[4],
+                       RDATA[8],
+                       RDATA[0]
+               };
+       end
+       16: begin
+               assign PORT_R_RD_DATA = {
+                       RDATA[15],
+                       RDATA[7],
+                       RDATA[11],
+                       RDATA[3],
+                       RDATA[13],
+                       RDATA[5],
+                       RDATA[9],
+                       RDATA[1],
+                       RDATA[14],
+                       RDATA[6],
+                       RDATA[10],
+                       RDATA[2],
+                       RDATA[12],
+                       RDATA[4],
+                       RDATA[8],
+                       RDATA[0]
+               };
+       end
+endcase
+
+case(PORT_W_WIDTH)
+       2: begin
+               assign {
+                       WDATA[11],
+                       WDATA[3]
+               } = PORT_W_WR_DATA;
+       end
+       4: begin
+               assign {
+                       WDATA[13],
+                       WDATA[5],
+                       WDATA[9],
+                       WDATA[1]
+               } = PORT_W_WR_DATA;
+       end
+       8: begin
+               assign {
+                       WDATA[14],
+                       WDATA[6],
+                       WDATA[10],
+                       WDATA[2],
+                       WDATA[12],
+                       WDATA[4],
+                       WDATA[8],
+                       WDATA[0]
+               } = PORT_W_WR_DATA;
+       end
+       16: begin
+               assign WDATA = {
+                       PORT_W_WR_DATA[15],
+                       PORT_W_WR_DATA[7],
+                       PORT_W_WR_DATA[11],
+                       PORT_W_WR_DATA[3],
+                       PORT_W_WR_DATA[13],
+                       PORT_W_WR_DATA[5],
+                       PORT_W_WR_DATA[9],
+                       PORT_W_WR_DATA[1],
+                       PORT_W_WR_DATA[14],
+                       PORT_W_WR_DATA[6],
+                       PORT_W_WR_DATA[10],
+                       PORT_W_WR_DATA[2],
+                       PORT_W_WR_DATA[12],
+                       PORT_W_WR_DATA[4],
+                       PORT_W_WR_DATA[8],
+                       PORT_W_WR_DATA[0]
+               };
+               assign MASK = ~{
+                       PORT_W_WR_BE[15],
+                       PORT_W_WR_BE[7],
+                       PORT_W_WR_BE[11],
+                       PORT_W_WR_BE[3],
+                       PORT_W_WR_BE[13],
+                       PORT_W_WR_BE[5],
+                       PORT_W_WR_BE[9],
+                       PORT_W_WR_BE[1],
+                       PORT_W_WR_BE[14],
+                       PORT_W_WR_BE[6],
+                       PORT_W_WR_BE[10],
+                       PORT_W_WR_BE[2],
+                       PORT_W_WR_BE[12],
+                       PORT_W_WR_BE[4],
+                       PORT_W_WR_BE[8],
+                       PORT_W_WR_BE[0]
+               };
+       end
+endcase
+
+if (PORT_R_CLK_POL) begin
+       if (PORT_W_CLK_POL) begin
+               `INSTANCE(SB_RAM40_4K, RCLK, WCLK)
+       end else begin
+               `INSTANCE(SB_RAM40_4KNW, RCLK, WCLKN)
+       end
+end else begin
+       if (PORT_W_CLK_POL) begin
+               `INSTANCE(SB_RAM40_4KNR, RCLKN, WCLK)
+       end else begin
+               `INSTANCE(SB_RAM40_4KNRNW, RCLKN, WCLKN)
+       end
+end
+
+endgenerate
 
 endmodule
-
diff --git a/techlibs/ice40/spram.txt b/techlibs/ice40/spram.txt
new file mode 100644 (file)
index 0000000..ed0699f
--- /dev/null
@@ -0,0 +1,12 @@
+ram huge $__ICE40_SPRAM_ {
+       abits 14;
+       width 16;
+       cost 2048;
+       byte 4;
+       port srsw "A" {
+               clock posedge;
+               clken;
+               wrbe_separate;
+               rdwr no_change;
+       }
+}
diff --git a/techlibs/ice40/spram_map.v b/techlibs/ice40/spram_map.v
new file mode 100644 (file)
index 0000000..ae89195
--- /dev/null
@@ -0,0 +1,24 @@
+module $__ICE40_SPRAM_ (...);
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input PORT_A_WR_EN;
+input [3:0] PORT_A_WR_BE;
+input [13:0] PORT_A_ADDR;
+input [15:0] PORT_A_WR_DATA;
+output [15:0] PORT_A_RD_DATA;
+
+SB_SPRAM256KA _TECHMAP_REPLACE_ (
+       .ADDRESS(PORT_A_ADDR),
+       .DATAIN(PORT_A_WR_DATA),
+       .MASKWREN(PORT_A_WR_BE),
+       .WREN(PORT_A_WR_EN),
+       .CHIPSELECT(PORT_A_CLK_EN),
+       .CLOCK(PORT_A_CLK),
+       .STANDBY(1'b0),
+       .SLEEP(1'b0),
+       .POWEROFF(1'b1),
+       .DATAOUT(PORT_A_RD_DATA),
+);
+
+endmodule
index 421ec3b4e2edc36256ec12c3f7b319aeba44a89a..c10b7003eecc2cddf22feeda1f16e610bc220e5e 100644 (file)
@@ -90,6 +90,9 @@ struct SynthIce40Pass : public ScriptPass
                log("    -nobram\n");
                log("        do not use SB_RAM40_4K* cells in output netlist\n");
                log("\n");
+               log("    -spram\n");
+               log("        enable automatic inference of SB_SPRAM256KA\n");
+               log("\n");
                log("    -dsp\n");
                log("        use iCE40 UltraPlus DSP cells for large arithmetic\n");
                log("\n");
@@ -116,7 +119,7 @@ struct SynthIce40Pass : public ScriptPass
        }
 
        string top_opt, blif_file, edif_file, json_file, device_opt;
-       bool nocarry, nodffe, nobram, dsp, flatten, retime, noabc, abc2, vpr, abc9, dff, flowmap;
+       bool nocarry, nodffe, nobram, spram, dsp, flatten, retime, noabc, abc2, vpr, abc9, dff, flowmap;
        int min_ce_use;
 
        void clear_flags() override
@@ -129,6 +132,7 @@ struct SynthIce40Pass : public ScriptPass
                nodffe = false;
                min_ce_use = -1;
                nobram = false;
+               spram = false;
                dsp = false;
                flatten = true;
                retime = false;
@@ -204,6 +208,10 @@ struct SynthIce40Pass : public ScriptPass
                                nobram = true;
                                continue;
                        }
+                       if (args[argidx] == "-spram") {
+                               spram = true;
+                               continue;
+                       }
                        if (args[argidx] == "-dsp") {
                                dsp = true;
                                continue;
@@ -322,19 +330,24 @@ struct SynthIce40Pass : public ScriptPass
                        run("opt_clean");
                }
 
-               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
+               if (check_label("map_ram"))
                {
-                       run("memory_bram -rules +/ice40/brams.txt");
-                       run("techmap -map +/ice40/brams_map.v");
+                       std::string args = "";
+                       if (!spram)
+                               args += " -no-auto-huge";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (help_mode)
+                               args += " [-no-auto-huge] [-no-auto-block]";
+                       run("memory_libmap -lib +/ice40/brams.txt -lib +/ice40/spram.txt" + args, "(-no-auto-huge unless -spram, -no-auto-block if -nobram)");
+                       run("techmap -map +/ice40/brams_map.v -map +/ice40/spram_map.v");
                        run("ice40_braminit");
                }
 
                if (check_label("map_ffram"))
                {
                        run("opt -fast -mux_undef -undriven -fine");
-                       run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
-                           "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
-                           "-attr syn_romstyle=auto -attr syn_romstyle=logic");
+                       run("memory_map");
                        run("opt -undriven -fine");
                }
 
index 6f6f6ce945848378cac897e68fa548a5b3c6fa65..f6aafbd2bde23f9e21e75c5a37c49ee99a5f4908 100644 (file)
@@ -3,3 +3,8 @@ OBJS += techlibs/machxo2/synth_machxo2.o
 
 $(eval $(call add_share_file,share/machxo2,techlibs/machxo2/cells_map.v))
 $(eval $(call add_share_file,share/machxo2,techlibs/machxo2/cells_sim.v))
+
+$(eval $(call add_share_file,share/machxo2,techlibs/machxo2/lutrams.txt))
+$(eval $(call add_share_file,share/machxo2,techlibs/machxo2/lutrams_map.v))
+$(eval $(call add_share_file,share/machxo2,techlibs/machxo2/brams.txt))
+$(eval $(call add_share_file,share/machxo2,techlibs/machxo2/brams_map.v))
diff --git a/techlibs/machxo2/brams.txt b/techlibs/machxo2/brams.txt
new file mode 100644 (file)
index 0000000..3afbeda
--- /dev/null
@@ -0,0 +1,50 @@
+ram block $__DP8KC_ {
+       abits 13;
+       widths 1 2 4 9 per_port;
+       cost 64;
+       init no_undef;
+       port srsw "A" "B" {
+               clock posedge;
+               clken;
+               portoption "WRITEMODE" "NORMAL" {
+                       rdwr no_change;
+               }
+               portoption "WRITEMODE" "WRITETHROUGH" {
+                       rdwr new;
+               }
+               portoption "WRITEMODE" "READBEFOREWRITE" {
+                       rdwr old;
+               }
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated block_wr;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+}
+
+ram block $__PDPW8KC_ {
+       abits 13;
+       widths 1 2 4 9 18 per_port;
+       byte 9;
+       cost 64;
+       init no_undef;
+       port sr "R" {
+               clock posedge;
+               clken;
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+       port sw "W" {
+               width 18;
+               clock posedge;
+               clken;
+       }
+}
diff --git a/techlibs/machxo2/brams_map.v b/techlibs/machxo2/brams_map.v
new file mode 100644 (file)
index 0000000..05a8e8a
--- /dev/null
@@ -0,0 +1,337 @@
+module $__DP8KC_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_A_WIDTH = 18;
+parameter PORT_A_OPTION_WRITEMODE = "NORMAL";
+
+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 [12:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+
+parameter PORT_B_WIDTH = 18;
+parameter PORT_B_OPTION_WRITEMODE = "NORMAL";
+
+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 [12:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [8:0] DOA;
+wire [8:0] DOB;
+wire [8:0] DIA = PORT_A_WR_DATA;
+wire [8:0] DIB = PORT_B_WR_DATA;
+
+assign PORT_A_RD_DATA = DOA;
+assign PORT_B_RD_DATA = DOB;
+
+DP8KC #(
+       .INITVAL_00($sformatf("0x%080x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%080x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%080x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%080x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%080x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%080x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%080x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%080x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%080x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%080x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%080x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%080x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%080x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%080x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%080x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%080x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%080x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%080x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%080x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%080x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%080x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%080x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%080x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%080x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%080x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%080x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%080x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%080x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%080x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%080x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%080x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%080x", init_slice('h1f))),
+       .DATA_WIDTH_A(PORT_A_WIDTH),
+       .DATA_WIDTH_B(PORT_B_WIDTH),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CSDECODE_A("0b000"),
+       .CSDECODE_B("0b000"),
+       .WRITEMODE_A(PORT_A_OPTION_WRITEMODE),
+       .WRITEMODE_B(PORT_B_OPTION_WRITEMODE),
+       .GSR("AUTO")
+) _TECHMAP_REPLACE_ (
+       .CLKA(PORT_A_CLK),
+       .WEA(PORT_A_WR_EN),
+       .CEA(PORT_A_CLK_EN),
+       .OCEA(1'b1),
+       .RSTA(OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+       .CSA0(1'b0),
+       .CSA1(1'b0),
+       .CSA2(1'b0),
+       .ADA0(PORT_A_WIDTH == 9 ? 1'b1 : PORT_A_ADDR[0]),
+       .ADA1(PORT_A_ADDR[1]),
+       .ADA2(PORT_A_ADDR[2]),
+       .ADA3(PORT_A_ADDR[3]),
+       .ADA4(PORT_A_ADDR[4]),
+       .ADA5(PORT_A_ADDR[5]),
+       .ADA6(PORT_A_ADDR[6]),
+       .ADA7(PORT_A_ADDR[7]),
+       .ADA8(PORT_A_ADDR[8]),
+       .ADA9(PORT_A_ADDR[9]),
+       .ADA10(PORT_A_ADDR[10]),
+       .ADA11(PORT_A_ADDR[11]),
+       .ADA12(PORT_A_ADDR[12]),
+       .DIA0(DIA[0]),
+       .DIA1(DIA[1]),
+       .DIA2(DIA[2]),
+       .DIA3(DIA[3]),
+       .DIA4(DIA[4]),
+       .DIA5(DIA[5]),
+       .DIA6(DIA[6]),
+       .DIA7(DIA[7]),
+       .DIA8(DIA[8]),
+       .DOA0(DOA[0]),
+       .DOA1(DOA[1]),
+       .DOA2(DOA[2]),
+       .DOA3(DOA[3]),
+       .DOA4(DOA[4]),
+       .DOA5(DOA[5]),
+       .DOA6(DOA[6]),
+       .DOA7(DOA[7]),
+       .DOA8(DOA[8]),
+
+       .CLKB(PORT_B_CLK),
+       .WEB(PORT_B_WR_EN),
+       .CEB(PORT_B_CLK_EN),
+       .OCEB(1'b1),
+       .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+       .CSB0(1'b0),
+       .CSB1(1'b0),
+       .CSB2(1'b0),
+       .ADB0(PORT_B_WIDTH == 9 ? 1'b1 : PORT_B_ADDR[0]),
+       .ADB1(PORT_B_ADDR[1]),
+       .ADB2(PORT_B_ADDR[2]),
+       .ADB3(PORT_B_ADDR[3]),
+       .ADB4(PORT_B_ADDR[4]),
+       .ADB5(PORT_B_ADDR[5]),
+       .ADB6(PORT_B_ADDR[6]),
+       .ADB7(PORT_B_ADDR[7]),
+       .ADB8(PORT_B_ADDR[8]),
+       .ADB9(PORT_B_ADDR[9]),
+       .ADB10(PORT_B_ADDR[10]),
+       .ADB11(PORT_B_ADDR[11]),
+       .ADB12(PORT_B_ADDR[12]),
+       .DIB0(DIB[0]),
+       .DIB1(DIB[1]),
+       .DIB2(DIB[2]),
+       .DIB3(DIB[3]),
+       .DIB4(DIB[4]),
+       .DIB5(DIB[5]),
+       .DIB6(DIB[6]),
+       .DIB7(DIB[7]),
+       .DIB8(DIB[8]),
+       .DOB0(DOB[0]),
+       .DOB1(DOB[1]),
+       .DOB2(DOB[2]),
+       .DOB3(DOB[3]),
+       .DOB4(DOB[4]),
+       .DOB5(DOB[5]),
+       .DOB6(DOB[6]),
+       .DOB7(DOB[7]),
+       .DOB8(DOB[8]),
+);
+
+endmodule
+
+
+module $__PDPW8KC_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+parameter PORT_R_WIDTH = 18;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input PORT_R_RD_SRST;
+input PORT_R_RD_ARST;
+input [12:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+
+parameter PORT_W_WIDTH = 18;
+parameter PORT_W_WR_EN_WIDTH = 2;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [12:0] PORT_W_ADDR;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [17:0] DI = PORT_W_WR_DATA;
+wire [17:0] DO;
+
+assign PORT_R_RD_DATA = PORT_R_WIDTH == 18 ? DO : DO[17:9];
+
+DP8KC #(
+       .INITVAL_00($sformatf("0x%080x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%080x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%080x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%080x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%080x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%080x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%080x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%080x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%080x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%080x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%080x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%080x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%080x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%080x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%080x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%080x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%080x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%080x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%080x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%080x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%080x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%080x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%080x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%080x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%080x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%080x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%080x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%080x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%080x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%080x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%080x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%080x", init_slice('h1f))),
+       .DATA_WIDTH_A(PORT_W_WIDTH),
+       .DATA_WIDTH_B(PORT_R_WIDTH),
+       .REGMODE_A("NOREG"),
+       .REGMODE_B("NOREG"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+       .CSDECODE_A("0b000"),
+       .CSDECODE_B("0b000"),
+       .GSR("AUTO")
+) _TECHMAP_REPLACE_ (
+       .CLKA(PORT_W_CLK),
+       .WEA(PORT_W_WIDTH >= 9 ? 1'b1 : PORT_W_WR_EN[0]),
+       .CEA(PORT_W_CLK_EN),
+       .OCEA(1'b0),
+       .RSTA(1'b0),
+       .CSA0(1'b0),
+       .CSA1(1'b0),
+       .CSA2(1'b0),
+       .ADA0(PORT_W_WIDTH >= 9 ? PORT_W_WR_EN[0] : PORT_W_ADDR[0]),
+       .ADA1(PORT_W_WIDTH >= 18 ? PORT_W_WR_EN[1] : PORT_W_ADDR[1]),
+       .ADA2(PORT_W_ADDR[2]),
+       .ADA3(PORT_W_ADDR[3]),
+       .ADA4(PORT_W_ADDR[4]),
+       .ADA5(PORT_W_ADDR[5]),
+       .ADA6(PORT_W_ADDR[6]),
+       .ADA7(PORT_W_ADDR[7]),
+       .ADA8(PORT_W_ADDR[8]),
+       .ADA9(PORT_W_ADDR[9]),
+       .ADA10(PORT_W_ADDR[10]),
+       .ADA11(PORT_W_ADDR[11]),
+       .ADA12(PORT_W_ADDR[12]),
+       .DIA0(DI[0]),
+       .DIA1(DI[1]),
+       .DIA2(DI[2]),
+       .DIA3(DI[3]),
+       .DIA4(DI[4]),
+       .DIA5(DI[5]),
+       .DIA6(DI[6]),
+       .DIA7(DI[7]),
+       .DIA8(DI[8]),
+       .DIB0(DI[9]),
+       .DIB1(DI[10]),
+       .DIB2(DI[11]),
+       .DIB3(DI[12]),
+       .DIB4(DI[13]),
+       .DIB5(DI[14]),
+       .DIB6(DI[15]),
+       .DIB7(DI[16]),
+       .DIB8(DI[17]),
+
+       .CLKB(PORT_R_CLK),
+       .WEB(1'b0),
+       .CEB(PORT_R_CLK_EN),
+       .OCEB(1'b1),
+       .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
+       .CSB0(1'b0),
+       .CSB1(1'b0),
+       .CSB2(1'b0),
+       .ADB0(PORT_R_ADDR[0]),
+       .ADB1(PORT_R_ADDR[1]),
+       .ADB2(PORT_R_ADDR[2]),
+       .ADB3(PORT_R_ADDR[3]),
+       .ADB4(PORT_R_ADDR[4]),
+       .ADB5(PORT_R_ADDR[5]),
+       .ADB6(PORT_R_ADDR[6]),
+       .ADB7(PORT_R_ADDR[7]),
+       .ADB8(PORT_R_ADDR[8]),
+       .ADB9(PORT_R_ADDR[9]),
+       .ADB10(PORT_R_ADDR[10]),
+       .ADB11(PORT_R_ADDR[11]),
+       .ADB12(PORT_R_ADDR[12]),
+       .DOA0(DO[0]),
+       .DOA1(DO[1]),
+       .DOA2(DO[2]),
+       .DOA3(DO[3]),
+       .DOA4(DO[4]),
+       .DOA5(DO[5]),
+       .DOA6(DO[6]),
+       .DOA7(DO[7]),
+       .DOA8(DO[8]),
+       .DOB0(DO[9]),
+       .DOB1(DO[10]),
+       .DOB2(DO[11]),
+       .DOB3(DO[12]),
+       .DOB4(DO[13]),
+       .DOB5(DO[14]),
+       .DOB6(DO[15]),
+       .DOB7(DO[16]),
+       .DOB8(DO[17]),
+);
+
+endmodule
index dc68a3127d597079f424c77d215ab8aa5f3f644e..82c9d8c4b831f889b75aebdb2cf6822fae124806 100644 (file)
@@ -199,6 +199,127 @@ module DCMA (
 );
 endmodule
 
+(* abc9_box, lib_whitebox *)
+module DPR16X4C (
+               input [3:0] DI,
+               input WCK, WRE,
+               input [3:0] RAD,
+               input [3:0] WAD,
+               output [3:0] DO
+);
+       parameter INITVAL = "0x0000000000000000";
+
+       function [63:0] convert_initval;
+               input [143:0] hex_initval;
+               reg done;
+               reg [63:0] temp;
+               reg [7:0] char;
+               integer i;
+               begin
+                       done = 1'b0;
+                       temp = 0;
+                       for (i = 0; i < 16; i = i + 1) begin
+                               if (!done) begin
+                                       char = hex_initval[8*i +: 8];
+                                       if (char == "x") begin
+                                               done = 1'b1;
+                                       end else begin
+                                               if (char >= "0" && char <= "9")
+                                                       temp[4*i +: 4] = char - "0";
+                                               else if (char >= "A" && char <= "F")
+                                                       temp[4*i +: 4] = 10 + char - "A";
+                                               else if (char >= "a" && char <= "f")
+                                                       temp[4*i +: 4] = 10 + char - "a";
+                                       end
+                               end
+                       end
+                       convert_initval = temp;
+               end
+       endfunction
+
+       localparam conv_initval = convert_initval(INITVAL);
+
+       reg [3:0] ram[0:15];
+       integer i;
+       initial begin
+               for (i = 0; i < 15; i = i + 1) begin
+                       ram[i] <= conv_initval[4*i +: 4];
+               end
+       end
+
+       always @(posedge WCK)
+               if (WRE)
+                       ram[WAD] <= DI;
+
+       assign DO = ram[RAD];
+endmodule
+
+(* blackbox *)
+module DP8KC(
+  input DIA8, DIA7, DIA6, DIA5, DIA4, DIA3, DIA2, DIA1, DIA0,
+  input ADA12, ADA11, ADA10, ADA9, ADA8, ADA7, ADA6, ADA5, ADA4, ADA3, ADA2, ADA1, ADA0,
+  input CEA, OCEA, CLKA, WEA, RSTA,
+  input CSA2, CSA1, CSA0,
+  output DOA8, DOA7, DOA6, DOA5, DOA4, DOA3, DOA2, DOA1, DOA0,
+
+  input DIB8, DIB7, DIB6, DIB5, DIB4, DIB3, DIB2, DIB1, DIB0,
+  input ADB12, ADB11, ADB10, ADB9, ADB8, ADB7, ADB6, ADB5, ADB4, ADB3, ADB2, ADB1, ADB0,
+  input CEB, OCEB, CLKB, WEB, RSTB,
+  input CSB2, CSB1, CSB0,
+  output DOB8, DOB7, DOB6, DOB5, DOB4, DOB3, DOB2, DOB1, DOB0
+);
+       parameter DATA_WIDTH_A = 9;
+       parameter DATA_WIDTH_B = 9;
+
+       parameter REGMODE_A = "NOREG";
+       parameter REGMODE_B = "NOREG";
+
+       parameter RESETMODE = "SYNC";
+       parameter ASYNC_RESET_RELEASE = "SYNC";
+
+       parameter CSDECODE_A = "0b000";
+       parameter CSDECODE_B = "0b000";
+
+       parameter WRITEMODE_A = "NORMAL";
+       parameter WRITEMODE_B = "NORMAL";
+
+       parameter GSR = "ENABLED";
+       parameter INIT_DATA = "STATIC";
+
+       parameter INITVAL_00 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_01 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_02 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_03 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_04 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_05 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_06 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_07 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_08 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_09 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_0F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_10 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_11 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_12 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_13 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_14 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_15 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_16 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_17 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_18 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_19 = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1A = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1B = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1C = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1D = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1E = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+       parameter INITVAL_1F = "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000";
+endmodule
+
 // IO- "$__" cells for the iopadmap pass. These are temporary cells not meant
 // to be instantiated by the end user. They are required in this file for
 // attrmvcp to work.
diff --git a/techlibs/machxo2/lutrams.txt b/techlibs/machxo2/lutrams.txt
new file mode 100644 (file)
index 0000000..c6b0b6c
--- /dev/null
@@ -0,0 +1,12 @@
+ram distributed $__DPR16X4C_ {
+       abits 4;
+       width 4;
+       cost 4;
+       init no_undef;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
diff --git a/techlibs/machxo2/lutrams_map.v b/techlibs/machxo2/lutrams_map.v
new file mode 100644 (file)
index 0000000..b55253f
--- /dev/null
@@ -0,0 +1,23 @@
+module $__DPR16X4C_ (...);
+       parameter INIT = 64'b0;
+
+       input PORT_W_CLK;
+       input [3:0] PORT_W_ADDR;
+       input [3:0] PORT_W_WR_DATA;
+       input PORT_W_WR_EN;
+
+       input [3:0] PORT_R_ADDR;
+       output [3:0] PORT_R_RD_DATA;
+
+       DPR16X4C #(
+               .INITVAL($sformatf("0x%08x", INIT))
+       ) _TECHMAP_REPLACE_ (
+               .RAD(PORT_R_ADDR),
+               .DO(PORT_R_RD_DATA),
+
+               .WAD(PORT_W_ADDR),
+               .DI(PORT_W_WR_DATA),
+               .WCK(PORT_W_CLK),
+               .WRE(PORT_W_WR_EN)
+       );
+endmodule
index e86ec5aafbbc2314f0ba3c3972a29267629c8f14..dbd01bbfd4dd924f64444d104f732f42774e3af1 100644 (file)
@@ -57,6 +57,12 @@ struct SynthMachXO2Pass : public ScriptPass
                log("        from label is synonymous to 'begin', and empty to label is\n");
                log("        synonymous to the end of the command list.\n");
                log("\n");
+               log("    -nobram\n");
+               log("        do not use block RAM cells in output netlist\n");
+               log("\n");
+               log("    -nolutram\n");
+               log("        do not use LUT RAM cells in output netlist\n");
+               log("\n");
                log("    -noflatten\n");
                log("        do not flatten design before synthesis\n");
                log("\n");
@@ -74,7 +80,7 @@ struct SynthMachXO2Pass : public ScriptPass
        }
 
        string top_opt, blif_file, edif_file, json_file;
-       bool flatten, vpr, noiopad;
+       bool nobram, nolutram, flatten, vpr, noiopad;
 
        void clear_flags() override
        {
@@ -82,6 +88,8 @@ struct SynthMachXO2Pass : public ScriptPass
                blif_file = "";
                edif_file = "";
                json_file = "";
+               nobram = false;
+               nolutram = false;
                flatten = true;
                vpr = false;
                noiopad = false;
@@ -127,6 +135,14 @@ struct SynthMachXO2Pass : public ScriptPass
                                flatten = false;
                                continue;
                        }
+                       if (args[argidx] == "-nobram") {
+                               nobram = true;
+                               continue;
+                       }
+                       if (args[argidx] == "-nolutram") {
+                               nolutram = true;
+                               continue;
+                       }
                        if (args[argidx] == "-noiopad") {
                                noiopad = true;
                                continue;
@@ -173,6 +189,19 @@ struct SynthMachXO2Pass : public ScriptPass
                        run("synth -run coarse");
                }
 
+               if (check_label("map_ram"))
+               {
+                       std::string args = "";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (nolutram)
+                               args += " -no-auto-distributed";
+                       if (help_mode)
+                               args += " [-no-auto-block] [-no-auto-distributed]";
+                       run("memory_libmap -lib +/machxo2/lutrams.txt -lib +/machxo2/brams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
+                       run("techmap -map +/machxo2/lutrams_map.v -map +/machxo2/brams_map.v");
+               }
+
                if (check_label("fine"))
                {
                        run("memory_map");
index 9828d32c163565b7657cab753d54e860fc676d7a..8121d1d8a11886d04fedd6af28d0e4a4280ff577 100644 (file)
@@ -6,10 +6,8 @@ $(eval $(call add_share_file,share/nexus,techlibs/nexus/parse_init.vh))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/cells_xtra.v))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/lutrams_map.v))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/lutrams.txt))
-$(eval $(call add_share_file,share/nexus,techlibs/nexus/brams_init.vh))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams_map.v))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/brams.txt))
-$(eval $(call add_share_file,share/nexus,techlibs/nexus/lrams_init.vh))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/lrams_map.v))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/lrams.txt))
 $(eval $(call add_share_file,share/nexus,techlibs/nexus/arith_map.v))
index 086afe8bf97511728e7839353e64def7fe786071..975a8d227db3c53891570ecc7661e599a80b8511 100644 (file)
@@ -1,63 +1,47 @@
-bram $__NX_PDP16K
-  init 1
+ram block $__NX_DP16K_ {
+       abits 14;
+       widths 1 2 4 9 18 per_port;
+       byte 9;
+       cost 129;
+       init no_undef;
+       port srsw "A" "B" {
+               clock posedge;
+               clken;
+               wrbe_separate;
+               rdwr no_change;
+               portoption "RESETMODE" "SYNC" {
+                       rdsrst zero gated_clken;
+               }
+               portoption "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+}
 
-  abits 9 @a9d36
-  dbits 36 @a9d36
-  abits 10 @a10d18
-  dbits 18 @a10d18
-  abits 11 @a11d9
-  dbits 9  @a11d9
-  abits 12 @a12d4
-  dbits 4  @a12d4
-  abits 13 @a13d2
-  dbits 2  @a13d2
-  abits 14 @a14d1
-  dbits 1  @a14d1
-
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 4 1 @a9d36
-  enable 2 1 @a10d18
-  enable 1 1 @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__NX_PDP16K
-  # implicitly requested RAM or ROM
-  attribute !syn_ramstyle syn_ramstyle=auto
-  attribute !syn_romstyle syn_romstyle=auto
-  attribute !ram_block
-  attribute !rom_block
-  attribute !logic_block
-  min bits 2048
-  min efficiency 5
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__NX_PDP16K
-  # explicitly requested RAM
-  attribute syn_ramstyle=block_ram ram_block
-  attribute !syn_romstyle
-  attribute !rom_block
-  attribute !logic_block
-  min wports 1
-  shuffle_enable A
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__NX_PDP16K
-  # explicitly requested ROM
-  attribute syn_romstyle=ebr rom_block
-  attribute !syn_ramstyle
-  attribute !ram_block
-  attribute !logic_block
-  max wports 0
-  make_transp
-  shuffle_enable A
-endmatch
+ram block $__NX_PDP16K_ {
+       abits 14;
+       widths 1 2 4 9 18 36 per_port;
+       byte 9;
+       option "SAME_CLOCK" 1 cost 128;
+       option "SAME_CLOCK" 0 cost 129;
+       init no_undef;
+       port sr "R" {
+               option "SAME_CLOCK" 1 clock posedge "C";
+               option "SAME_CLOCK" 0 clock posedge;
+               clken;
+               portoption "RESETMODE" "SYNC" {
+                       rdsrst zero gated_clken;
+               }
+               portoption "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+       }
+       port sw "W" {
+               option "SAME_CLOCK" 1 clock posedge "C";
+               option "SAME_CLOCK" 0 clock posedge;
+               clken;
+               option "SAME_CLOCK" 1 wrtrans all old;
+       }
+}
diff --git a/techlibs/nexus/brams_init.vh b/techlibs/nexus/brams_init.vh
deleted file mode 100644 (file)
index 5b1d018..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-.INITVAL_00($sformatf("0x%080x", permute_init(INIT[0 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_01($sformatf("0x%080x", permute_init(INIT[1 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_02($sformatf("0x%080x", permute_init(INIT[2 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_03($sformatf("0x%080x", permute_init(INIT[3 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_04($sformatf("0x%080x", permute_init(INIT[4 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_05($sformatf("0x%080x", permute_init(INIT[5 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_06($sformatf("0x%080x", permute_init(INIT[6 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_07($sformatf("0x%080x", permute_init(INIT[7 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_08($sformatf("0x%080x", permute_init(INIT[8 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_09($sformatf("0x%080x", permute_init(INIT[9 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0A($sformatf("0x%080x", permute_init(INIT[10 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0B($sformatf("0x%080x", permute_init(INIT[11 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0C($sformatf("0x%080x", permute_init(INIT[12 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0D($sformatf("0x%080x", permute_init(INIT[13 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0E($sformatf("0x%080x", permute_init(INIT[14 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0F($sformatf("0x%080x", permute_init(INIT[15 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_10($sformatf("0x%080x", permute_init(INIT[16 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_11($sformatf("0x%080x", permute_init(INIT[17 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_12($sformatf("0x%080x", permute_init(INIT[18 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_13($sformatf("0x%080x", permute_init(INIT[19 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_14($sformatf("0x%080x", permute_init(INIT[20 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_15($sformatf("0x%080x", permute_init(INIT[21 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_16($sformatf("0x%080x", permute_init(INIT[22 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_17($sformatf("0x%080x", permute_init(INIT[23 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_18($sformatf("0x%080x", permute_init(INIT[24 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_19($sformatf("0x%080x", permute_init(INIT[25 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1A($sformatf("0x%080x", permute_init(INIT[26 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1B($sformatf("0x%080x", permute_init(INIT[27 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1C($sformatf("0x%080x", permute_init(INIT[28 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1D($sformatf("0x%080x", permute_init(INIT[29 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1E($sformatf("0x%080x", permute_init(INIT[30 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1F($sformatf("0x%080x", permute_init(INIT[31 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_20($sformatf("0x%080x", permute_init(INIT[32 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_21($sformatf("0x%080x", permute_init(INIT[33 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_22($sformatf("0x%080x", permute_init(INIT[34 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_23($sformatf("0x%080x", permute_init(INIT[35 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_24($sformatf("0x%080x", permute_init(INIT[36 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_25($sformatf("0x%080x", permute_init(INIT[37 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_26($sformatf("0x%080x", permute_init(INIT[38 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_27($sformatf("0x%080x", permute_init(INIT[39 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_28($sformatf("0x%080x", permute_init(INIT[40 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_29($sformatf("0x%080x", permute_init(INIT[41 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2A($sformatf("0x%080x", permute_init(INIT[42 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2B($sformatf("0x%080x", permute_init(INIT[43 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2C($sformatf("0x%080x", permute_init(INIT[44 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2D($sformatf("0x%080x", permute_init(INIT[45 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2E($sformatf("0x%080x", permute_init(INIT[46 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2F($sformatf("0x%080x", permute_init(INIT[47 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_30($sformatf("0x%080x", permute_init(INIT[48 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_31($sformatf("0x%080x", permute_init(INIT[49 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_32($sformatf("0x%080x", permute_init(INIT[50 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_33($sformatf("0x%080x", permute_init(INIT[51 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_34($sformatf("0x%080x", permute_init(INIT[52 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_35($sformatf("0x%080x", permute_init(INIT[53 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_36($sformatf("0x%080x", permute_init(INIT[54 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_37($sformatf("0x%080x", permute_init(INIT[55 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_38($sformatf("0x%080x", permute_init(INIT[56 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_39($sformatf("0x%080x", permute_init(INIT[57 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3A($sformatf("0x%080x", permute_init(INIT[58 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3B($sformatf("0x%080x", permute_init(INIT[59 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3C($sformatf("0x%080x", permute_init(INIT[60 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3D($sformatf("0x%080x", permute_init(INIT[61 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3E($sformatf("0x%080x", permute_init(INIT[62 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3F($sformatf("0x%080x", permute_init(INIT[63 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE])))
index 214da4326c288140e5bab3e14fc8fc1225d0c091..3cada24143550115d36e202be9ea0eb19a4ae96b 100644 (file)
-module \$__NX_PDP16K (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_A = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'b0;
-
-       parameter _TECHMAP_BITS_CONNMAP_ = 8;
-       parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_CLK2_ = 0;
-       parameter [_TECHMAP_BITS_CONNMAP_-1:0] _TECHMAP_CONNMAP_CLK3_ = 0;
-
-       input CLK2;
-       input CLK3;
-
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;
-       input [CFG_ENABLE_A-1:0] A1EN;
-
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
-
-       // Address is left justified, in x18 and above lower bits are byte enables
-       localparam A_SHIFT =
-               (CFG_DBITS == 36) ? 5 :
-               (CFG_DBITS == 18) ? 4 :
-               (CFG_DBITS == 9) ? 3 :
-               (CFG_DBITS == 4) ? 2 :
-               (CFG_DBITS == 2) ? 1 :
-               0;
-
-       // Different primitives needed for single vs dual clock case
-       localparam SINGLE_CLOCK = (_TECHMAP_CONNMAP_CLK2_ == _TECHMAP_CONNMAP_CLK3_);
-
-       localparam WIDTH = $sformatf("X%d", CFG_DBITS);
-
-       wire [13:0] ra, wa;
-       wire [35:0] rd, wd;
-
-       assign ra = {B1ADDR, {A_SHIFT{1'b1}}};
-
-       generate
-               if (CFG_ENABLE_A > 1)
-                       assign wa = {A1ADDR, {(A_SHIFT-CFG_ENABLE_A){1'b1}}, A1EN};
-               else
-                       assign wa = {A1ADDR, {A_SHIFT{1'b1}}};
-       endgenerate
-
-       assign wd = A1DATA;
-       assign B1DATA = rd[CFG_DBITS-1:0];
-
-       wire wck, rck;
-
-       generate
-               if (CLKPOL2)
-                       assign wck = CLK2;
-               else
-                       INV wck_inv_i (.A(CLK2), .Z(wck));
-               if (CLKPOL3)
-                       assign rck = CLK3;
-               else
-                       INV wck_inv_i (.A(CLK3), .Z(rck));
-       endgenerate
-
-       wire we = |A1EN;
-
-       localparam INIT_CHUNK_SIZE = (CFG_DBITS <= 4) ? 256 : 288;
-
-       function [319:0] permute_init;
-               input [INIT_CHUNK_SIZE-1:0] chunk;
-               integer i;
-               begin
-                       if (CFG_DBITS <= 4) begin
-                               for (i = 0; i < 32; i = i + 1'b1)
-                                       permute_init[i * 10 +: 10] = {2'b00, chunk[i * 8 +: 8]};
-                       end else begin
-                               for (i = 0; i < 32; i = i + 1'b1)
-                                       permute_init[i * 10 +: 10] = {1'b0, chunk[i * 9 +: 9]};
-                       end
-               end
-       endfunction
-
-       generate
-               if (SINGLE_CLOCK) begin
-                       PDPSC16K #(
-                               .DATA_WIDTH_W(WIDTH),
-                               .DATA_WIDTH_R(WIDTH),
-                               .OUTREG("BYPASSED"),
-                               .ECC("DISABLED"),
-                               .GSR("DISABLED"),
-`include "brams_init.vh"
-                       ) _TECHMAP_REPLACE_ (
-                               .CLK(wck), .RST(1'b0),
-                               .DI(wd), .ADW(wa), .CEW(we), .CSW(3'b111),
-                               .ADR(ra), .DO(rd), .CER(B1EN), .CSR(3'b111)
-                       );
-               end else begin
-                       PDP16K #(
-                               .DATA_WIDTH_W(WIDTH),
-                               .DATA_WIDTH_R(WIDTH),
-                               .OUTREG("BYPASSED"),
-                               .ECC("DISABLED"),
-                               .GSR("DISABLED"),
-`include "brams_init.vh"
-                       ) _TECHMAP_REPLACE_ (
-                               .CLKW(wck), .CLKR(rck), .RST(1'b0),
-                               .DI(wd), .ADW(wa), .CEW(we), .CSW(3'b111),
-                               .ADR(ra), .DO(rd), .CER(B1EN), .CSR(3'b111)
-                       );
-               end
-       endgenerate
+module $__NX_DP16K_ (...);
+
+parameter INIT = 0;
+
+parameter PORT_A_OPTION_RESETMODE = "SYNC";
+parameter PORT_A_WIDTH = 18;
+parameter PORT_A_WR_BE_WIDTH = 2;
+
+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_WR_BE_WIDTH-1:0] PORT_A_WR_BE;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+
+parameter PORT_B_OPTION_RESETMODE = "SYNC";
+parameter PORT_B_WIDTH = 18;
+parameter PORT_B_WR_BE_WIDTH = 2;
+
+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_B_WR_BE_WIDTH-1:0] PORT_B_WR_BE;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [17:0] DOA;
+wire [17:0] DOB;
+wire [17:0] DIA = PORT_A_WR_DATA;
+wire [17:0] DIB = PORT_B_WR_DATA;
+wire [13:0] ADA = PORT_A_WIDTH == 18 ? {PORT_A_ADDR[13:2], PORT_A_WR_BE} : PORT_A_ADDR;
+wire [13:0] ADB = PORT_B_WIDTH == 18 ? {PORT_B_ADDR[13:2], PORT_B_WR_BE} : PORT_B_ADDR;
+
+assign PORT_A_RD_DATA = DOA;
+assign PORT_B_RD_DATA = DOB;
+
+DP16K #(
+       .INITVAL_00($sformatf("0x%080x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%080x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%080x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%080x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%080x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%080x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%080x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%080x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%080x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%080x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%080x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%080x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%080x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%080x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%080x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%080x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%080x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%080x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%080x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%080x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%080x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%080x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%080x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%080x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%080x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%080x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%080x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%080x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%080x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%080x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%080x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%080x", init_slice('h1f))),
+       .INITVAL_20($sformatf("0x%080x", init_slice('h20))),
+       .INITVAL_21($sformatf("0x%080x", init_slice('h21))),
+       .INITVAL_22($sformatf("0x%080x", init_slice('h22))),
+       .INITVAL_23($sformatf("0x%080x", init_slice('h23))),
+       .INITVAL_24($sformatf("0x%080x", init_slice('h24))),
+       .INITVAL_25($sformatf("0x%080x", init_slice('h25))),
+       .INITVAL_26($sformatf("0x%080x", init_slice('h26))),
+       .INITVAL_27($sformatf("0x%080x", init_slice('h27))),
+       .INITVAL_28($sformatf("0x%080x", init_slice('h28))),
+       .INITVAL_29($sformatf("0x%080x", init_slice('h29))),
+       .INITVAL_2A($sformatf("0x%080x", init_slice('h2a))),
+       .INITVAL_2B($sformatf("0x%080x", init_slice('h2b))),
+       .INITVAL_2C($sformatf("0x%080x", init_slice('h2c))),
+       .INITVAL_2D($sformatf("0x%080x", init_slice('h2d))),
+       .INITVAL_2E($sformatf("0x%080x", init_slice('h2e))),
+       .INITVAL_2F($sformatf("0x%080x", init_slice('h2f))),
+       .INITVAL_30($sformatf("0x%080x", init_slice('h30))),
+       .INITVAL_31($sformatf("0x%080x", init_slice('h31))),
+       .INITVAL_32($sformatf("0x%080x", init_slice('h32))),
+       .INITVAL_33($sformatf("0x%080x", init_slice('h33))),
+       .INITVAL_34($sformatf("0x%080x", init_slice('h34))),
+       .INITVAL_35($sformatf("0x%080x", init_slice('h35))),
+       .INITVAL_36($sformatf("0x%080x", init_slice('h36))),
+       .INITVAL_37($sformatf("0x%080x", init_slice('h37))),
+       .INITVAL_38($sformatf("0x%080x", init_slice('h38))),
+       .INITVAL_39($sformatf("0x%080x", init_slice('h39))),
+       .INITVAL_3A($sformatf("0x%080x", init_slice('h3a))),
+       .INITVAL_3B($sformatf("0x%080x", init_slice('h3b))),
+       .INITVAL_3C($sformatf("0x%080x", init_slice('h3c))),
+       .INITVAL_3D($sformatf("0x%080x", init_slice('h3d))),
+       .INITVAL_3E($sformatf("0x%080x", init_slice('h3e))),
+       .INITVAL_3F($sformatf("0x%080x", init_slice('h3f))),
+       .DATA_WIDTH_A($sformatf("X%d", PORT_A_WIDTH)),
+       .DATA_WIDTH_B($sformatf("X%d", PORT_B_WIDTH)),
+       .OUTREG_A("BYPASSED"),
+       .OUTREG_B("BYPASSED"),
+       .RESETMODE_A(PORT_A_OPTION_RESETMODE),
+       .RESETMODE_B(PORT_B_OPTION_RESETMODE),
+       .ASYNC_RST_RELEASE_A(PORT_A_OPTION_RESETMODE),
+       .ASYNC_RST_RELEASE_B(PORT_B_OPTION_RESETMODE),
+       .CSDECODE_A("000"),
+       .CSDECODE_B("000"),
+       .GSR("DISABLED"),
+) _TECHMAP_REPLACE_ (
+       .CLKA(PORT_A_CLK),
+       .WEA(PORT_A_WIDTH == 18 ? PORT_A_WR_EN : (PORT_A_WR_EN | PORT_A_WR_BE[0])),
+       .CEA(PORT_A_CLK_EN),
+       .RSTA(PORT_A_OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+       .CSA(3'b111),
+       .DIA(DIA),
+       .DOA(DOA),
+       .ADA(ADA),
+
+       .CLKB(PORT_B_CLK),
+       .WEB(PORT_B_WIDTH == 18 ? PORT_B_WR_EN : (PORT_B_WR_EN | PORT_B_WR_BE[0])),
+       .CEB(PORT_B_CLK_EN),
+       .RSTB(PORT_B_OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+       .CSB(3'b111),
+       .ADB(ADB),
+       .DIB(DIB),
+       .DOB(DOB),
+);
+
+endmodule
+
+
+module $__NX_PDP16K_ (...);
+
+parameter INIT = 0;
+parameter OPTION_SAME_CLOCK = 1;
+
+parameter PORT_R_WIDTH = 36;
+parameter PORT_R_OPTION_RESETMODE = "SYNC";
+
+input CLK_C;
+
+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;
+
+parameter PORT_W_WIDTH = 36;
+parameter PORT_W_WR_EN_WIDTH = 4;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [13:0] PORT_W_ADDR;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+
+function [319:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 16; i = i + 1) begin
+               init_slice[i*20+:18] = INIT[(idx * 16 + i) * 18+:18];
+       end
+endfunction
+
+wire [35:0] DI = PORT_W_WR_DATA;
+wire [35:0] DO;
+
+assign PORT_R_RD_DATA = DO;
+
+wire [13:0] ADW = PORT_W_WIDTH == 36 ? {PORT_W_ADDR[13:4], PORT_W_WR_EN} :
+       (PORT_W_WIDTH == 18 ? {PORT_W_ADDR[13:2], PORT_W_WR_EN} : PORT_W_ADDR);
+
+generate
+
+if (OPTION_SAME_CLOCK) begin
+
+PDPSC16K #(
+       .INITVAL_00($sformatf("0x%080x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%080x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%080x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%080x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%080x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%080x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%080x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%080x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%080x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%080x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%080x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%080x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%080x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%080x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%080x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%080x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%080x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%080x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%080x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%080x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%080x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%080x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%080x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%080x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%080x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%080x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%080x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%080x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%080x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%080x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%080x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%080x", init_slice('h1f))),
+       .INITVAL_20($sformatf("0x%080x", init_slice('h20))),
+       .INITVAL_21($sformatf("0x%080x", init_slice('h21))),
+       .INITVAL_22($sformatf("0x%080x", init_slice('h22))),
+       .INITVAL_23($sformatf("0x%080x", init_slice('h23))),
+       .INITVAL_24($sformatf("0x%080x", init_slice('h24))),
+       .INITVAL_25($sformatf("0x%080x", init_slice('h25))),
+       .INITVAL_26($sformatf("0x%080x", init_slice('h26))),
+       .INITVAL_27($sformatf("0x%080x", init_slice('h27))),
+       .INITVAL_28($sformatf("0x%080x", init_slice('h28))),
+       .INITVAL_29($sformatf("0x%080x", init_slice('h29))),
+       .INITVAL_2A($sformatf("0x%080x", init_slice('h2a))),
+       .INITVAL_2B($sformatf("0x%080x", init_slice('h2b))),
+       .INITVAL_2C($sformatf("0x%080x", init_slice('h2c))),
+       .INITVAL_2D($sformatf("0x%080x", init_slice('h2d))),
+       .INITVAL_2E($sformatf("0x%080x", init_slice('h2e))),
+       .INITVAL_2F($sformatf("0x%080x", init_slice('h2f))),
+       .INITVAL_30($sformatf("0x%080x", init_slice('h30))),
+       .INITVAL_31($sformatf("0x%080x", init_slice('h31))),
+       .INITVAL_32($sformatf("0x%080x", init_slice('h32))),
+       .INITVAL_33($sformatf("0x%080x", init_slice('h33))),
+       .INITVAL_34($sformatf("0x%080x", init_slice('h34))),
+       .INITVAL_35($sformatf("0x%080x", init_slice('h35))),
+       .INITVAL_36($sformatf("0x%080x", init_slice('h36))),
+       .INITVAL_37($sformatf("0x%080x", init_slice('h37))),
+       .INITVAL_38($sformatf("0x%080x", init_slice('h38))),
+       .INITVAL_39($sformatf("0x%080x", init_slice('h39))),
+       .INITVAL_3A($sformatf("0x%080x", init_slice('h3a))),
+       .INITVAL_3B($sformatf("0x%080x", init_slice('h3b))),
+       .INITVAL_3C($sformatf("0x%080x", init_slice('h3c))),
+       .INITVAL_3D($sformatf("0x%080x", init_slice('h3d))),
+       .INITVAL_3E($sformatf("0x%080x", init_slice('h3e))),
+       .INITVAL_3F($sformatf("0x%080x", init_slice('h3f))),
+       .DATA_WIDTH_W($sformatf("X%d", PORT_W_WIDTH)),
+       .DATA_WIDTH_R($sformatf("X%d", PORT_R_WIDTH)),
+       .OUTREG("BYPASSED"),
+       .RESETMODE(PORT_R_OPTION_RESETMODE),
+       .ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE),
+       .CSDECODE_W("000"),
+       .CSDECODE_R("000"),
+       .ECC("DISABLED"),
+       .GSR("DISABLED"),
+) _TECHMAP_REPLACE_ (
+       .CLK(CLK_C),
+
+       .CEW(PORT_W_CLK_EN),
+       .CSW(3'b111),
+       .ADW(ADW),
+       .DI(DI),
+
+       .CER(PORT_R_CLK_EN),
+       .RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
+       .CSR(3'b111),
+       .ADR(PORT_R_ADDR),
+       .DO(DO),
+);
+
+end else begin
+
+PDP16K #(
+       .INITVAL_00($sformatf("0x%080x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%080x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%080x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%080x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%080x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%080x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%080x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%080x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%080x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%080x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%080x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%080x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%080x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%080x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%080x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%080x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%080x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%080x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%080x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%080x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%080x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%080x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%080x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%080x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%080x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%080x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%080x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%080x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%080x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%080x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%080x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%080x", init_slice('h1f))),
+       .INITVAL_20($sformatf("0x%080x", init_slice('h20))),
+       .INITVAL_21($sformatf("0x%080x", init_slice('h21))),
+       .INITVAL_22($sformatf("0x%080x", init_slice('h22))),
+       .INITVAL_23($sformatf("0x%080x", init_slice('h23))),
+       .INITVAL_24($sformatf("0x%080x", init_slice('h24))),
+       .INITVAL_25($sformatf("0x%080x", init_slice('h25))),
+       .INITVAL_26($sformatf("0x%080x", init_slice('h26))),
+       .INITVAL_27($sformatf("0x%080x", init_slice('h27))),
+       .INITVAL_28($sformatf("0x%080x", init_slice('h28))),
+       .INITVAL_29($sformatf("0x%080x", init_slice('h29))),
+       .INITVAL_2A($sformatf("0x%080x", init_slice('h2a))),
+       .INITVAL_2B($sformatf("0x%080x", init_slice('h2b))),
+       .INITVAL_2C($sformatf("0x%080x", init_slice('h2c))),
+       .INITVAL_2D($sformatf("0x%080x", init_slice('h2d))),
+       .INITVAL_2E($sformatf("0x%080x", init_slice('h2e))),
+       .INITVAL_2F($sformatf("0x%080x", init_slice('h2f))),
+       .INITVAL_30($sformatf("0x%080x", init_slice('h30))),
+       .INITVAL_31($sformatf("0x%080x", init_slice('h31))),
+       .INITVAL_32($sformatf("0x%080x", init_slice('h32))),
+       .INITVAL_33($sformatf("0x%080x", init_slice('h33))),
+       .INITVAL_34($sformatf("0x%080x", init_slice('h34))),
+       .INITVAL_35($sformatf("0x%080x", init_slice('h35))),
+       .INITVAL_36($sformatf("0x%080x", init_slice('h36))),
+       .INITVAL_37($sformatf("0x%080x", init_slice('h37))),
+       .INITVAL_38($sformatf("0x%080x", init_slice('h38))),
+       .INITVAL_39($sformatf("0x%080x", init_slice('h39))),
+       .INITVAL_3A($sformatf("0x%080x", init_slice('h3a))),
+       .INITVAL_3B($sformatf("0x%080x", init_slice('h3b))),
+       .INITVAL_3C($sformatf("0x%080x", init_slice('h3c))),
+       .INITVAL_3D($sformatf("0x%080x", init_slice('h3d))),
+       .INITVAL_3E($sformatf("0x%080x", init_slice('h3e))),
+       .INITVAL_3F($sformatf("0x%080x", init_slice('h3f))),
+       .DATA_WIDTH_W($sformatf("X%d", PORT_W_WIDTH)),
+       .DATA_WIDTH_R($sformatf("X%d", PORT_R_WIDTH)),
+       .OUTREG("BYPASSED"),
+       .RESETMODE(PORT_R_OPTION_RESETMODE),
+       .ASYNC_RST_RELEASE(PORT_R_OPTION_RESETMODE),
+       .CSDECODE_W("000"),
+       .CSDECODE_R("000"),
+       .ECC("DISABLED"),
+       .GSR("DISABLED"),
+) _TECHMAP_REPLACE_ (
+       .CLKW(PORT_W_CLK),
+       .CEW(PORT_W_CLK_EN),
+       .CSW(3'b111),
+       .ADW(ADW),
+       .DI(DI),
+
+       .CLKR(PORT_R_CLK),
+       .CER(PORT_R_CLK_EN),
+       .RST(PORT_R_OPTION_RESETMODE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST),
+       .CSR(3'b111),
+       .ADR(PORT_R_ADDR),
+       .DO(DO),
+);
+
+end
+
+endgenerate
 
 endmodule
index 481629b985f130609ee11ae5e4c059a99f12184d..ad2845783366a85ce74b796dd8d8513651c0f910 100644 (file)
@@ -1,22 +1,21 @@
-bram $__NX_PDPSC512K
-  init 1
-
-  abits 14
-  dbits 32
-
-  groups 2
-  ports 1 1
-  wrmode 1 0
-  enable 4 1
-  transp 0 0
-  clocks 2 2
-  clkpol 2 2
-endbram
-
-match $__NX_PDPSC512K
-  # explicitly requested LRAM only, due to limited availability and
-  # slower Fmax
-  attribute lram
-  shuffle_enable A
-  make_transp
-endmatch
+ram huge $__NX_DPSC512K_ {
+       abits 14;
+       width 32;
+       byte 8;
+       cost 2048;
+       init no_undef;
+       port srsw "A" "B" {
+               clock posedge "C";
+               clken;
+               wrbe_separate;
+               rdwr no_change;
+               option "RESETMODE" "SYNC" {
+                       rdsrst zero gated_clken;
+               }
+               option "RESETMODE" "ASYNC" {
+                       rdarst zero;
+               }
+               rdinit zero;
+               wrtrans all old;
+       }
+}
diff --git a/techlibs/nexus/lrams_init.vh b/techlibs/nexus/lrams_init.vh
deleted file mode 100644 (file)
index 31a7ba4..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-.INITVAL_00($sformatf("0x%05120x", permute_init(INIT[0 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_01($sformatf("0x%05120x", permute_init(INIT[1 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_02($sformatf("0x%05120x", permute_init(INIT[2 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_03($sformatf("0x%05120x", permute_init(INIT[3 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_04($sformatf("0x%05120x", permute_init(INIT[4 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_05($sformatf("0x%05120x", permute_init(INIT[5 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_06($sformatf("0x%05120x", permute_init(INIT[6 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_07($sformatf("0x%05120x", permute_init(INIT[7 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_08($sformatf("0x%05120x", permute_init(INIT[8 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_09($sformatf("0x%05120x", permute_init(INIT[9 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0A($sformatf("0x%05120x", permute_init(INIT[10 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0B($sformatf("0x%05120x", permute_init(INIT[11 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0C($sformatf("0x%05120x", permute_init(INIT[12 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0D($sformatf("0x%05120x", permute_init(INIT[13 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0E($sformatf("0x%05120x", permute_init(INIT[14 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_0F($sformatf("0x%05120x", permute_init(INIT[15 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_10($sformatf("0x%05120x", permute_init(INIT[16 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_11($sformatf("0x%05120x", permute_init(INIT[17 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_12($sformatf("0x%05120x", permute_init(INIT[18 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_13($sformatf("0x%05120x", permute_init(INIT[19 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_14($sformatf("0x%05120x", permute_init(INIT[20 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_15($sformatf("0x%05120x", permute_init(INIT[21 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_16($sformatf("0x%05120x", permute_init(INIT[22 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_17($sformatf("0x%05120x", permute_init(INIT[23 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_18($sformatf("0x%05120x", permute_init(INIT[24 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_19($sformatf("0x%05120x", permute_init(INIT[25 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1A($sformatf("0x%05120x", permute_init(INIT[26 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1B($sformatf("0x%05120x", permute_init(INIT[27 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1C($sformatf("0x%05120x", permute_init(INIT[28 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1D($sformatf("0x%05120x", permute_init(INIT[29 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1E($sformatf("0x%05120x", permute_init(INIT[30 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_1F($sformatf("0x%05120x", permute_init(INIT[31 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_20($sformatf("0x%05120x", permute_init(INIT[32 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_21($sformatf("0x%05120x", permute_init(INIT[33 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_22($sformatf("0x%05120x", permute_init(INIT[34 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_23($sformatf("0x%05120x", permute_init(INIT[35 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_24($sformatf("0x%05120x", permute_init(INIT[36 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_25($sformatf("0x%05120x", permute_init(INIT[37 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_26($sformatf("0x%05120x", permute_init(INIT[38 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_27($sformatf("0x%05120x", permute_init(INIT[39 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_28($sformatf("0x%05120x", permute_init(INIT[40 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_29($sformatf("0x%05120x", permute_init(INIT[41 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2A($sformatf("0x%05120x", permute_init(INIT[42 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2B($sformatf("0x%05120x", permute_init(INIT[43 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2C($sformatf("0x%05120x", permute_init(INIT[44 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2D($sformatf("0x%05120x", permute_init(INIT[45 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2E($sformatf("0x%05120x", permute_init(INIT[46 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_2F($sformatf("0x%05120x", permute_init(INIT[47 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_30($sformatf("0x%05120x", permute_init(INIT[48 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_31($sformatf("0x%05120x", permute_init(INIT[49 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_32($sformatf("0x%05120x", permute_init(INIT[50 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_33($sformatf("0x%05120x", permute_init(INIT[51 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_34($sformatf("0x%05120x", permute_init(INIT[52 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_35($sformatf("0x%05120x", permute_init(INIT[53 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_36($sformatf("0x%05120x", permute_init(INIT[54 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_37($sformatf("0x%05120x", permute_init(INIT[55 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_38($sformatf("0x%05120x", permute_init(INIT[56 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_39($sformatf("0x%05120x", permute_init(INIT[57 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3A($sformatf("0x%05120x", permute_init(INIT[58 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3B($sformatf("0x%05120x", permute_init(INIT[59 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3C($sformatf("0x%05120x", permute_init(INIT[60 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3D($sformatf("0x%05120x", permute_init(INIT[61 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3E($sformatf("0x%05120x", permute_init(INIT[62 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_3F($sformatf("0x%05120x", permute_init(INIT[63 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_40($sformatf("0x%05120x", permute_init(INIT[64 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_41($sformatf("0x%05120x", permute_init(INIT[65 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_42($sformatf("0x%05120x", permute_init(INIT[66 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_43($sformatf("0x%05120x", permute_init(INIT[67 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_44($sformatf("0x%05120x", permute_init(INIT[68 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_45($sformatf("0x%05120x", permute_init(INIT[69 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_46($sformatf("0x%05120x", permute_init(INIT[70 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_47($sformatf("0x%05120x", permute_init(INIT[71 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_48($sformatf("0x%05120x", permute_init(INIT[72 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_49($sformatf("0x%05120x", permute_init(INIT[73 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4A($sformatf("0x%05120x", permute_init(INIT[74 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4B($sformatf("0x%05120x", permute_init(INIT[75 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4C($sformatf("0x%05120x", permute_init(INIT[76 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4D($sformatf("0x%05120x", permute_init(INIT[77 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4E($sformatf("0x%05120x", permute_init(INIT[78 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_4F($sformatf("0x%05120x", permute_init(INIT[79 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_50($sformatf("0x%05120x", permute_init(INIT[80 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_51($sformatf("0x%05120x", permute_init(INIT[81 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_52($sformatf("0x%05120x", permute_init(INIT[82 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_53($sformatf("0x%05120x", permute_init(INIT[83 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_54($sformatf("0x%05120x", permute_init(INIT[84 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_55($sformatf("0x%05120x", permute_init(INIT[85 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_56($sformatf("0x%05120x", permute_init(INIT[86 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_57($sformatf("0x%05120x", permute_init(INIT[87 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_58($sformatf("0x%05120x", permute_init(INIT[88 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_59($sformatf("0x%05120x", permute_init(INIT[89 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5A($sformatf("0x%05120x", permute_init(INIT[90 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5B($sformatf("0x%05120x", permute_init(INIT[91 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5C($sformatf("0x%05120x", permute_init(INIT[92 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5D($sformatf("0x%05120x", permute_init(INIT[93 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5E($sformatf("0x%05120x", permute_init(INIT[94 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_5F($sformatf("0x%05120x", permute_init(INIT[95 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_60($sformatf("0x%05120x", permute_init(INIT[96 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_61($sformatf("0x%05120x", permute_init(INIT[97 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_62($sformatf("0x%05120x", permute_init(INIT[98 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_63($sformatf("0x%05120x", permute_init(INIT[99 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_64($sformatf("0x%05120x", permute_init(INIT[100 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_65($sformatf("0x%05120x", permute_init(INIT[101 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_66($sformatf("0x%05120x", permute_init(INIT[102 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_67($sformatf("0x%05120x", permute_init(INIT[103 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_68($sformatf("0x%05120x", permute_init(INIT[104 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_69($sformatf("0x%05120x", permute_init(INIT[105 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6A($sformatf("0x%05120x", permute_init(INIT[106 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6B($sformatf("0x%05120x", permute_init(INIT[107 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6C($sformatf("0x%05120x", permute_init(INIT[108 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6D($sformatf("0x%05120x", permute_init(INIT[109 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6E($sformatf("0x%05120x", permute_init(INIT[110 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_6F($sformatf("0x%05120x", permute_init(INIT[111 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_70($sformatf("0x%05120x", permute_init(INIT[112 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_71($sformatf("0x%05120x", permute_init(INIT[113 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_72($sformatf("0x%05120x", permute_init(INIT[114 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_73($sformatf("0x%05120x", permute_init(INIT[115 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_74($sformatf("0x%05120x", permute_init(INIT[116 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_75($sformatf("0x%05120x", permute_init(INIT[117 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_76($sformatf("0x%05120x", permute_init(INIT[118 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_77($sformatf("0x%05120x", permute_init(INIT[119 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_78($sformatf("0x%05120x", permute_init(INIT[120 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_79($sformatf("0x%05120x", permute_init(INIT[121 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7A($sformatf("0x%05120x", permute_init(INIT[122 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7B($sformatf("0x%05120x", permute_init(INIT[123 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7C($sformatf("0x%05120x", permute_init(INIT[124 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7D($sformatf("0x%05120x", permute_init(INIT[125 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7E($sformatf("0x%05120x", permute_init(INIT[126 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
-.INITVAL_7F($sformatf("0x%05120x", permute_init(INIT[127 * INIT_CHUNK_SIZE +: INIT_CHUNK_SIZE]))),
index 938a0e84345db2c737753eda501676ffa6c0916f..5db5ae8bf970cc9213031acfbd499a8bc32d3e38 100644 (file)
-module \$__NX_PDPSC512K (CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 14;
-       parameter CFG_DBITS = 32;
-       parameter CFG_ENABLE_A = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter [524287:0] INIT = 524287'b0;
-
-       input CLK2;
-
-       input [CFG_ABITS-1:0] A1ADDR;
-       input [CFG_DBITS-1:0] A1DATA;
-       input [CFG_ENABLE_A-1:0] A1EN;
-
-       input [CFG_ABITS-1:0] B1ADDR;
-       output [CFG_DBITS-1:0] B1DATA;
-       input B1EN;
-
-       wire clk;
-       wire [31:0] rd;
-       assign B1DATA = rd[CFG_DBITS-1:0];
-
-       generate
-               if (CLKPOL2)
-                       assign clk = CLK2;
-               else
-                       INV clk_inv_i (.A(CLK2), .Z(clk));
-       endgenerate
-
-       wire we = |A1EN;
-
-       localparam INIT_CHUNK_SIZE = 4096;
-
-       function [5119:0] permute_init;
-               input [INIT_CHUNK_SIZE-1:0] chunk;
-               integer i;
-               begin
-                       for (i = 0; i < 128; i = i + 1'b1)
-                               permute_init[i * 40 +: 40] = {8'b0, chunk[i * 32 +: 32]};
-               end
-       endfunction
-
-       generate
-               PDPSC512K #(
-                       .OUTREG("NO_REG"),
-                       .ECC_BYTE_SEL("BYTE_EN"),
-`include "lrams_init.vh"
-                       .GSR("DISABLED")
-               ) _TECHMAP_REPLACE_ (
-                       .CLK(clk), .RSTR(1'b0),
-                       .DI(A1DATA), .ADW(A1ADDR), .CEW(we), .WE(we), .CSW(1'b1),
-                       .ADR(B1ADDR), .DO(rd), .CER(B1EN), .CSR(1'b1),
-               );
-       endgenerate
+module $__NX_DPSC512K_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RESETMODE = "SYNC";
+
+input CLK_C;
+
+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 [3:0] PORT_A_WR_BE;
+input [31:0] PORT_A_WR_DATA;
+output [31: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 [3:0] PORT_B_WR_BE;
+input [31:0] PORT_B_WR_DATA;
+output [31:0] PORT_B_RD_DATA;
+
+function [5119:0] init_slice;
+       input integer idx;
+       integer i, j;
+       init_slice = 0;
+       for (i = 0; i < 128; i = i + 1) begin
+               init_slice[i*40+:32] = INIT[(idx * 128 + i) * 32+:32];
+       end
+endfunction
+
+DPSC512K #(
+       .INITVAL_00($sformatf("0x%01280x", init_slice('h00))),
+       .INITVAL_01($sformatf("0x%01280x", init_slice('h01))),
+       .INITVAL_02($sformatf("0x%01280x", init_slice('h02))),
+       .INITVAL_03($sformatf("0x%01280x", init_slice('h03))),
+       .INITVAL_04($sformatf("0x%01280x", init_slice('h04))),
+       .INITVAL_05($sformatf("0x%01280x", init_slice('h05))),
+       .INITVAL_06($sformatf("0x%01280x", init_slice('h06))),
+       .INITVAL_07($sformatf("0x%01280x", init_slice('h07))),
+       .INITVAL_08($sformatf("0x%01280x", init_slice('h08))),
+       .INITVAL_09($sformatf("0x%01280x", init_slice('h09))),
+       .INITVAL_0A($sformatf("0x%01280x", init_slice('h0a))),
+       .INITVAL_0B($sformatf("0x%01280x", init_slice('h0b))),
+       .INITVAL_0C($sformatf("0x%01280x", init_slice('h0c))),
+       .INITVAL_0D($sformatf("0x%01280x", init_slice('h0d))),
+       .INITVAL_0E($sformatf("0x%01280x", init_slice('h0e))),
+       .INITVAL_0F($sformatf("0x%01280x", init_slice('h0f))),
+       .INITVAL_10($sformatf("0x%01280x", init_slice('h10))),
+       .INITVAL_11($sformatf("0x%01280x", init_slice('h11))),
+       .INITVAL_12($sformatf("0x%01280x", init_slice('h12))),
+       .INITVAL_13($sformatf("0x%01280x", init_slice('h13))),
+       .INITVAL_14($sformatf("0x%01280x", init_slice('h14))),
+       .INITVAL_15($sformatf("0x%01280x", init_slice('h15))),
+       .INITVAL_16($sformatf("0x%01280x", init_slice('h16))),
+       .INITVAL_17($sformatf("0x%01280x", init_slice('h17))),
+       .INITVAL_18($sformatf("0x%01280x", init_slice('h18))),
+       .INITVAL_19($sformatf("0x%01280x", init_slice('h19))),
+       .INITVAL_1A($sformatf("0x%01280x", init_slice('h1a))),
+       .INITVAL_1B($sformatf("0x%01280x", init_slice('h1b))),
+       .INITVAL_1C($sformatf("0x%01280x", init_slice('h1c))),
+       .INITVAL_1D($sformatf("0x%01280x", init_slice('h1d))),
+       .INITVAL_1E($sformatf("0x%01280x", init_slice('h1e))),
+       .INITVAL_1F($sformatf("0x%01280x", init_slice('h1f))),
+       .INITVAL_20($sformatf("0x%01280x", init_slice('h20))),
+       .INITVAL_21($sformatf("0x%01280x", init_slice('h21))),
+       .INITVAL_22($sformatf("0x%01280x", init_slice('h22))),
+       .INITVAL_23($sformatf("0x%01280x", init_slice('h23))),
+       .INITVAL_24($sformatf("0x%01280x", init_slice('h24))),
+       .INITVAL_25($sformatf("0x%01280x", init_slice('h25))),
+       .INITVAL_26($sformatf("0x%01280x", init_slice('h26))),
+       .INITVAL_27($sformatf("0x%01280x", init_slice('h27))),
+       .INITVAL_28($sformatf("0x%01280x", init_slice('h28))),
+       .INITVAL_29($sformatf("0x%01280x", init_slice('h29))),
+       .INITVAL_2A($sformatf("0x%01280x", init_slice('h2a))),
+       .INITVAL_2B($sformatf("0x%01280x", init_slice('h2b))),
+       .INITVAL_2C($sformatf("0x%01280x", init_slice('h2c))),
+       .INITVAL_2D($sformatf("0x%01280x", init_slice('h2d))),
+       .INITVAL_2E($sformatf("0x%01280x", init_slice('h2e))),
+       .INITVAL_2F($sformatf("0x%01280x", init_slice('h2f))),
+       .INITVAL_30($sformatf("0x%01280x", init_slice('h30))),
+       .INITVAL_31($sformatf("0x%01280x", init_slice('h31))),
+       .INITVAL_32($sformatf("0x%01280x", init_slice('h32))),
+       .INITVAL_33($sformatf("0x%01280x", init_slice('h33))),
+       .INITVAL_34($sformatf("0x%01280x", init_slice('h34))),
+       .INITVAL_35($sformatf("0x%01280x", init_slice('h35))),
+       .INITVAL_36($sformatf("0x%01280x", init_slice('h36))),
+       .INITVAL_37($sformatf("0x%01280x", init_slice('h37))),
+       .INITVAL_38($sformatf("0x%01280x", init_slice('h38))),
+       .INITVAL_39($sformatf("0x%01280x", init_slice('h39))),
+       .INITVAL_3A($sformatf("0x%01280x", init_slice('h3a))),
+       .INITVAL_3B($sformatf("0x%01280x", init_slice('h3b))),
+       .INITVAL_3C($sformatf("0x%01280x", init_slice('h3c))),
+       .INITVAL_3D($sformatf("0x%01280x", init_slice('h3d))),
+       .INITVAL_3E($sformatf("0x%01280x", init_slice('h3e))),
+       .INITVAL_3F($sformatf("0x%01280x", init_slice('h3f))),
+       .INITVAL_40($sformatf("0x%01280x", init_slice('h40))),
+       .INITVAL_41($sformatf("0x%01280x", init_slice('h41))),
+       .INITVAL_42($sformatf("0x%01280x", init_slice('h42))),
+       .INITVAL_43($sformatf("0x%01280x", init_slice('h43))),
+       .INITVAL_44($sformatf("0x%01280x", init_slice('h44))),
+       .INITVAL_45($sformatf("0x%01280x", init_slice('h45))),
+       .INITVAL_46($sformatf("0x%01280x", init_slice('h46))),
+       .INITVAL_47($sformatf("0x%01280x", init_slice('h47))),
+       .INITVAL_48($sformatf("0x%01280x", init_slice('h48))),
+       .INITVAL_49($sformatf("0x%01280x", init_slice('h49))),
+       .INITVAL_4A($sformatf("0x%01280x", init_slice('h4a))),
+       .INITVAL_4B($sformatf("0x%01280x", init_slice('h4b))),
+       .INITVAL_4C($sformatf("0x%01280x", init_slice('h4c))),
+       .INITVAL_4D($sformatf("0x%01280x", init_slice('h4d))),
+       .INITVAL_4E($sformatf("0x%01280x", init_slice('h4e))),
+       .INITVAL_4F($sformatf("0x%01280x", init_slice('h4f))),
+       .INITVAL_50($sformatf("0x%01280x", init_slice('h50))),
+       .INITVAL_51($sformatf("0x%01280x", init_slice('h51))),
+       .INITVAL_52($sformatf("0x%01280x", init_slice('h52))),
+       .INITVAL_53($sformatf("0x%01280x", init_slice('h53))),
+       .INITVAL_54($sformatf("0x%01280x", init_slice('h54))),
+       .INITVAL_55($sformatf("0x%01280x", init_slice('h55))),
+       .INITVAL_56($sformatf("0x%01280x", init_slice('h56))),
+       .INITVAL_57($sformatf("0x%01280x", init_slice('h57))),
+       .INITVAL_58($sformatf("0x%01280x", init_slice('h58))),
+       .INITVAL_59($sformatf("0x%01280x", init_slice('h59))),
+       .INITVAL_5A($sformatf("0x%01280x", init_slice('h5a))),
+       .INITVAL_5B($sformatf("0x%01280x", init_slice('h5b))),
+       .INITVAL_5C($sformatf("0x%01280x", init_slice('h5c))),
+       .INITVAL_5D($sformatf("0x%01280x", init_slice('h5d))),
+       .INITVAL_5E($sformatf("0x%01280x", init_slice('h5e))),
+       .INITVAL_5F($sformatf("0x%01280x", init_slice('h5f))),
+       .INITVAL_60($sformatf("0x%01280x", init_slice('h60))),
+       .INITVAL_61($sformatf("0x%01280x", init_slice('h61))),
+       .INITVAL_62($sformatf("0x%01280x", init_slice('h62))),
+       .INITVAL_63($sformatf("0x%01280x", init_slice('h63))),
+       .INITVAL_64($sformatf("0x%01280x", init_slice('h64))),
+       .INITVAL_65($sformatf("0x%01280x", init_slice('h65))),
+       .INITVAL_66($sformatf("0x%01280x", init_slice('h66))),
+       .INITVAL_67($sformatf("0x%01280x", init_slice('h67))),
+       .INITVAL_68($sformatf("0x%01280x", init_slice('h68))),
+       .INITVAL_69($sformatf("0x%01280x", init_slice('h69))),
+       .INITVAL_6A($sformatf("0x%01280x", init_slice('h6a))),
+       .INITVAL_6B($sformatf("0x%01280x", init_slice('h6b))),
+       .INITVAL_6C($sformatf("0x%01280x", init_slice('h6c))),
+       .INITVAL_6D($sformatf("0x%01280x", init_slice('h6d))),
+       .INITVAL_6E($sformatf("0x%01280x", init_slice('h6e))),
+       .INITVAL_6F($sformatf("0x%01280x", init_slice('h6f))),
+       .INITVAL_70($sformatf("0x%01280x", init_slice('h70))),
+       .INITVAL_71($sformatf("0x%01280x", init_slice('h71))),
+       .INITVAL_72($sformatf("0x%01280x", init_slice('h72))),
+       .INITVAL_73($sformatf("0x%01280x", init_slice('h73))),
+       .INITVAL_74($sformatf("0x%01280x", init_slice('h74))),
+       .INITVAL_75($sformatf("0x%01280x", init_slice('h75))),
+       .INITVAL_76($sformatf("0x%01280x", init_slice('h76))),
+       .INITVAL_77($sformatf("0x%01280x", init_slice('h77))),
+       .INITVAL_78($sformatf("0x%01280x", init_slice('h78))),
+       .INITVAL_79($sformatf("0x%01280x", init_slice('h79))),
+       .INITVAL_7A($sformatf("0x%01280x", init_slice('h7a))),
+       .INITVAL_7B($sformatf("0x%01280x", init_slice('h7b))),
+       .INITVAL_7C($sformatf("0x%01280x", init_slice('h7c))),
+       .INITVAL_7D($sformatf("0x%01280x", init_slice('h7d))),
+       .INITVAL_7E($sformatf("0x%01280x", init_slice('h7e))),
+       .INITVAL_7F($sformatf("0x%01280x", init_slice('h7f))),
+       .OUTREG_A("NO_REG"),
+       .OUTREG_B("NO_REG"),
+       .ECC_BYTE_SEL("BYTE_EN"),
+       .GSR("DISABLED"),
+       .RESETMODE(OPTION_RESETMODE),
+       .ASYNC_RESET_RELEASE(OPTION_RESETMODE),
+) _TECHMAP_REPLACE_ (
+       .CLK(CLK_C),
+
+       .WEA(PORT_A_WR_EN),
+       .CEA(PORT_A_CLK_EN),
+       .RSTA(OPTION_RESETMODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+       .CSA(1'b1),
+       .ADA(PORT_A_ADDR),
+       .BENA_N(~PORT_A_WR_BE),
+       .DIA(PORT_A_WR_DATA),
+       .DOA(PORT_A_RD_DATA),
+
+       .WEB(PORT_B_WR_EN),
+       .CEB(PORT_B_CLK_EN),
+       .RSTB(OPTION_RESETMODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+       .CSB(1'b1),
+       .BENB_N(~PORT_B_WR_BE),
+       .ADB(PORT_B_ADDR),
+       .DIB(PORT_B_WR_DATA),
+       .DOB(PORT_B_RD_DATA),
+);
 
 endmodule
index 2568b99987ba8053a9f6d48d0964a140bf56618f..90e1e7bfd60a94f5cfa9748ece862ae5d997beb9 100644 (file)
@@ -1,26 +1,12 @@
-bram $__NEXUS_DPR16X4
-  init 1
-  abits 4
-  dbits 4
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-# The syn_* attributes are described in:
-# https://www.latticesemi.com/-/media/LatticeSemi/Documents/Tutorials/AK/LatticeDiamondTutorial311.ashx
-attr_icase 1
-
-match $__NEXUS_DPR16X4
-    attribute !syn_ramstyle syn_ramstyle=auto syn_ramstyle=distributed
-    attribute !syn_romstyle syn_romstyle=auto
-    attribute !ram_block
-    attribute !rom_block
-    attribute !logic_block
-  make_outreg
-  min wports 1
-endmatch
+ram distributed $__NEXUS_DPR16X4_ {
+       abits 4;
+       width 4;
+       cost 4;
+       init no_undef;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
index 0910664ce67529720d03f612ccd253c11a9b4f44..d12b490607ec6c079f336a6633d926b090cf2535 100644 (file)
@@ -1,34 +1,23 @@
-module \$__NEXUS_DPR16X4 (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0] INIT = 64'b0;
-       parameter CLKPOL2 = 1;
-       input CLK1;
+module $__NEXUS_DPR16X4_ (...);
+       parameter INIT = 64'b0;
 
-       input [3:0] A1ADDR;
-       output [3:0] A1DATA;
+       input PORT_W_CLK;
+       input [3:0] PORT_W_ADDR;
+       input [3:0] PORT_W_WR_DATA;
+       input PORT_W_WR_EN;
 
-       input [3:0] B1ADDR;
-       input [3:0] B1DATA;
-       input B1EN;
-
-
-       wire wck;
-
-       generate
-               if (CLKPOL2)
-                       assign wck = CLK1;
-               else
-                       INV wck_inv_i (.A(CLK1), .Z(wck));
-       endgenerate
+       input [3:0] PORT_R_ADDR;
+       output [3:0] PORT_R_RD_DATA;
 
        DPR16X4 #(
                .INITVAL($sformatf("0x%08x", INIT))
        ) _TECHMAP_REPLACE_ (
-               .RAD(A1ADDR),
-               .DO(A1DATA),
+               .RAD(PORT_R_ADDR),
+               .DO(PORT_R_RD_DATA),
 
-               .WAD(B1ADDR),
-               .DI(B1DATA),
-               .WCK(CLK1),
-               .WRE(B1EN)
+               .WAD(PORT_W_ADDR),
+               .DI(PORT_W_WR_DATA),
+               .WCK(PORT_W_CLK),
+               .WRE(PORT_W_WR_EN)
        );
 endmodule
index 03bff0649143ce41d8105b3b46cb7fb7f033f6ba..6fd15ba55773c22b597c353bbf17a419e090b806 100644 (file)
@@ -296,33 +296,24 @@ struct SynthNexusPass : public ScriptPass
                        run("opt_clean");
                }
 
-               if (!nolram && check_label("map_lram", "(skip if -nolram)"))
+               if (check_label("map_ram"))
                {
-                       run("memory_bram -rules +/nexus/lrams.txt");
-                       run("setundef -zero -params t:$__NX_PDPSC512K");
-                       run("techmap -map +/nexus/lrams_map.v");
-               }
-
-               if (!nobram && check_label("map_bram", "(skip if -nobram)"))
-               {
-                       run("memory_bram -rules +/nexus/brams.txt");
-                       run("setundef -zero -params t:$__NX_PDP16K");
-                       run("techmap -map +/nexus/brams_map.v");
-               }
-
-               if (!nolutram && check_label("map_lutram", "(skip if -nolutram)"))
-               {
-                       run("memory_bram -rules +/nexus/lutrams.txt");
-                       run("setundef -zero -params t:$__NEXUS_DPR16X4");
-                       run("techmap -map +/nexus/lutrams_map.v");
+                       std::string args = "";
+                       args += " -no-auto-huge";
+                       if (nobram)
+                               args += " -no-auto-block";
+                       if (nolutram)
+                               args += " -no-auto-distributed";
+                       if (help_mode)
+                               args += " [-no-auto-block] [-no-auto-distributed]";
+                       run("memory_libmap -lib +/nexus/lutrams.txt -lib +/nexus/brams.txt -lib +/nexus/lrams.txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)");
+                       run("techmap -map +/nexus/lutrams_map.v -map +/nexus/brams_map.v -map +/nexus/lrams_map.v");
                }
 
                if (check_label("map_ffram"))
                {
                        run("opt -fast -mux_undef -undriven -fine");
-                       run("memory_map -iattr -attr !ram_block -attr !rom_block -attr logic_block "
-                           "-attr syn_ramstyle=auto -attr syn_ramstyle=registers "
-                           "-attr syn_romstyle=auto -attr syn_romstyle=logic");
+                       run("memory_map");
                        run("opt -undriven -fine");
                }
 
diff --git a/techlibs/xilinx/.gitignore b/techlibs/xilinx/.gitignore
deleted file mode 100644 (file)
index d127107..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-brams_init.mk
-brams_init_*.vh
index ba87278de12ffd75ab8d4515372be72178216d96..2d3d0f63cd773babc77f94b92457df2cab7e7d29 100644 (file)
@@ -2,45 +2,37 @@
 OBJS += techlibs/xilinx/synth_xilinx.o
 OBJS += techlibs/xilinx/xilinx_dffopt.o
 
-GENFILES += techlibs/xilinx/brams_init_36.vh
-GENFILES += techlibs/xilinx/brams_init_32.vh
-GENFILES += techlibs/xilinx/brams_init_18.vh
-GENFILES += techlibs/xilinx/brams_init_16.vh
-GENFILES += techlibs/xilinx/brams_init_9.vh
-GENFILES += techlibs/xilinx/brams_init_8.vh
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v))
 
-EXTRA_OBJS += techlibs/xilinx/brams_init.mk
-.SECONDARY: techlibs/xilinx/brams_init.mk
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_xcv.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_xcv_map.v))
 
-techlibs/xilinx/brams_init.mk: techlibs/xilinx/brams_init.py
-       $(Q) mkdir -p techlibs/xilinx
-       $(P) $(PYTHON_EXECUTABLE) $<
-       $(Q) touch $@
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_xc5v.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_xcu.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_xc5v_map.v))
 
-techlibs/xilinx/brams_init_36.vh: techlibs/xilinx/brams_init.mk
-techlibs/xilinx/brams_init_32.vh: techlibs/xilinx/brams_init.mk
-techlibs/xilinx/brams_init_18.vh: techlibs/xilinx/brams_init.mk
-techlibs/xilinx/brams_init_16.vh: techlibs/xilinx/brams_init.mk
-techlibs/xilinx/brams_init_9.vh: techlibs/xilinx/brams_init.mk
-techlibs/xilinx/brams_init_8.vh: techlibs/xilinx/brams_init.mk
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xcv.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xcv_map.v))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_defs.vh))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc2v.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc2v_map.v))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc3sda.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc3sda_map.v))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc4v.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc4v_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc5v_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xc6v_map.v))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_xcu_map.v))
+
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/urams.txt))
+$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/urams_map.v))
 
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_sim.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/cells_xtra.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc2v_brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc2v_brams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3sa_brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc3sda_brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc6s_brams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_xcu_brams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_brams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_brams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcup_urams_map.v))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut4_lutrams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut6_lutrams.txt))
-$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lutrams_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v))
@@ -54,11 +46,3 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xc7_dsp_map.v))
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/xcu_dsp_map.v))
 
 $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/abc9_model.v))
-
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh))
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh))
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_18.vh))
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_16.vh))
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_9.vh))
-$(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_8.vh))
-
diff --git a/techlibs/xilinx/brams_defs.vh b/techlibs/xilinx/brams_defs.vh
new file mode 100644 (file)
index 0000000..69fe5d7
--- /dev/null
@@ -0,0 +1,561 @@
+`define PARAMS_INIT_9 \
+       .INIT_00(slice_init('h00)), \
+       .INIT_01(slice_init('h01)), \
+       .INIT_02(slice_init('h02)), \
+       .INIT_03(slice_init('h03)), \
+       .INIT_04(slice_init('h04)), \
+       .INIT_05(slice_init('h05)), \
+       .INIT_06(slice_init('h06)), \
+       .INIT_07(slice_init('h07)), \
+       .INIT_08(slice_init('h08)), \
+       .INIT_09(slice_init('h09)), \
+       .INIT_0A(slice_init('h0a)), \
+       .INIT_0B(slice_init('h0b)), \
+       .INIT_0C(slice_init('h0c)), \
+       .INIT_0D(slice_init('h0d)), \
+       .INIT_0E(slice_init('h0e)), \
+       .INIT_0F(slice_init('h0f)), \
+       .INIT_10(slice_init('h10)), \
+       .INIT_11(slice_init('h11)), \
+       .INIT_12(slice_init('h12)), \
+       .INIT_13(slice_init('h13)), \
+       .INIT_14(slice_init('h14)), \
+       .INIT_15(slice_init('h15)), \
+       .INIT_16(slice_init('h16)), \
+       .INIT_17(slice_init('h17)), \
+       .INIT_18(slice_init('h18)), \
+       .INIT_19(slice_init('h19)), \
+       .INIT_1A(slice_init('h1a)), \
+       .INIT_1B(slice_init('h1b)), \
+       .INIT_1C(slice_init('h1c)), \
+       .INIT_1D(slice_init('h1d)), \
+       .INIT_1E(slice_init('h1e)), \
+       .INIT_1F(slice_init('h1f)),
+
+`define PARAMS_INITP_9 \
+       .INITP_00(slice_initp('h00)), \
+       .INITP_01(slice_initp('h01)), \
+       .INITP_02(slice_initp('h02)), \
+       .INITP_03(slice_initp('h03)),
+
+`define PARAMS_INIT_18 \
+       .INIT_00(slice_init('h00)), \
+       .INIT_01(slice_init('h01)), \
+       .INIT_02(slice_init('h02)), \
+       .INIT_03(slice_init('h03)), \
+       .INIT_04(slice_init('h04)), \
+       .INIT_05(slice_init('h05)), \
+       .INIT_06(slice_init('h06)), \
+       .INIT_07(slice_init('h07)), \
+       .INIT_08(slice_init('h08)), \
+       .INIT_09(slice_init('h09)), \
+       .INIT_0A(slice_init('h0a)), \
+       .INIT_0B(slice_init('h0b)), \
+       .INIT_0C(slice_init('h0c)), \
+       .INIT_0D(slice_init('h0d)), \
+       .INIT_0E(slice_init('h0e)), \
+       .INIT_0F(slice_init('h0f)), \
+       .INIT_10(slice_init('h10)), \
+       .INIT_11(slice_init('h11)), \
+       .INIT_12(slice_init('h12)), \
+       .INIT_13(slice_init('h13)), \
+       .INIT_14(slice_init('h14)), \
+       .INIT_15(slice_init('h15)), \
+       .INIT_16(slice_init('h16)), \
+       .INIT_17(slice_init('h17)), \
+       .INIT_18(slice_init('h18)), \
+       .INIT_19(slice_init('h19)), \
+       .INIT_1A(slice_init('h1a)), \
+       .INIT_1B(slice_init('h1b)), \
+       .INIT_1C(slice_init('h1c)), \
+       .INIT_1D(slice_init('h1d)), \
+       .INIT_1E(slice_init('h1e)), \
+       .INIT_1F(slice_init('h1f)), \
+       .INIT_20(slice_init('h20)), \
+       .INIT_21(slice_init('h21)), \
+       .INIT_22(slice_init('h22)), \
+       .INIT_23(slice_init('h23)), \
+       .INIT_24(slice_init('h24)), \
+       .INIT_25(slice_init('h25)), \
+       .INIT_26(slice_init('h26)), \
+       .INIT_27(slice_init('h27)), \
+       .INIT_28(slice_init('h28)), \
+       .INIT_29(slice_init('h29)), \
+       .INIT_2A(slice_init('h2a)), \
+       .INIT_2B(slice_init('h2b)), \
+       .INIT_2C(slice_init('h2c)), \
+       .INIT_2D(slice_init('h2d)), \
+       .INIT_2E(slice_init('h2e)), \
+       .INIT_2F(slice_init('h2f)), \
+       .INIT_30(slice_init('h30)), \
+       .INIT_31(slice_init('h31)), \
+       .INIT_32(slice_init('h32)), \
+       .INIT_33(slice_init('h33)), \
+       .INIT_34(slice_init('h34)), \
+       .INIT_35(slice_init('h35)), \
+       .INIT_36(slice_init('h36)), \
+       .INIT_37(slice_init('h37)), \
+       .INIT_38(slice_init('h38)), \
+       .INIT_39(slice_init('h39)), \
+       .INIT_3A(slice_init('h3a)), \
+       .INIT_3B(slice_init('h3b)), \
+       .INIT_3C(slice_init('h3c)), \
+       .INIT_3D(slice_init('h3d)), \
+       .INIT_3E(slice_init('h3e)), \
+       .INIT_3F(slice_init('h3f)),
+
+`define PARAMS_INIT_18_U \
+       .INIT_00(slice_init('h40)), \
+       .INIT_01(slice_init('h41)), \
+       .INIT_02(slice_init('h42)), \
+       .INIT_03(slice_init('h43)), \
+       .INIT_04(slice_init('h44)), \
+       .INIT_05(slice_init('h45)), \
+       .INIT_06(slice_init('h46)), \
+       .INIT_07(slice_init('h47)), \
+       .INIT_08(slice_init('h48)), \
+       .INIT_09(slice_init('h49)), \
+       .INIT_0A(slice_init('h4a)), \
+       .INIT_0B(slice_init('h4b)), \
+       .INIT_0C(slice_init('h4c)), \
+       .INIT_0D(slice_init('h4d)), \
+       .INIT_0E(slice_init('h4e)), \
+       .INIT_0F(slice_init('h4f)), \
+       .INIT_10(slice_init('h50)), \
+       .INIT_11(slice_init('h51)), \
+       .INIT_12(slice_init('h52)), \
+       .INIT_13(slice_init('h53)), \
+       .INIT_14(slice_init('h54)), \
+       .INIT_15(slice_init('h55)), \
+       .INIT_16(slice_init('h56)), \
+       .INIT_17(slice_init('h57)), \
+       .INIT_18(slice_init('h58)), \
+       .INIT_19(slice_init('h59)), \
+       .INIT_1A(slice_init('h5a)), \
+       .INIT_1B(slice_init('h5b)), \
+       .INIT_1C(slice_init('h5c)), \
+       .INIT_1D(slice_init('h5d)), \
+       .INIT_1E(slice_init('h5e)), \
+       .INIT_1F(slice_init('h5f)), \
+       .INIT_20(slice_init('h60)), \
+       .INIT_21(slice_init('h61)), \
+       .INIT_22(slice_init('h62)), \
+       .INIT_23(slice_init('h63)), \
+       .INIT_24(slice_init('h64)), \
+       .INIT_25(slice_init('h65)), \
+       .INIT_26(slice_init('h66)), \
+       .INIT_27(slice_init('h67)), \
+       .INIT_28(slice_init('h68)), \
+       .INIT_29(slice_init('h69)), \
+       .INIT_2A(slice_init('h6a)), \
+       .INIT_2B(slice_init('h6b)), \
+       .INIT_2C(slice_init('h6c)), \
+       .INIT_2D(slice_init('h6d)), \
+       .INIT_2E(slice_init('h6e)), \
+       .INIT_2F(slice_init('h6f)), \
+       .INIT_30(slice_init('h70)), \
+       .INIT_31(slice_init('h71)), \
+       .INIT_32(slice_init('h72)), \
+       .INIT_33(slice_init('h73)), \
+       .INIT_34(slice_init('h74)), \
+       .INIT_35(slice_init('h75)), \
+       .INIT_36(slice_init('h76)), \
+       .INIT_37(slice_init('h77)), \
+       .INIT_38(slice_init('h78)), \
+       .INIT_39(slice_init('h79)), \
+       .INIT_3A(slice_init('h7a)), \
+       .INIT_3B(slice_init('h7b)), \
+       .INIT_3C(slice_init('h7c)), \
+       .INIT_3D(slice_init('h7d)), \
+       .INIT_3E(slice_init('h7e)), \
+       .INIT_3F(slice_init('h7f)),
+
+`define PARAMS_INITP_18 \
+       .INITP_00(slice_initp('h00)), \
+       .INITP_01(slice_initp('h01)), \
+       .INITP_02(slice_initp('h02)), \
+       .INITP_03(slice_initp('h03)), \
+       .INITP_04(slice_initp('h04)), \
+       .INITP_05(slice_initp('h05)), \
+       .INITP_06(slice_initp('h06)), \
+       .INITP_07(slice_initp('h07)),
+
+`define PARAMS_INIT_36 \
+       .INIT_00(slice_init('h00)), \
+       .INIT_01(slice_init('h01)), \
+       .INIT_02(slice_init('h02)), \
+       .INIT_03(slice_init('h03)), \
+       .INIT_04(slice_init('h04)), \
+       .INIT_05(slice_init('h05)), \
+       .INIT_06(slice_init('h06)), \
+       .INIT_07(slice_init('h07)), \
+       .INIT_08(slice_init('h08)), \
+       .INIT_09(slice_init('h09)), \
+       .INIT_0A(slice_init('h0a)), \
+       .INIT_0B(slice_init('h0b)), \
+       .INIT_0C(slice_init('h0c)), \
+       .INIT_0D(slice_init('h0d)), \
+       .INIT_0E(slice_init('h0e)), \
+       .INIT_0F(slice_init('h0f)), \
+       .INIT_10(slice_init('h10)), \
+       .INIT_11(slice_init('h11)), \
+       .INIT_12(slice_init('h12)), \
+       .INIT_13(slice_init('h13)), \
+       .INIT_14(slice_init('h14)), \
+       .INIT_15(slice_init('h15)), \
+       .INIT_16(slice_init('h16)), \
+       .INIT_17(slice_init('h17)), \
+       .INIT_18(slice_init('h18)), \
+       .INIT_19(slice_init('h19)), \
+       .INIT_1A(slice_init('h1a)), \
+       .INIT_1B(slice_init('h1b)), \
+       .INIT_1C(slice_init('h1c)), \
+       .INIT_1D(slice_init('h1d)), \
+       .INIT_1E(slice_init('h1e)), \
+       .INIT_1F(slice_init('h1f)), \
+       .INIT_20(slice_init('h20)), \
+       .INIT_21(slice_init('h21)), \
+       .INIT_22(slice_init('h22)), \
+       .INIT_23(slice_init('h23)), \
+       .INIT_24(slice_init('h24)), \
+       .INIT_25(slice_init('h25)), \
+       .INIT_26(slice_init('h26)), \
+       .INIT_27(slice_init('h27)), \
+       .INIT_28(slice_init('h28)), \
+       .INIT_29(slice_init('h29)), \
+       .INIT_2A(slice_init('h2a)), \
+       .INIT_2B(slice_init('h2b)), \
+       .INIT_2C(slice_init('h2c)), \
+       .INIT_2D(slice_init('h2d)), \
+       .INIT_2E(slice_init('h2e)), \
+       .INIT_2F(slice_init('h2f)), \
+       .INIT_30(slice_init('h30)), \
+       .INIT_31(slice_init('h31)), \
+       .INIT_32(slice_init('h32)), \
+       .INIT_33(slice_init('h33)), \
+       .INIT_34(slice_init('h34)), \
+       .INIT_35(slice_init('h35)), \
+       .INIT_36(slice_init('h36)), \
+       .INIT_37(slice_init('h37)), \
+       .INIT_38(slice_init('h38)), \
+       .INIT_39(slice_init('h39)), \
+       .INIT_3A(slice_init('h3a)), \
+       .INIT_3B(slice_init('h3b)), \
+       .INIT_3C(slice_init('h3c)), \
+       .INIT_3D(slice_init('h3d)), \
+       .INIT_3E(slice_init('h3e)), \
+       .INIT_3F(slice_init('h3f)), \
+       .INIT_40(slice_init('h40)), \
+       .INIT_41(slice_init('h41)), \
+       .INIT_42(slice_init('h42)), \
+       .INIT_43(slice_init('h43)), \
+       .INIT_44(slice_init('h44)), \
+       .INIT_45(slice_init('h45)), \
+       .INIT_46(slice_init('h46)), \
+       .INIT_47(slice_init('h47)), \
+       .INIT_48(slice_init('h48)), \
+       .INIT_49(slice_init('h49)), \
+       .INIT_4A(slice_init('h4a)), \
+       .INIT_4B(slice_init('h4b)), \
+       .INIT_4C(slice_init('h4c)), \
+       .INIT_4D(slice_init('h4d)), \
+       .INIT_4E(slice_init('h4e)), \
+       .INIT_4F(slice_init('h4f)), \
+       .INIT_50(slice_init('h50)), \
+       .INIT_51(slice_init('h51)), \
+       .INIT_52(slice_init('h52)), \
+       .INIT_53(slice_init('h53)), \
+       .INIT_54(slice_init('h54)), \
+       .INIT_55(slice_init('h55)), \
+       .INIT_56(slice_init('h56)), \
+       .INIT_57(slice_init('h57)), \
+       .INIT_58(slice_init('h58)), \
+       .INIT_59(slice_init('h59)), \
+       .INIT_5A(slice_init('h5a)), \
+       .INIT_5B(slice_init('h5b)), \
+       .INIT_5C(slice_init('h5c)), \
+       .INIT_5D(slice_init('h5d)), \
+       .INIT_5E(slice_init('h5e)), \
+       .INIT_5F(slice_init('h5f)), \
+       .INIT_60(slice_init('h60)), \
+       .INIT_61(slice_init('h61)), \
+       .INIT_62(slice_init('h62)), \
+       .INIT_63(slice_init('h63)), \
+       .INIT_64(slice_init('h64)), \
+       .INIT_65(slice_init('h65)), \
+       .INIT_66(slice_init('h66)), \
+       .INIT_67(slice_init('h67)), \
+       .INIT_68(slice_init('h68)), \
+       .INIT_69(slice_init('h69)), \
+       .INIT_6A(slice_init('h6a)), \
+       .INIT_6B(slice_init('h6b)), \
+       .INIT_6C(slice_init('h6c)), \
+       .INIT_6D(slice_init('h6d)), \
+       .INIT_6E(slice_init('h6e)), \
+       .INIT_6F(slice_init('h6f)), \
+       .INIT_70(slice_init('h70)), \
+       .INIT_71(slice_init('h71)), \
+       .INIT_72(slice_init('h72)), \
+       .INIT_73(slice_init('h73)), \
+       .INIT_74(slice_init('h74)), \
+       .INIT_75(slice_init('h75)), \
+       .INIT_76(slice_init('h76)), \
+       .INIT_77(slice_init('h77)), \
+       .INIT_78(slice_init('h78)), \
+       .INIT_79(slice_init('h79)), \
+       .INIT_7A(slice_init('h7a)), \
+       .INIT_7B(slice_init('h7b)), \
+       .INIT_7C(slice_init('h7c)), \
+       .INIT_7D(slice_init('h7d)), \
+       .INIT_7E(slice_init('h7e)), \
+       .INIT_7F(slice_init('h7f)),
+
+`define PARAMS_INIT_36_U \
+       .INIT_00(slice_init('h80)), \
+       .INIT_01(slice_init('h81)), \
+       .INIT_02(slice_init('h82)), \
+       .INIT_03(slice_init('h83)), \
+       .INIT_04(slice_init('h84)), \
+       .INIT_05(slice_init('h85)), \
+       .INIT_06(slice_init('h86)), \
+       .INIT_07(slice_init('h87)), \
+       .INIT_08(slice_init('h88)), \
+       .INIT_09(slice_init('h89)), \
+       .INIT_0A(slice_init('h8a)), \
+       .INIT_0B(slice_init('h8b)), \
+       .INIT_0C(slice_init('h8c)), \
+       .INIT_0D(slice_init('h8d)), \
+       .INIT_0E(slice_init('h8e)), \
+       .INIT_0F(slice_init('h8f)), \
+       .INIT_10(slice_init('h90)), \
+       .INIT_11(slice_init('h91)), \
+       .INIT_12(slice_init('h92)), \
+       .INIT_13(slice_init('h93)), \
+       .INIT_14(slice_init('h94)), \
+       .INIT_15(slice_init('h95)), \
+       .INIT_16(slice_init('h96)), \
+       .INIT_17(slice_init('h97)), \
+       .INIT_18(slice_init('h98)), \
+       .INIT_19(slice_init('h99)), \
+       .INIT_1A(slice_init('h9a)), \
+       .INIT_1B(slice_init('h9b)), \
+       .INIT_1C(slice_init('h9c)), \
+       .INIT_1D(slice_init('h9d)), \
+       .INIT_1E(slice_init('h9e)), \
+       .INIT_1F(slice_init('h9f)), \
+       .INIT_20(slice_init('ha0)), \
+       .INIT_21(slice_init('ha1)), \
+       .INIT_22(slice_init('ha2)), \
+       .INIT_23(slice_init('ha3)), \
+       .INIT_24(slice_init('ha4)), \
+       .INIT_25(slice_init('ha5)), \
+       .INIT_26(slice_init('ha6)), \
+       .INIT_27(slice_init('ha7)), \
+       .INIT_28(slice_init('ha8)), \
+       .INIT_29(slice_init('ha9)), \
+       .INIT_2A(slice_init('haa)), \
+       .INIT_2B(slice_init('hab)), \
+       .INIT_2C(slice_init('hac)), \
+       .INIT_2D(slice_init('had)), \
+       .INIT_2E(slice_init('hae)), \
+       .INIT_2F(slice_init('haf)), \
+       .INIT_30(slice_init('hb0)), \
+       .INIT_31(slice_init('hb1)), \
+       .INIT_32(slice_init('hb2)), \
+       .INIT_33(slice_init('hb3)), \
+       .INIT_34(slice_init('hb4)), \
+       .INIT_35(slice_init('hb5)), \
+       .INIT_36(slice_init('hb6)), \
+       .INIT_37(slice_init('hb7)), \
+       .INIT_38(slice_init('hb8)), \
+       .INIT_39(slice_init('hb9)), \
+       .INIT_3A(slice_init('hba)), \
+       .INIT_3B(slice_init('hbb)), \
+       .INIT_3C(slice_init('hbc)), \
+       .INIT_3D(slice_init('hbd)), \
+       .INIT_3E(slice_init('hbe)), \
+       .INIT_3F(slice_init('hbf)), \
+       .INIT_40(slice_init('hc0)), \
+       .INIT_41(slice_init('hc1)), \
+       .INIT_42(slice_init('hc2)), \
+       .INIT_43(slice_init('hc3)), \
+       .INIT_44(slice_init('hc4)), \
+       .INIT_45(slice_init('hc5)), \
+       .INIT_46(slice_init('hc6)), \
+       .INIT_47(slice_init('hc7)), \
+       .INIT_48(slice_init('hc8)), \
+       .INIT_49(slice_init('hc9)), \
+       .INIT_4A(slice_init('hca)), \
+       .INIT_4B(slice_init('hcb)), \
+       .INIT_4C(slice_init('hcc)), \
+       .INIT_4D(slice_init('hcd)), \
+       .INIT_4E(slice_init('hce)), \
+       .INIT_4F(slice_init('hcf)), \
+       .INIT_50(slice_init('hd0)), \
+       .INIT_51(slice_init('hd1)), \
+       .INIT_52(slice_init('hd2)), \
+       .INIT_53(slice_init('hd3)), \
+       .INIT_54(slice_init('hd4)), \
+       .INIT_55(slice_init('hd5)), \
+       .INIT_56(slice_init('hd6)), \
+       .INIT_57(slice_init('hd7)), \
+       .INIT_58(slice_init('hd8)), \
+       .INIT_59(slice_init('hd9)), \
+       .INIT_5A(slice_init('hda)), \
+       .INIT_5B(slice_init('hdb)), \
+       .INIT_5C(slice_init('hdc)), \
+       .INIT_5D(slice_init('hdd)), \
+       .INIT_5E(slice_init('hde)), \
+       .INIT_5F(slice_init('hdf)), \
+       .INIT_60(slice_init('he0)), \
+       .INIT_61(slice_init('he1)), \
+       .INIT_62(slice_init('he2)), \
+       .INIT_63(slice_init('he3)), \
+       .INIT_64(slice_init('he4)), \
+       .INIT_65(slice_init('he5)), \
+       .INIT_66(slice_init('he6)), \
+       .INIT_67(slice_init('he7)), \
+       .INIT_68(slice_init('he8)), \
+       .INIT_69(slice_init('he9)), \
+       .INIT_6A(slice_init('hea)), \
+       .INIT_6B(slice_init('heb)), \
+       .INIT_6C(slice_init('hec)), \
+       .INIT_6D(slice_init('hed)), \
+       .INIT_6E(slice_init('hee)), \
+       .INIT_6F(slice_init('hef)), \
+       .INIT_70(slice_init('hf0)), \
+       .INIT_71(slice_init('hf1)), \
+       .INIT_72(slice_init('hf2)), \
+       .INIT_73(slice_init('hf3)), \
+       .INIT_74(slice_init('hf4)), \
+       .INIT_75(slice_init('hf5)), \
+       .INIT_76(slice_init('hf6)), \
+       .INIT_77(slice_init('hf7)), \
+       .INIT_78(slice_init('hf8)), \
+       .INIT_79(slice_init('hf9)), \
+       .INIT_7A(slice_init('hfa)), \
+       .INIT_7B(slice_init('hfb)), \
+       .INIT_7C(slice_init('hfc)), \
+       .INIT_7D(slice_init('hfd)), \
+       .INIT_7E(slice_init('hfe)), \
+       .INIT_7F(slice_init('hff)),
+
+`define PARAMS_INITP_36 \
+       .INITP_00(slice_initp('h00)), \
+       .INITP_01(slice_initp('h01)), \
+       .INITP_02(slice_initp('h02)), \
+       .INITP_03(slice_initp('h03)), \
+       .INITP_04(slice_initp('h04)), \
+       .INITP_05(slice_initp('h05)), \
+       .INITP_06(slice_initp('h06)), \
+       .INITP_07(slice_initp('h07)), \
+       .INITP_08(slice_initp('h08)), \
+       .INITP_09(slice_initp('h09)), \
+       .INITP_0A(slice_initp('h0a)), \
+       .INITP_0B(slice_initp('h0b)), \
+       .INITP_0C(slice_initp('h0c)), \
+       .INITP_0D(slice_initp('h0d)), \
+       .INITP_0E(slice_initp('h0e)), \
+       .INITP_0F(slice_initp('h0f)),
+
+`define MAKE_DO(do, dop, rdata) \
+       wire [63:0] do; \
+       wire [7:0] dop; \
+       assign rdata = { \
+               dop[7], \
+               do[63:56], \
+               dop[6], \
+               do[55:48], \
+               dop[5], \
+               do[47:40], \
+               dop[4], \
+               do[39:32], \
+               dop[3], \
+               do[31:24], \
+               dop[2], \
+               do[23:16], \
+               dop[1], \
+               do[15:8], \
+               dop[0], \
+               do[7:0] \
+       };
+
+`define MAKE_DI(di, dip, wdata) \
+       wire [63:0] di; \
+       wire [7:0] dip; \
+       assign { \
+               dip[7], \
+               di[63:56], \
+               dip[6], \
+               di[55:48], \
+               dip[5], \
+               di[47:40], \
+               dip[4], \
+               di[39:32], \
+               dip[3], \
+               di[31:24], \
+               dip[2], \
+               di[23:16], \
+               dip[1], \
+               di[15:8], \
+               dip[0], \
+               di[7:0] \
+       } = wdata;
+
+function [71:0] ival;
+       input integer width;
+       input [71:0] val;
+       if (width == 72)
+               ival = {
+                       val[71],
+                       val[62],
+                       val[53],
+                       val[44],
+                       val[35],
+                       val[26],
+                       val[17],
+                       val[8],
+                       val[70:63],
+                       val[61:54],
+                       val[52:45],
+                       val[43:36],
+                       val[34:27],
+                       val[25:18],
+                       val[16:9],
+                       val[7:0]
+               };
+       else if (width == 36)
+               ival = {
+                       val[35],
+                       val[26],
+                       val[17],
+                       val[8],
+                       val[34:27],
+                       val[25:18],
+                       val[16:9],
+                       val[7:0]
+               };
+       else if (width == 18)
+               ival = {
+                       val[17],
+                       val[8],
+                       val[16:9],
+                       val[7:0]
+               };
+       else
+               ival = val;
+endfunction
+
+function [255:0] slice_init;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 32; i = i + 1)
+               slice_init[i*8+:8] = INIT[(idx * 32 + i)*9+:8];
+endfunction
+
+function [255:0] slice_initp;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 256; i = i + 1)
+               slice_initp[i] = INIT[(idx * 256 + i)*9+8];
+endfunction
diff --git a/techlibs/xilinx/brams_init.py b/techlibs/xilinx/brams_init.py
deleted file mode 100644 (file)
index 10057a0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-
-with open("techlibs/xilinx/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/xilinx/brams_init_18.vh", "w") as f:
-    for i in range(8):
-        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(64):
-        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/xilinx/brams_init_36.vh", "w") as f:
-    for i in range(16):
-        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(128):
-        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/xilinx/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/xilinx/brams_init_16.vh", "w") as f:
-    for i in range(64):
-        print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
-
-with open("techlibs/xilinx/brams_init_32.vh", "w") as f:
-    for i in range(128):
-        print(".INIT_%02X(INIT[%3d*256 +: 256])," % (i, i), file=f)
-
diff --git a/techlibs/xilinx/brams_xc2v.txt b/techlibs/xilinx/brams_xc2v.txt
new file mode 100644 (file)
index 0000000..562148c
--- /dev/null
@@ -0,0 +1,33 @@
+# Block RAMs for Virtex 2, Spartan 3, Spartan 3E, Spartan 3A(N)
+# The corresponding mapping file is brams_xc2v_map.v
+
+ram block $__XILINX_BLOCKRAM_ {
+       abits 14;
+       widths 1 2 4 9 18 36 per_port;
+       ifdef HAS_BE {
+               option "USE_BE" 1 byte 9;
+       }
+       cost 129;
+       init any;
+       port srsw "A" "B" {
+               option "USE_BE" 0 width tied;
+               ifdef HAS_BE {
+                       option "USE_BE" 1 width tied 9 18 36;
+               }
+               clock posedge;
+               clken;
+               rdsrst any gated_clken;
+               rdinit any;
+               portoption "WRITE_MODE" "NO_CHANGE" {
+                       rdwr no_change;
+               }
+               portoption "WRITE_MODE" "WRITE_FIRST" {
+                       rdwr new_only;
+               }
+               portoption "WRITE_MODE" "READ_FIRST" {
+                       rdwr old;
+                       wrtrans all old;
+               }
+               optional;
+       }
+}
diff --git a/techlibs/xilinx/brams_xc2v_map.v b/techlibs/xilinx/brams_xc2v_map.v
new file mode 100644 (file)
index 0000000..a82feff
--- /dev/null
@@ -0,0 +1,532 @@
+module $__XILINX_BLOCKRAM_ (...);
+
+parameter INIT = 0;
+parameter OPTION_USE_BE = 0;
+
+parameter PORT_A_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 0;
+
+parameter PORT_B_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [13:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [13:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_DP \
+       `PARAMS_INIT_18 \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .SRVAL_A(SRVAL_A), \
+       .SRVAL_B(SRVAL_B), \
+       .INIT_A(INIT_A), \
+       .INIT_B(INIT_B),
+
+`define PARAMS_DP_SWAP \
+       `PARAMS_INIT_18 \
+       .WRITE_MODE_A(PORT_B_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_A_OPTION_WRITE_MODE), \
+       .SRVAL_A(SRVAL_B), \
+       .SRVAL_B(SRVAL_A), \
+       .INIT_A(INIT_B), \
+       .INIT_B(INIT_A),
+
+`define PARAMS_SP \
+       `PARAMS_INIT_18 \
+       .WRITE_MODE(PORT_A_OPTION_WRITE_MODE), \
+       .SRVAL(SRVAL_A), \
+       .INIT(INIT_A),
+
+`define PORTS_DP(addr_slice_a, addr_slice_b) \
+       .CLKA(PORT_A_CLK), \
+       .ENA(PORT_A_CLK_EN), \
+       .WEA(PORT_A_WR_EN), \
+       .SSRA(PORT_A_RD_SRST), \
+       .ADDRA(PORT_A_ADDR addr_slice_a), \
+       .DOA(DO_A), \
+       .DIA(DI_A), \
+       .CLKB(PORT_B_CLK), \
+       .ENB(PORT_B_CLK_EN), \
+       .WEB(PORT_B_WR_EN), \
+       .SSRB(PORT_B_RD_SRST), \
+       .ADDRB(PORT_B_ADDR addr_slice_b), \
+       .DOB(DO_B), \
+       .DIB(DI_B),
+
+`define PORTS_DP_SWAP(addr_slice_a, addr_slice_b) \
+       .CLKB(PORT_A_CLK), \
+       .ENB(PORT_A_CLK_EN), \
+       .WEB(PORT_A_WR_EN), \
+       .SSRB(PORT_A_RD_SRST), \
+       .ADDRB(PORT_A_ADDR addr_slice_a), \
+       .DOB(DO_A), \
+       .DIB(DI_A), \
+       .CLKA(PORT_B_CLK), \
+       .ENA(PORT_B_CLK_EN), \
+       .WEA(PORT_B_WR_EN), \
+       .SSRA(PORT_B_RD_SRST), \
+       .ADDRA(PORT_B_ADDR addr_slice_b), \
+       .DOA(DO_B), \
+       .DIA(DI_B),
+
+`define PORTS_SP(addr_slice) \
+       .CLK(PORT_A_CLK), \
+       .EN(PORT_A_CLK_EN), \
+       .WE(PORT_A_WR_EN), \
+       .SSR(PORT_A_RD_SRST), \
+       .ADDR(PORT_A_ADDR addr_slice), \
+       .DO(DO_A), \
+       .DI(DI_A),
+
+localparam [PORT_A_WIDTH-1:0] SRVAL_A = ival(PORT_A_WIDTH, PORT_A_RD_SRST_VALUE);
+localparam [PORT_B_WIDTH-1:0] SRVAL_B = ival(PORT_B_WIDTH, PORT_B_RD_SRST_VALUE);
+localparam [PORT_A_WIDTH-1:0] INIT_A = ival(PORT_A_WIDTH, PORT_A_RD_INIT_VALUE);
+localparam [PORT_B_WIDTH-1:0] INIT_B = ival(PORT_B_WIDTH, PORT_B_RD_INIT_VALUE);
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+generate
+
+if (OPTION_USE_BE) begin
+       if (!PORT_B_USED) begin
+               case (PORT_A_WIDTH)
+               9: RAMB16_S9 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:3])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               18: RAMB16BWE_S18 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:4])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               36: RAMB16BWE_S36 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:5])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               endcase
+       end else begin
+               case (PORT_A_WIDTH)
+               9:      case(PORT_B_WIDTH)
+                       9: RAMB16_S9_S9 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:3])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       18: RAMB16BWE_S9_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:4])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16BWE_S9_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               18:     case(PORT_B_WIDTH)
+                       9: RAMB16BWE_S9_S18 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:4], [13:3])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       18: RAMB16BWE_S18_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:4], [13:4])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16BWE_S18_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:4], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               36:     case(PORT_B_WIDTH)
+                       9: RAMB16BWE_S9_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:3])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       18: RAMB16BWE_S18_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:4])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       36: RAMB16BWE_S36_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:5], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               endcase
+       end
+end else begin
+       if (!PORT_B_USED) begin
+               case (PORT_A_WIDTH)
+               1: RAMB16_S1 #(
+                       `PARAMS_SP
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:0])
+               );
+               2: RAMB16_S2 #(
+                       `PARAMS_SP
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:1])
+               );
+               4: RAMB16_S4 #(
+                       `PARAMS_SP
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:2])
+               );
+               9: RAMB16_S9 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:3])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               18: RAMB16_S18 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:4])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               36: RAMB16_S36 #(
+                       `PARAMS_SP
+                       `PARAMS_INITP_18
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_SP([13:5])
+                       .DIP(DIP_A),
+                       .DOP(DOP_A),
+               );
+               endcase
+       end else begin
+               case (PORT_A_WIDTH)
+               1:      case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S1 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:0])
+                       );
+                       2: RAMB16_S1_S2 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:1])
+                       );
+                       4: RAMB16_S1_S4 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:2])
+                       );
+                       9: RAMB16_S1_S9 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:3])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       18: RAMB16_S1_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:4])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16_S1_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:0], [13:5])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               2:      case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S2 #(
+                               `PARAMS_DP_SWAP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:1], [13:0])
+                       );
+                       2: RAMB16_S2_S2 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:1], [13:1])
+                       );
+                       4: RAMB16_S2_S4 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:1], [13:2])
+                       );
+                       9: RAMB16_S2_S9 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:1], [13:3])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       18: RAMB16_S2_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:1], [13:4])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16_S2_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:1], [13:5])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               4:      case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S4 #(
+                               `PARAMS_DP_SWAP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:2], [13:0])
+                       );
+                       2: RAMB16_S2_S4 #(
+                               `PARAMS_DP_SWAP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:2], [13:1])
+                       );
+                       4: RAMB16_S4_S4 #(
+                               `PARAMS_DP
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:2], [13:2])
+                       );
+                       9: RAMB16_S4_S9 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:2], [13:3])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       18: RAMB16_S4_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:2], [13:4])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16_S4_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:2], [13:5])
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               9:      case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S9 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:3], [13:0])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       2: RAMB16_S2_S9 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:3], [13:1])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       4: RAMB16_S4_S9 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:3], [13:2])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       9: RAMB16_S9_S9 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:3])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       18: RAMB16_S9_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:4])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16_S9_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:3], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               18:     case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S18 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:4], [13:0])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       2: RAMB16_S2_S18 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:4], [13:1])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       4: RAMB16_S4_S18 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:4], [13:2])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       9: RAMB16_S9_S18 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:4], [13:3])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       18: RAMB16_S18_S18 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:4], [13:4])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       36: RAMB16_S18_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:4], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               36:     case(PORT_B_WIDTH)
+                       1: RAMB16_S1_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:0])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       2: RAMB16_S2_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:1])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       4: RAMB16_S4_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:2])
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       9: RAMB16_S9_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:3])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       18: RAMB16_S18_S36 #(
+                               `PARAMS_DP_SWAP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP_SWAP([13:5], [13:4])
+                               .DIPA(DIP_B), .DOPA(DOP_B),
+                               .DIPB(DIP_A), .DOPB(DOP_A),
+                       );
+                       36: RAMB16_S36_S36 #(
+                               `PARAMS_DP
+                               `PARAMS_INITP_18
+                       ) _TECHMAP_REPLACE_ (
+                               `PORTS_DP([13:5], [13:5])
+                               .DIPA(DIP_A), .DOPA(DOP_A),
+                               .DIPB(DIP_B), .DOPB(DOP_B),
+                       );
+                       endcase
+               endcase
+       end
+end
+
+endgenerate
+
+
+endmodule
diff --git a/techlibs/xilinx/brams_xc3sda.txt b/techlibs/xilinx/brams_xc3sda.txt
new file mode 100644 (file)
index 0000000..4519991
--- /dev/null
@@ -0,0 +1,120 @@
+# Block RAMs for Spartan 3A DSP and Spartan 6.
+# The corresponding mapping file is brams_xc3sda_map.v
+
+ram block $__XILINX_BLOCKRAM_TDP_ {
+       byte 9;
+       ifdef IS_SPARTAN6 {
+               option "MODE" "HALF" {
+                       abits 13;
+                       widths 1 2 4 9 18 per_port;
+                       cost 65;
+               }
+       }
+       option "MODE" "FULL" {
+               abits 14;
+               widths 1 2 4 9 18 36 per_port;
+               cost 129;
+       }
+       init any;
+       port srsw "A" "B" {
+               # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+               ifdef IS_SPARTAN6 {
+                       option "HAS_RDFIRST" 1 {
+                               clock posedge "C";
+                       }
+                       option "HAS_RDFIRST" 0 {
+                               clock posedge;
+                       }
+               } else {
+                       clock posedge;
+               }
+               clken;
+               option "RSTTYPE" "SYNC" {
+                       portoption "RST_PRIORITY" "CE" {
+                               rdsrst any gated_clken;
+                       }
+                       ifdef IS_SPARTAN6 {
+                               portoption "RST_PRIORITY" "SR" {
+                                       rdsrst any ungated;
+                               }
+                       }
+               }
+               ifdef IS_SPARTAN6 {
+                       option "RSTTYPE" "ASYNC" {
+                               portoption "RST_PRIORITY" "SR" {
+                                       rdarst any;
+                               }
+                       }
+               }
+               rdinit any;
+               portoption "WRITE_MODE" "NO_CHANGE" {
+                       rdwr no_change;
+               }
+               portoption "WRITE_MODE" "WRITE_FIRST" {
+                       rdwr new;
+               }
+               ifdef IS_SPARTAN6 {
+                       option "HAS_RDFIRST" 1 {
+                               portoption "WRITE_MODE" "READ_FIRST" {
+                                       rdwr old;
+                                       wrtrans all old;
+                               }
+                       }
+               } else {
+                       portoption "WRITE_MODE" "READ_FIRST" {
+                               rdwr old;
+                               wrtrans all old;
+                       }
+               }
+               optional;
+       }
+}
+
+ifdef IS_SPARTAN6 {
+       ram block $__XILINX_BLOCKRAM_SDP_ {
+               byte 9;
+               abits 13;
+               widths 1 2 4 9 18 36 per_port;
+               cost 65;
+               init any;
+               port sw "W" {
+                       width 36;
+                       # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+                       option "WRITE_MODE" "READ_FIRST" {
+                               clock posedge "C";
+                               wrtrans all old;
+                       }
+                       option "WRITE_MODE" "WRITE_FIRST" {
+                               clock posedge;
+                       }
+                       clken;
+                       optional;
+               }
+               port sr "R" {
+                       width 36;
+                       # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+                       option "WRITE_MODE" "READ_FIRST" {
+                               clock posedge "C";
+                       }
+                       option "WRITE_MODE" "WRITE_FIRST" {
+                               clock posedge;
+                       }
+                       clken;
+                       option "RSTTYPE" "SYNC" {
+                               portoption "RST_PRIORITY" "CE" {
+                                       rdsrst any gated_clken;
+                               }
+                               portoption "RST_PRIORITY" "SR" {
+                                       rdsrst any ungated;
+                               }
+                       }
+                       option "RSTTYPE" "ASYNC" {
+                               portoption "RST_PRIORITY" "SR" {
+                                       rdarst any;
+                               }
+                       }
+                       rdinit any;
+                       optional;
+               }
+       }
+}
diff --git a/techlibs/xilinx/brams_xc3sda_map.v b/techlibs/xilinx/brams_xc3sda_map.v
new file mode 100644 (file)
index 0000000..f5f0e5a
--- /dev/null
@@ -0,0 +1,224 @@
+module $__XILINX_BLOCKRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_RSTTYPE = "SYNC";
+parameter OPTION_HAS_RDFIRST = 0;
+
+parameter PORT_A_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 0;
+parameter PORT_A_RD_ARST_VALUE = 0;
+parameter PORT_A_OPTION_RST_PRIORITY = "CE";
+
+parameter PORT_B_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+parameter PORT_B_RD_ARST_VALUE = 0;
+parameter PORT_B_OPTION_RST_PRIORITY = "CE";
+
+input CLK_C;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [13:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+input PORT_A_RD_ARST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [13:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+input PORT_B_RD_ARST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .DATA_WIDTH_A(PORT_A_USED ? PORT_A_WIDTH : 0), \
+       .DATA_WIDTH_B(PORT_B_USED ? PORT_B_WIDTH : 0), \
+       .EN_RSTRAM_A("TRUE"), \
+       .EN_RSTRAM_B("TRUE"), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .RST_PRIORITY_A(PORT_A_OPTION_RST_PRIORITY), \
+       .RST_PRIORITY_B(PORT_B_OPTION_RST_PRIORITY), \
+       .RSTTYPE(OPTION_RSTTYPE), \
+       .INIT_A(ival(PORT_A_WIDTH, PORT_A_RD_INIT_VALUE)), \
+       .INIT_B(ival(PORT_B_WIDTH, PORT_B_RD_INIT_VALUE)), \
+       .SRVAL_A(ival(PORT_A_WIDTH, OPTION_RSTTYPE == "SYNC" ? PORT_A_RD_SRST_VALUE : PORT_A_RD_ARST_VALUE)), \
+       .SRVAL_B(ival(PORT_B_WIDTH, OPTION_RSTTYPE == "SYNC" ? PORT_B_RD_SRST_VALUE : PORT_B_RD_ARST_VALUE)),
+
+wire RST_A = OPTION_RSTTYPE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST;
+wire RST_B = OPTION_RSTTYPE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST;
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+generate
+
+if (OPTION_MODE == "FULL") begin
+       wire [3:0] WE_A = {4{PORT_A_WR_EN}};
+       wire [3:0] WE_B = {4{PORT_B_WR_EN}};
+       RAMB16BWER #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               .DOA(DO_A),
+               .DOPA(DOP_A),
+               .DIA(DI_A),
+               .DIPA(DIP_A),
+               .DOB(DO_B),
+               .DOPB(DOP_B),
+               .DIB(DI_B),
+               .DIPB(DIP_B),
+               .ADDRA(PORT_A_ADDR),
+               .ADDRB(PORT_B_ADDR),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .RSTA(RST_A),
+               .RSTB(RST_B),
+               .WEA(WE_A),
+               .WEB(WE_B),
+       );
+end else begin
+       wire [1:0] WE_A = {2{PORT_A_WR_EN}};
+       wire [1:0] WE_B = {2{PORT_B_WR_EN}};
+       RAMB8BWER #(
+               `PARAMS_INIT_9
+               `PARAMS_INITP_9
+               `PARAMS_COMMON
+               .RAM_MODE("TDP"),
+       ) _TECHMAP_REPLACE_ (
+               .DOADO(DO_A),
+               .DOPADOP(DOP_A),
+               .DIADI(DI_A),
+               .DIPADIP(DIP_A),
+               .DOBDO(DO_B),
+               .DOPBDOP(DOP_B),
+               .DIBDI(DI_B),
+               .DIPBDIP(DIP_B),
+               .ADDRAWRADDR(PORT_A_ADDR),
+               .ADDRBRDADDR(PORT_B_ADDR),
+               .CLKAWRCLK(PORT_A_CLK),
+               .CLKBRDCLK(PORT_B_CLK),
+               .ENAWREN(PORT_A_CLK_EN),
+               .ENBRDEN(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEBREGCE(1'b0),
+               .RSTA(RST_A),
+               .RSTBRST(RST_B),
+               .WEAWEL(WE_A),
+               .WEBWEU(WE_B),
+       );
+end
+
+endgenerate
+
+endmodule
+
+
+module $__XILINX_BLOCKRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_RSTTYPE = "SYNC";
+parameter OPTION_WRITE_MODE = "READ_FIRST";
+
+parameter PORT_W_WIDTH = 1;
+parameter PORT_W_WR_EN_WIDTH = 1;
+parameter PORT_W_USED = 1;
+
+parameter PORT_R_WIDTH = 1;
+parameter PORT_R_USED = 0;
+parameter PORT_R_RD_INIT_VALUE = 0;
+parameter PORT_R_RD_SRST_VALUE = 0;
+parameter PORT_R_RD_ARST_VALUE = 0;
+parameter PORT_R_OPTION_RST_PRIORITY = "CE";
+
+input CLK_C;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [13:0] PORT_W_ADDR;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input [13:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+input PORT_R_RD_SRST;
+input PORT_R_RD_ARST;
+
+`include "brams_defs.vh"
+
+wire RST = OPTION_RSTTYPE == "SYNC" ? PORT_R_RD_SRST : PORT_R_RD_ARST;
+
+`MAKE_DI(DI, DIP, PORT_W_WR_DATA)
+`MAKE_DO(DO, DOP, PORT_R_RD_DATA)
+
+localparam [35:0] RST_VALUE = OPTION_RSTTYPE == "SYNC" ? PORT_R_RD_SRST_VALUE : PORT_R_RD_ARST_VALUE;
+
+RAMB8BWER #(
+       `PARAMS_INIT_9
+       `PARAMS_INITP_9
+       .WRITE_MODE_A(OPTION_WRITE_MODE),
+       .WRITE_MODE_B(OPTION_WRITE_MODE),
+       .DATA_WIDTH_A(PORT_W_USED ? PORT_W_WIDTH : 0),
+       .DATA_WIDTH_B(PORT_R_USED ? PORT_R_WIDTH : 0),
+       .EN_RSTRAM_A("TRUE"),
+       .EN_RSTRAM_B("TRUE"),
+       .DOA_REG(0),
+       .DOB_REG(0),
+       .RST_PRIORITY_A("CE"),
+       .RST_PRIORITY_B(PORT_R_OPTION_RST_PRIORITY),
+       .RSTTYPE(OPTION_RSTTYPE),
+       .INIT_A(ival(18, PORT_R_RD_INIT_VALUE[17:0])),
+       .INIT_B(ival(18, PORT_R_RD_INIT_VALUE[35:18])),
+       .SRVAL_A(ival(18, RST_VALUE[17:0])),
+       .SRVAL_B(ival(18, RST_VALUE[35:18])),
+       .RAM_MODE("SDP"),
+) _TECHMAP_REPLACE_ (
+       .DOADO(DO[15:0]),
+       .DOPADOP(DOP[1:0]),
+       .DIADI(DI[15:0]),
+       .DIPADIP(DIP[1:0]),
+       .DOBDO(DO[31:16]),
+       .DOPBDOP(DOP[3:2]),
+       .DIBDI(DI[31:16]),
+       .DIPBDIP(DIP[3:2]),
+       .ADDRAWRADDR(PORT_W_ADDR),
+       .ADDRBRDADDR(PORT_R_ADDR),
+       .CLKAWRCLK(PORT_W_CLK),
+       .CLKBRDCLK(PORT_R_CLK),
+       .ENAWREN(PORT_W_CLK_EN),
+       .ENBRDEN(PORT_R_CLK_EN),
+       .REGCEA(1'b0),
+       .REGCEBREGCE(1'b0),
+       .RSTA(1'b0),
+       .RSTBRST(RST),
+       .WEAWEL(PORT_W_WR_EN[1:0]),
+       .WEBWEU(PORT_W_WR_EN[3:2]),
+);
+
+endmodule
diff --git a/techlibs/xilinx/brams_xc4v.txt b/techlibs/xilinx/brams_xc4v.txt
new file mode 100644 (file)
index 0000000..2301835
--- /dev/null
@@ -0,0 +1,169 @@
+# Block RAMs for Virtex 4+.
+# The corresponding mapping files are:
+# - brams_xc3sda_map.v: Spartan 3A DSP, Spartan 6
+# - brams_xc4v_map.v: Virtex 4
+# - brams_xc5v_map.v: Virtex 5
+# - brams_xc6v_map.v: Virtex 6, Series 7
+# - brams_xcu_map.v: Ultrascale
+
+ram block $__XILINX_BLOCKRAM_TDP_ {
+       byte 9;
+       ifdef HAS_SIZE_36 {
+               option "MODE" "HALF" {
+                       abits 14;
+                       widths 1 2 4 9 18 per_port;
+                       cost 129;
+               }
+               option "MODE" "FULL" {
+                       abits 15;
+                       widths 1 2 4 9 18 36 per_port;
+                       cost 257;
+               }
+               ifdef HAS_CASCADE {
+                       option "MODE" "CASCADE" {
+                               abits 16;
+                               # hack to enforce same INIT layout as in the other modes
+                               widths 1 2 4 9 per_port;
+                               cost 513;
+                       }
+               }
+       } else {
+               option "MODE" "FULL" {
+                       abits 14;
+                       widths 1 2 4 9 18 36 per_port;
+                       cost 129;
+               }
+               ifdef HAS_CASCADE {
+                       option "MODE" "CASCADE" {
+                               abits 15;
+                               widths 1 2 4 9 per_port;
+                               cost 257;
+                       }
+               }
+       }
+       init any;
+       port srsw "A" "B" {
+               option "MODE" "HALF" {
+                       width mix;
+               }
+               option "MODE" "FULL" {
+                       width mix;
+               }
+               option "MODE" "CASCADE" {
+                       width mix 1;
+               }
+               ifdef HAS_ADDRCE {
+                       # TODO
+                       # addrce;
+               }
+               # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+               ifdef HAS_CONFLICT_BUG {
+                       option "HAS_RDFIRST" 1 {
+                               clock posedge "C";
+                       }
+                       option "HAS_RDFIRST" 0 {
+                               clock posedge;
+                       }
+               } else {
+                       clock posedge;
+               }
+               clken;
+               rdsrst any gated_clken;
+               rdinit any;
+               portoption "WRITE_MODE" "NO_CHANGE" {
+                       rdwr no_change;
+                       option "MODE" "CASCADE" {
+                               forbid;
+                       }
+               }
+               portoption "WRITE_MODE" "WRITE_FIRST" {
+                       ifdef HAS_SIZE_36 {
+                               rdwr new;
+                       } else {
+                               rdwr new_only;
+                       }
+               }
+               ifdef HAS_CONFLICT_BUG {
+                       option "HAS_RDFIRST" 1 {
+                               portoption "WRITE_MODE" "READ_FIRST" {
+                                       rdwr old;
+                                       wrtrans all old;
+                               }
+                       }
+               } else {
+                       portoption "WRITE_MODE" "READ_FIRST" {
+                               rdwr old;
+                               wrtrans all old;
+                       }
+               }
+               optional_rw;
+       }
+}
+
+ifdef HAS_SIZE_36 {
+       ram block $__XILINX_BLOCKRAM_SDP_ {
+               byte 9;
+               option "MODE" "HALF" {
+                       abits 14;
+                       widths 1 2 4 9 18 36 per_port;
+                       cost 129;
+               }
+               option "MODE" "FULL" {
+                       abits 15;
+                       widths 1 2 4 9 18 36 72 per_port;
+                       cost 257;
+               }
+               init any;
+               port sw "W" {
+                       ifndef HAS_MIXWIDTH_SDP {
+                               option "MODE" "HALF" width 36;
+                               option "MODE" "FULL" width 72;
+                       }
+                       ifdef HAS_ADDRCE {
+                               # TODO
+                               # addrce;
+                       }
+                       # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+                       ifdef HAS_CONFLICT_BUG {
+                               option "WRITE_MODE" "READ_FIRST" {
+                                       clock posedge "C";
+                               }
+                               option "WRITE_MODE" "WRITE_FIRST" {
+                                       clock posedge;
+                               }
+                       } else {
+                               clock posedge;
+                       }
+                       clken;
+                       option "WRITE_MODE" "READ_FIRST" {
+                               wrtrans all old;
+                       }
+                       optional;
+               }
+               port sr "R" {
+                       ifndef HAS_MIXWIDTH_SDP {
+                               option "MODE" "HALF" width 36;
+                               option "MODE" "FULL" width 72;
+                       }
+                       ifdef HAS_ADDRCE {
+                               # TODO
+                               # addrce;
+                       }
+                       # Spartan 6 and Virtex 6 have a bug where READ_FIRST is not usable with asynchronous clocks.
+                       ifdef HAS_CONFLICT_BUG {
+                               option "WRITE_MODE" "READ_FIRST" {
+                                       clock posedge "C";
+                               }
+                               option "WRITE_MODE" "WRITE_FIRST" {
+                                       clock posedge;
+                               }
+                       } else {
+                               clock posedge;
+                       }
+                       clken;
+                       rdsrst any gated_clken;
+                       rdinit any;
+                       optional;
+               }
+       }
+}
diff --git a/techlibs/xilinx/brams_xc4v_map.v b/techlibs/xilinx/brams_xc4v_map.v
new file mode 100644 (file)
index 0000000..a1747d4
--- /dev/null
@@ -0,0 +1,149 @@
+module $__XILINX_BLOCKRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+
+parameter PORT_A_RD_WIDTH = 1;
+parameter PORT_A_WR_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_RD_USED = 1;
+parameter PORT_A_WR_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 0;
+
+parameter PORT_B_RD_WIDTH = 1;
+parameter PORT_B_WR_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_RD_USED = 0;
+parameter PORT_B_WR_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [14:0] PORT_A_ADDR;
+input [PORT_A_WR_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_RD_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [14:0] PORT_B_ADDR;
+input [PORT_B_WR_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_RD_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_A_RD_USED ? PORT_A_RD_WIDTH : 0), \
+       .READ_WIDTH_B(PORT_B_RD_USED ? PORT_B_RD_WIDTH : 0), \
+       .WRITE_WIDTH_A(PORT_A_WR_USED ? PORT_A_WR_WIDTH : 0), \
+       .WRITE_WIDTH_B(PORT_B_WR_USED ? PORT_B_WR_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .INIT_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_INIT_VALUE)), \
+       .INIT_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_INIT_VALUE)), \
+       .SRVAL_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_SRST_VALUE)), \
+       .SRVAL_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_SRST_VALUE)),
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+wire [3:0] WE_A = {4{PORT_A_WR_EN}};
+wire [3:0] WE_B = {4{PORT_B_WR_EN}};
+
+generate
+
+if (OPTION_MODE == "FULL") begin
+       RAMB16 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("NONE"),
+               .RAM_EXTENSION_B("NONE"),
+       ) _TECHMAP_REPLACE_ (
+               .DOA(DO_A),
+               .DOPA(DOP_A),
+               .DIA(DI_A),
+               .DIPA(DIP_A),
+               .DOB(DO_B),
+               .DOPB(DOP_B),
+               .DIB(DI_B),
+               .DIPB(DIP_B),
+               .ADDRA({1'b1, PORT_A_ADDR[13:0]}),
+               .ADDRB({1'b1, PORT_B_ADDR[13:0]}),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+       );
+end else begin
+       wire CAS_A, CAS_B;
+       RAMB16 #(
+               `PARAMS_INIT_18
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("LOWER"),
+               .RAM_EXTENSION_B("LOWER"),
+       ) lower (
+               .DIA(DI_A),
+               .DIB(DI_B),
+               .ADDRA(PORT_A_ADDR),
+               .ADDRB(PORT_B_ADDR),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+               .CASCADEOUTA(CAS_A),
+               .CASCADEOUTB(CAS_B),
+       );
+       RAMB16 #(
+               `PARAMS_INIT_18_U
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("UPPER"),
+               .RAM_EXTENSION_B("UPPER"),
+       ) upper (
+               .DOA(DO_A),
+               .DIA(DI_A),
+               .DOB(DO_B),
+               .DIB(DI_B),
+               .ADDRA(PORT_A_ADDR),
+               .ADDRB(PORT_B_ADDR),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+               .CASCADEINA(CAS_A),
+               .CASCADEINB(CAS_B),
+       );
+end
+
+endgenerate
+
+endmodule
diff --git a/techlibs/xilinx/brams_xc5v_map.v b/techlibs/xilinx/brams_xc5v_map.v
new file mode 100644 (file)
index 0000000..6349af3
--- /dev/null
@@ -0,0 +1,255 @@
+module $__XILINX_BLOCKRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+
+parameter PORT_A_RD_WIDTH = 1;
+parameter PORT_A_WR_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_RD_USED = 1;
+parameter PORT_A_WR_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 0;
+
+parameter PORT_B_RD_WIDTH = 1;
+parameter PORT_B_WR_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_RD_USED = 0;
+parameter PORT_B_WR_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [15:0] PORT_A_ADDR;
+input [PORT_A_WR_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_RD_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [15:0] PORT_B_ADDR;
+input [PORT_B_WR_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_RD_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_A_RD_USED ? PORT_A_RD_WIDTH : 0), \
+       .READ_WIDTH_B(PORT_B_RD_USED ? PORT_B_RD_WIDTH : 0), \
+       .WRITE_WIDTH_A(PORT_A_WR_USED ? PORT_A_WR_WIDTH : 0), \
+       .WRITE_WIDTH_B(PORT_B_WR_USED ? PORT_B_WR_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .INIT_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_INIT_VALUE)), \
+       .INIT_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_INIT_VALUE)), \
+       .SRVAL_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_SRST_VALUE)), \
+       .SRVAL_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_SRST_VALUE)),
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+wire [3:0] WE_A = {4{PORT_A_WR_EN}};
+wire [3:0] WE_B = {4{PORT_B_WR_EN}};
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               .DOA(DO_A),
+               .DOPA(DOP_A),
+               .DIA(DI_A),
+               .DIPA(DIP_A),
+               .DOB(DO_B),
+               .DOPB(DOP_B),
+               .DIB(DI_B),
+               .DIPB(DIP_B),
+               .ADDRA(PORT_A_ADDR[13:0]),
+               .ADDRB(PORT_B_ADDR[13:0]),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36 #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("NONE"),
+               .RAM_EXTENSION_B("NONE"),
+       ) _TECHMAP_REPLACE_ (
+               .DOA(DO_A),
+               .DOPA(DOP_A),
+               .DIA(DI_A),
+               .DIPA(DIP_A),
+               .DOB(DO_B),
+               .DOPB(DOP_B),
+               .DIB(DI_B),
+               .DIPB(DIP_B),
+               .ADDRA({1'b1, PORT_A_ADDR[14:0]}),
+               .ADDRB({1'b1, PORT_B_ADDR[14:0]}),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+       );
+end else begin
+       wire CAS_A, CAS_B;
+       RAMB36 #(
+               `PARAMS_INIT_36
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("LOWER"),
+               .RAM_EXTENSION_B("LOWER"),
+       ) lower (
+               .DIA(DI_A),
+               .DIB(DI_B),
+               .ADDRA(PORT_A_ADDR),
+               .ADDRB(PORT_B_ADDR),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+               .CASCADEOUTLATA(CAS_A),
+               .CASCADEOUTLATB(CAS_B),
+       );
+       RAMB36 #(
+               `PARAMS_INIT_36_U
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("UPPER"),
+               .RAM_EXTENSION_B("UPPER"),
+       ) upper (
+               .DOA(DO_A),
+               .DIA(DI_A),
+               .DOB(DO_B),
+               .DIB(DI_B),
+               .ADDRA(PORT_A_ADDR),
+               .ADDRB(PORT_B_ADDR),
+               .CLKA(PORT_A_CLK),
+               .CLKB(PORT_B_CLK),
+               .ENA(PORT_A_CLK_EN),
+               .ENB(PORT_B_CLK_EN),
+               .REGCEA(1'b0),
+               .REGCEB(1'b0),
+               .SSRA(PORT_A_RD_SRST),
+               .SSRB(PORT_B_RD_SRST),
+               .WEA(WE_A),
+               .WEB(WE_B),
+               .CASCADEINLATA(CAS_A),
+               .CASCADEINLATB(CAS_B),
+       );
+end
+
+endgenerate
+
+endmodule
+
+
+module $__XILINX_BLOCKRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_WRITE_MODE = "READ_FIRST";
+
+parameter PORT_W_WIDTH = 1;
+parameter PORT_W_WR_EN_WIDTH = 1;
+parameter PORT_W_USED = 1;
+
+parameter PORT_R_WIDTH = 1;
+parameter PORT_R_USED = 0;
+parameter PORT_R_RD_INIT_VALUE = 0;
+parameter PORT_R_RD_SRST_VALUE = 0;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [15:0] PORT_W_ADDR;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input [15:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+input PORT_R_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .DO_REG(0), \
+       .INIT(ival(PORT_R_WIDTH, PORT_R_RD_INIT_VALUE)), \
+       .SRVAL(ival(PORT_R_WIDTH, PORT_R_RD_SRST_VALUE)),
+
+`define PORTS_COMMON \
+       .DO(DO), \
+       .DOP(DOP), \
+       .DI(DI), \
+       .DIP(DIP), \
+       .WRCLK(PORT_W_CLK), \
+       .RDCLK(PORT_R_CLK), \
+       .WREN(PORT_W_CLK_EN), \
+       .RDEN(PORT_R_CLK_EN), \
+       .REGCE(1'b0), \
+       .SSR(PORT_R_RD_SRST), \
+       .WE(PORT_W_WR_EN),
+
+`MAKE_DI(DI, DIP, PORT_W_WR_DATA)
+`MAKE_DO(DO, DOP, PORT_R_RD_DATA)
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18SDP #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .WRADDR(PORT_W_ADDR[13:5]),
+               .RDADDR(PORT_R_ADDR[13:5]),
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36SDP #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .WRADDR(PORT_W_ADDR[14:6]),
+               .RDADDR(PORT_R_ADDR[14:6]),
+       );
+end
+
+endgenerate
+
+endmodule
diff --git a/techlibs/xilinx/brams_xc6v_map.v b/techlibs/xilinx/brams_xc6v_map.v
new file mode 100644 (file)
index 0000000..b2698a3
--- /dev/null
@@ -0,0 +1,284 @@
+module $__XILINX_BLOCKRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_HAS_RDFIRST = 0;
+
+parameter PORT_A_RD_WIDTH = 1;
+parameter PORT_A_WR_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_RD_USED = 1;
+parameter PORT_A_WR_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 1;
+
+parameter PORT_B_RD_WIDTH = 1;
+parameter PORT_B_WR_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_RD_USED = 0;
+parameter PORT_B_WR_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+
+input CLK_C;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [15:0] PORT_A_ADDR;
+input [PORT_A_WR_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_RD_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [15:0] PORT_B_ADDR;
+input [PORT_B_WR_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_RD_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_A_RD_USED ? PORT_A_RD_WIDTH : 0), \
+       .READ_WIDTH_B(PORT_B_RD_USED ? PORT_B_RD_WIDTH : 0), \
+       .WRITE_WIDTH_A(PORT_A_WR_USED ? PORT_A_WR_WIDTH : 0), \
+       .WRITE_WIDTH_B(PORT_B_WR_USED ? PORT_B_WR_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .INIT_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_INIT_VALUE)), \
+       .INIT_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_INIT_VALUE)), \
+       .SRVAL_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_SRST_VALUE)), \
+       .SRVAL_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_SRST_VALUE)), \
+       .RAM_MODE("TDP"),
+
+`define PORTS_COMMON \
+       .DOADO(DO_A), \
+       .DOPADOP(DOP_A), \
+       .DIADI(DI_A), \
+       .DIPADIP(DIP_A), \
+       .DOBDO(DO_B), \
+       .DOPBDOP(DOP_B), \
+       .DIBDI(DI_B), \
+       .DIPBDIP(DIP_B), \
+       .CLKARDCLK(PORT_A_CLK), \
+       .CLKBWRCLK(PORT_B_CLK), \
+       .ENARDEN(PORT_A_CLK_EN), \
+       .ENBWREN(PORT_B_CLK_EN), \
+       .REGCEAREGCE(1'b0), \
+       .REGCEB(1'b0), \
+       .RSTRAMARSTRAM(PORT_A_RD_SRST), \
+       .RSTRAMB(PORT_B_RD_SRST), \
+       .RSTREGARSTREG(1'b0), \
+       .RSTREGB(1'b0), \
+       .WEA(WE_A), \
+       .WEBWE(WE_B),
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+wire [3:0] WE_A = {4{PORT_A_WR_EN}};
+wire [3:0] WE_B = {4{PORT_B_WR_EN}};
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18E1 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .ADDRARDADDR(PORT_A_ADDR[13:0]),
+               .ADDRBWRADDR(PORT_B_ADDR[13:0]),
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36E1 #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("NONE"),
+               .RAM_EXTENSION_B("NONE"),
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .ADDRARDADDR({1'b1, PORT_A_ADDR[14:0]}),
+               .ADDRBWRADDR({1'b1, PORT_B_ADDR[14:0]}),
+       );
+end else begin
+       wire CAS_A, CAS_B;
+       RAMB36E1 #(
+               `PARAMS_INIT_36
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("LOWER"),
+               .RAM_EXTENSION_B("LOWER"),
+       ) lower (
+               .DIADI(DI_A),
+               .DIBDI(DI_B),
+               .CLKARDCLK(PORT_A_CLK),
+               .CLKBWRCLK(PORT_B_CLK),
+               .ENARDEN(PORT_A_CLK_EN),
+               .ENBWREN(PORT_B_CLK_EN),
+               .REGCEAREGCE(1'b0),
+               .REGCEB(1'b0),
+               .RSTRAMARSTRAM(PORT_A_RD_SRST),
+               .RSTRAMB(PORT_B_RD_SRST),
+               .RSTREGARSTREG(1'b0),
+               .RSTREGB(1'b0),
+               .WEA(WE_A),
+               .WEBWE(WE_B),
+               .ADDRARDADDR(PORT_A_ADDR),
+               .ADDRBWRADDR(PORT_B_ADDR),
+               .CASCADEOUTA(CAS_A),
+               .CASCADEOUTB(CAS_B),
+       );
+       RAMB36E1 #(
+               `PARAMS_INIT_36_U
+               `PARAMS_COMMON
+               .RAM_EXTENSION_A("UPPER"),
+               .RAM_EXTENSION_B("UPPER"),
+       ) upper (
+               .DOADO(DO_A),
+               .DIADI(DI_A),
+               .DOBDO(DO_B),
+               .DIBDI(DI_B),
+               .CLKARDCLK(PORT_A_CLK),
+               .CLKBWRCLK(PORT_B_CLK),
+               .ENARDEN(PORT_A_CLK_EN),
+               .ENBWREN(PORT_B_CLK_EN),
+               .REGCEAREGCE(1'b0),
+               .REGCEB(1'b0),
+               .RSTRAMARSTRAM(PORT_A_RD_SRST),
+               .RSTRAMB(PORT_B_RD_SRST),
+               .RSTREGARSTREG(1'b0),
+               .RSTREGB(1'b0),
+               .WEA(WE_A),
+               .WEBWE(WE_B),
+               .ADDRARDADDR(PORT_A_ADDR),
+               .ADDRBWRADDR(PORT_B_ADDR),
+               .CASCADEINA(CAS_A),
+               .CASCADEINB(CAS_B),
+       );
+end
+
+endgenerate
+
+endmodule
+
+
+module $__XILINX_BLOCKRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_WRITE_MODE = "READ_FIRST";
+
+parameter PORT_W_WIDTH = 1;
+parameter PORT_W_WR_EN_WIDTH = 1;
+parameter PORT_W_USED = 1;
+
+parameter PORT_R_WIDTH = 1;
+parameter PORT_R_USED = 0;
+parameter PORT_R_RD_INIT_VALUE = 0;
+parameter PORT_R_RD_SRST_VALUE = 0;
+
+input CLK_C;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [15:0] PORT_W_ADDR;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input [15:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+input PORT_R_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_R_USED ? PORT_R_WIDTH : 0), \
+       .READ_WIDTH_B(0), \
+       .WRITE_WIDTH_A(0), \
+       .WRITE_WIDTH_B(PORT_W_USED ? PORT_W_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .RAM_MODE("SDP"),
+
+`define PORTS_COMMON \
+       .CLKBWRCLK(PORT_W_CLK), \
+       .CLKARDCLK(PORT_R_CLK), \
+       .ENBWREN(PORT_W_CLK_EN), \
+       .ENARDEN(PORT_R_CLK_EN), \
+       .REGCEAREGCE(1'b0), \
+       .REGCEB(1'b0), \
+       .RSTRAMARSTRAM(PORT_R_RD_SRST), \
+       .RSTRAMB(1'b0), \
+       .RSTREGARSTREG(1'b0), \
+       .RSTREGB(1'b0), \
+       .WEA(0), \
+       .WEBWE(PORT_W_WR_EN),
+
+`MAKE_DI(DI, DIP, PORT_W_WR_DATA)
+`MAKE_DO(DO, DOP, PORT_R_RD_DATA)
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18E1 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+               .INIT_A(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_INIT_VALUE[17:0]) : ival(PORT_R_WIDTH, PORT_R_RD_INIT_VALUE)),
+               .INIT_B(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_INIT_VALUE[35:18]) : 0),
+               .SRVAL_A(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_SRST_VALUE[17:0]) : ival(PORT_R_WIDTH, PORT_R_RD_SRST_VALUE)),
+               .SRVAL_B(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_SRST_VALUE[35:18]) : 0),
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .ADDRARDADDR(PORT_R_ADDR[13:0]),
+               .ADDRBWRADDR(PORT_W_ADDR[13:0]),
+               .DOADO(DO[15:0]),
+               .DOBDO(DO[31:16]),
+               .DOPADOP(DOP[1:0]),
+               .DOPBDOP(DOP[3:2]),
+               .DIADI(DI[15:0]),
+               .DIBDI(PORT_W_WIDTH == 36 ? DI[31:16] : DI[15:0]),
+               .DIPADIP(DIP[1:0]),
+               .DIPBDIP(PORT_W_WIDTH == 36 ? DIP[3:2] : DIP[1:0]),
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36E1 #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+               .INIT_A(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_INIT_VALUE[35:0]) : ival(PORT_R_WIDTH, PORT_R_RD_INIT_VALUE)),
+               .INIT_B(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_INIT_VALUE[71:36]) : 0),
+               .SRVAL_A(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_SRST_VALUE[35:0]) : ival(PORT_R_WIDTH, PORT_R_RD_SRST_VALUE)),
+               .SRVAL_B(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_SRST_VALUE[71:36]) : 0),
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .ADDRARDADDR({1'b1, PORT_R_ADDR}),
+               .ADDRBWRADDR({1'b1, PORT_W_ADDR}),
+               .DOADO(DO[31:0]),
+               .DOBDO(DO[63:32]),
+               .DOPADOP(DOP[3:0]),
+               .DOPBDOP(DOP[7:4]),
+               .DIADI(DI[31:0]),
+               .DIBDI(PORT_W_WIDTH == 72 ? DI[63:32] : DI[31:0]),
+               .DIPADIP(DIP[3:0]),
+               .DIPBDIP(PORT_W_WIDTH == 71 ? DIP[7:4] : DIP[3:0]),
+       );
+end
+
+endgenerate
+
+endmodule
diff --git a/techlibs/xilinx/brams_xcu_map.v b/techlibs/xilinx/brams_xcu_map.v
new file mode 100644 (file)
index 0000000..d48c21a
--- /dev/null
@@ -0,0 +1,225 @@
+module $__XILINX_BLOCKRAM_TDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_HAS_RDFIRST = 0;
+
+parameter PORT_A_RD_WIDTH = 1;
+parameter PORT_A_WR_WIDTH = 1;
+parameter PORT_A_WR_EN_WIDTH = 1;
+parameter PORT_A_RD_USED = 1;
+parameter PORT_A_WR_USED = 1;
+parameter PORT_A_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_A_RD_INIT_VALUE = 0;
+parameter PORT_A_RD_SRST_VALUE = 1;
+
+parameter PORT_B_RD_WIDTH = 1;
+parameter PORT_B_WR_WIDTH = 1;
+parameter PORT_B_WR_EN_WIDTH = 1;
+parameter PORT_B_RD_USED = 0;
+parameter PORT_B_WR_USED = 0;
+parameter PORT_B_OPTION_WRITE_MODE = "NO_CHANGE";
+parameter PORT_B_RD_INIT_VALUE = 0;
+parameter PORT_B_RD_SRST_VALUE = 0;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [15:0] PORT_A_ADDR;
+input [PORT_A_WR_WIDTH-1:0] PORT_A_WR_DATA;
+input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN;
+output [PORT_A_RD_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [15:0] PORT_B_ADDR;
+input [PORT_B_WR_WIDTH-1:0] PORT_B_WR_DATA;
+input [PORT_B_WR_EN_WIDTH-1:0] PORT_B_WR_EN;
+output [PORT_B_RD_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(PORT_A_OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(PORT_B_OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_A_RD_USED ? PORT_A_RD_WIDTH : 0), \
+       .READ_WIDTH_B(PORT_B_RD_USED ? PORT_B_RD_WIDTH : 0), \
+       .WRITE_WIDTH_A(PORT_A_WR_USED ? PORT_A_WR_WIDTH : 0), \
+       .WRITE_WIDTH_B(PORT_B_WR_USED ? PORT_B_WR_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0), \
+       .INIT_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_INIT_VALUE)), \
+       .INIT_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_INIT_VALUE)), \
+       .SRVAL_A(ival(PORT_A_RD_WIDTH, PORT_A_RD_SRST_VALUE)), \
+       .SRVAL_B(ival(PORT_B_RD_WIDTH, PORT_B_RD_SRST_VALUE)),
+
+`define PORTS_COMMON \
+       .DOUTADOUT(DO_A), \
+       .DOUTPADOUTP(DOP_A), \
+       .DINADIN(DI_A), \
+       .DINPADINP(DIP_A), \
+       .DOUTBDOUT(DO_B), \
+       .DOUTPBDOUTP(DOP_B), \
+       .DINBDIN(DI_B), \
+       .DINPBDINP(DIP_B), \
+       .CLKARDCLK(PORT_A_CLK), \
+       .CLKBWRCLK(PORT_B_CLK), \
+       .ENARDEN(PORT_A_CLK_EN), \
+       .ENBWREN(PORT_B_CLK_EN), \
+       .REGCEAREGCE(1'b0), \
+       .REGCEB(1'b0), \
+       .ADDRENA(1'b1), \
+       .ADDRENB(1'b1), \
+       .RSTRAMARSTRAM(PORT_A_RD_SRST), \
+       .RSTRAMB(PORT_B_RD_SRST), \
+       .RSTREGARSTREG(1'b0), \
+       .RSTREGB(1'b0), \
+       .WEA(WE_A), \
+       .WEBWE(WE_B), \
+       .ADDRARDADDR(PORT_A_ADDR), \
+       .ADDRBWRADDR(PORT_B_ADDR), \
+       .SLEEP(1'b0),
+
+`MAKE_DI(DI_A, DIP_A, PORT_A_WR_DATA)
+`MAKE_DI(DI_B, DIP_B, PORT_B_WR_DATA)
+`MAKE_DO(DO_A, DOP_A, PORT_A_RD_DATA)
+`MAKE_DO(DO_B, DOP_B, PORT_B_RD_DATA)
+
+wire [3:0] WE_A = {4{PORT_A_WR_EN}};
+wire [3:0] WE_B = {4{PORT_B_WR_EN}};
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18E2 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36E2 #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+       );
+end
+
+endgenerate
+
+endmodule
+
+
+module $__XILINX_BLOCKRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_MODE = "FULL";
+parameter OPTION_WRITE_MODE = "READ_FIRST";
+
+parameter PORT_W_WIDTH = 1;
+parameter PORT_W_WR_EN_WIDTH = 1;
+parameter PORT_W_USED = 1;
+
+parameter PORT_R_WIDTH = 1;
+parameter PORT_R_USED = 0;
+parameter PORT_R_RD_INIT_VALUE = 0;
+parameter PORT_R_RD_SRST_VALUE = 0;
+
+input PORT_W_CLK;
+input PORT_W_CLK_EN;
+input [15:0] PORT_W_ADDR;
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+input [PORT_W_WR_EN_WIDTH-1:0] PORT_W_WR_EN;
+
+input PORT_R_CLK;
+input PORT_R_CLK_EN;
+input [15:0] PORT_R_ADDR;
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+input PORT_R_RD_SRST;
+
+`include "brams_defs.vh"
+
+`define PARAMS_COMMON \
+       .WRITE_MODE_A(OPTION_WRITE_MODE), \
+       .WRITE_MODE_B(OPTION_WRITE_MODE), \
+       .READ_WIDTH_A(PORT_R_USED ? PORT_R_WIDTH : 0), \
+       .READ_WIDTH_B(0), \
+       .WRITE_WIDTH_A(0), \
+       .WRITE_WIDTH_B(PORT_W_USED ? PORT_W_WIDTH : 0), \
+       .DOA_REG(0), \
+       .DOB_REG(0),
+
+`define PORTS_COMMON \
+       .CLKBWRCLK(PORT_W_CLK), \
+       .CLKARDCLK(PORT_R_CLK), \
+       .ENBWREN(PORT_W_CLK_EN), \
+       .ENARDEN(PORT_R_CLK_EN), \
+       .REGCEAREGCE(1'b0), \
+       .REGCEB(1'b0), \
+       .ADDRENA(1'b1), \
+       .ADDRENB(1'b1), \
+       .RSTRAMARSTRAM(PORT_R_RD_SRST), \
+       .RSTRAMB(1'b0), \
+       .RSTREGARSTREG(1'b0), \
+       .RSTREGB(1'b0), \
+       .WEA(0), \
+       .WEBWE(PORT_W_WR_EN), \
+       .ADDRARDADDR(PORT_R_ADDR), \
+       .ADDRBWRADDR(PORT_W_ADDR), \
+       .SLEEP(1'b0),
+
+`MAKE_DI(DI, DIP, PORT_W_WR_DATA)
+`MAKE_DO(DO, DOP, PORT_R_RD_DATA)
+
+generate
+
+if (OPTION_MODE == "HALF") begin
+       RAMB18E2 #(
+               `PARAMS_INIT_18
+               `PARAMS_INITP_18
+               `PARAMS_COMMON
+               .INIT_A(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_INIT_VALUE[17:0]) : ival(PORT_R_WIDTH, PORT_R_RD_INIT_VALUE)),
+               .INIT_B(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_INIT_VALUE[35:18]) : 0),
+               .SRVAL_A(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_SRST_VALUE[17:0]) : ival(PORT_R_WIDTH, PORT_R_RD_SRST_VALUE)),
+               .SRVAL_B(PORT_R_WIDTH == 36 ? ival(18, PORT_R_RD_SRST_VALUE[35:18]) : 0),
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .DOUTADOUT(DO[15:0]),
+               .DOUTBDOUT(DO[31:16]),
+               .DOUTPADOUTP(DOP[1:0]),
+               .DOUTPBDOUTP(DOP[3:2]),
+               .DINADIN(DI[15:0]),
+               .DINBDIN(PORT_W_WIDTH == 36 ? DI[31:16] : DI[15:0]),
+               .DINPADINP(DIP[1:0]),
+               .DINPBDINP(PORT_W_WIDTH == 36 ? DIP[3:2] : DIP[1:0]),
+       );
+end else if (OPTION_MODE == "FULL") begin
+       RAMB36E2 #(
+               `PARAMS_INIT_36
+               `PARAMS_INITP_36
+               `PARAMS_COMMON
+               .INIT_A(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_INIT_VALUE[35:0]) : ival(PORT_R_WIDTH, PORT_R_RD_INIT_VALUE)),
+               .INIT_B(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_INIT_VALUE[71:36]) : 0),
+               .SRVAL_A(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_SRST_VALUE[35:0]) : ival(PORT_R_WIDTH, PORT_R_RD_SRST_VALUE)),
+               .SRVAL_B(PORT_R_WIDTH == 72 ? ival(36, PORT_R_RD_SRST_VALUE[71:36]) : 0),
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_COMMON
+               .DOUTADOUT(DO[31:0]),
+               .DOUTBDOUT(DO[63:32]),
+               .DOUTPADOUTP(DOP[3:0]),
+               .DOUTPBDOUTP(DOP[7:4]),
+               .DINADIN(DI[31:0]),
+               .DINBDIN(PORT_W_WIDTH == 72 ? DI[63:32] : DI[31:0]),
+               .DINPADINP(DIP[3:0]),
+               .DINPBDINP(PORT_W_WIDTH == 71 ? DIP[7:4] : DIP[3:0]),
+       );
+end
+
+endgenerate
+
+endmodule
+
diff --git a/techlibs/xilinx/brams_xcv.txt b/techlibs/xilinx/brams_xcv.txt
new file mode 100644 (file)
index 0000000..294e903
--- /dev/null
@@ -0,0 +1,17 @@
+# Block RAMs for the original Virtex.
+# The corresponding mapping file is brams_xcv_map.v
+
+ram block $__XILINX_BLOCKRAM_ {
+       abits 12;
+       widths 1 2 4 8 16 per_port;
+       cost 32;
+       init any;
+       port srsw "A" "B" {
+               clock posedge;
+               clken;
+               rdwr new;
+               rdinit zero;
+               rdsrst zero gated_clken;
+               optional;
+       }
+}
diff --git a/techlibs/xilinx/brams_xcv_map.v b/techlibs/xilinx/brams_xcv_map.v
new file mode 100644 (file)
index 0000000..408cc67
--- /dev/null
@@ -0,0 +1,257 @@
+module $__XILINX_BLOCKRAM_ (...);
+
+parameter INIT = 0;
+
+parameter PORT_A_WIDTH = 1;
+parameter PORT_B_WIDTH = 1;
+parameter PORT_A_USED = 1;
+parameter PORT_B_USED = 0;
+
+input PORT_A_CLK;
+input PORT_A_CLK_EN;
+input [11:0] PORT_A_ADDR;
+input [PORT_A_WIDTH-1:0] PORT_A_WR_DATA;
+input PORT_A_WR_EN;
+output [PORT_A_WIDTH-1:0] PORT_A_RD_DATA;
+input PORT_A_RD_SRST;
+
+input PORT_B_CLK;
+input PORT_B_CLK_EN;
+input [11:0] PORT_B_ADDR;
+input [PORT_B_WIDTH-1:0] PORT_B_WR_DATA;
+input PORT_B_WR_EN;
+output [PORT_B_WIDTH-1:0] PORT_B_RD_DATA;
+input PORT_B_RD_SRST;
+
+`define PARAMS_INIT \
+       .INIT_00(INIT[0*256+:256]), \
+       .INIT_01(INIT[1*256+:256]), \
+       .INIT_02(INIT[2*256+:256]), \
+       .INIT_03(INIT[3*256+:256]), \
+       .INIT_04(INIT[4*256+:256]), \
+       .INIT_05(INIT[5*256+:256]), \
+       .INIT_06(INIT[6*256+:256]), \
+       .INIT_07(INIT[7*256+:256]), \
+       .INIT_08(INIT[8*256+:256]), \
+       .INIT_09(INIT[9*256+:256]), \
+       .INIT_0A(INIT[10*256+:256]), \
+       .INIT_0B(INIT[11*256+:256]), \
+       .INIT_0C(INIT[12*256+:256]), \
+       .INIT_0D(INIT[13*256+:256]), \
+       .INIT_0E(INIT[14*256+:256]), \
+       .INIT_0F(INIT[15*256+:256]),
+
+`define PORTS_DP(addr_slice_a, addr_slice_b) \
+       .CLKA(PORT_A_CLK), \
+       .ENA(PORT_A_CLK_EN), \
+       .WEA(PORT_A_WR_EN), \
+       .RSTA(PORT_A_RD_SRST), \
+       .ADDRA(PORT_A_ADDR addr_slice_a), \
+       .DOA(PORT_A_RD_DATA), \
+       .DIA(PORT_A_WR_DATA), \
+       .CLKB(PORT_B_CLK), \
+       .ENB(PORT_B_CLK_EN), \
+       .WEB(PORT_B_WR_EN), \
+       .RSTB(PORT_B_RD_SRST), \
+       .ADDRB(PORT_B_ADDR addr_slice_b), \
+       .DOB(PORT_B_RD_DATA), \
+       .DIB(PORT_B_WR_DATA),
+
+`define PORTS_DP_SWAP(addr_slice_a, addr_slice_b) \
+       .CLKB(PORT_A_CLK), \
+       .ENB(PORT_A_CLK_EN), \
+       .WEB(PORT_A_WR_EN), \
+       .RSTB(PORT_A_RD_SRST), \
+       .ADDRB(PORT_A_ADDR addr_slice_a), \
+       .DOB(PORT_A_RD_DATA), \
+       .DIB(PORT_A_WR_DATA), \
+       .CLKA(PORT_B_CLK), \
+       .ENA(PORT_B_CLK_EN), \
+       .WEA(PORT_B_WR_EN), \
+       .RSTA(PORT_B_RD_SRST), \
+       .ADDRA(PORT_B_ADDR addr_slice_b), \
+       .DOA(PORT_B_RD_DATA), \
+       .DIA(PORT_B_WR_DATA),
+
+`define PORTS_SP(addr_slice) \
+       .CLK(PORT_A_CLK), \
+       .EN(PORT_A_CLK_EN), \
+       .WE(PORT_A_WR_EN), \
+       .RST(PORT_A_RD_SRST), \
+       .ADDR(PORT_A_ADDR addr_slice), \
+       .DO(PORT_A_RD_DATA), \
+       .DI(PORT_A_WR_DATA),
+
+generate
+
+if (!PORT_B_USED) begin
+       case (PORT_A_WIDTH)
+       1: RAMB4_S1 #(
+               `PARAMS_INIT
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_SP([11:0])
+       );
+       2: RAMB4_S2 #(
+               `PARAMS_INIT
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_SP([11:1])
+       );
+       4: RAMB4_S4 #(
+               `PARAMS_INIT
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_SP([11:2])
+       );
+       8: RAMB4_S8 #(
+               `PARAMS_INIT
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_SP([11:3])
+       );
+       16: RAMB4_S16 #(
+               `PARAMS_INIT
+       ) _TECHMAP_REPLACE_ (
+               `PORTS_SP([11:4])
+       );
+       endcase
+end else begin
+       case (PORT_A_WIDTH)
+       1:      case(PORT_B_WIDTH)
+               1: RAMB4_S1_S1 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:0], [11:0])
+               );
+               2: RAMB4_S1_S2 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:0], [11:1])
+               );
+               4: RAMB4_S1_S4 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:0], [11:2])
+               );
+               8: RAMB4_S1_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:0], [11:3])
+               );
+               16: RAMB4_S1_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:0], [11:4])
+               );
+               endcase
+       2:      case(PORT_B_WIDTH)
+               1: RAMB4_S1_S2 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:1], [11:0])
+               );
+               2: RAMB4_S2_S2 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:1], [11:1])
+               );
+               4: RAMB4_S2_S4 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:1], [11:2])
+               );
+               8: RAMB4_S2_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:1], [11:3])
+               );
+               16: RAMB4_S2_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:1], [11:4])
+               );
+               endcase
+       4:      case(PORT_B_WIDTH)
+               1: RAMB4_S1_S4 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:2], [11:0])
+               );
+               2: RAMB4_S2_S4 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:2], [11:1])
+               );
+               4: RAMB4_S4_S4 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:2], [11:2])
+               );
+               8: RAMB4_S4_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:2], [11:3])
+               );
+               16: RAMB4_S4_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:2], [11:4])
+               );
+               endcase
+       8:      case(PORT_B_WIDTH)
+               1: RAMB4_S1_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:3], [11:0])
+               );
+               2: RAMB4_S2_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:3], [11:1])
+               );
+               4: RAMB4_S4_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:3], [11:2])
+               );
+               8: RAMB4_S8_S8 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:3], [11:3])
+               );
+               16: RAMB4_S8_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:3], [11:4])
+               );
+               endcase
+       16:     case(PORT_B_WIDTH)
+               1: RAMB4_S1_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:4], [11:0])
+               );
+               2: RAMB4_S2_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:4], [11:1])
+               );
+               4: RAMB4_S4_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:4], [11:2])
+               );
+               8: RAMB4_S8_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP_SWAP([11:4], [11:3])
+               );
+               16: RAMB4_S16_S16 #(
+                       `PARAMS_INIT
+               ) _TECHMAP_REPLACE_ (
+                       `PORTS_DP([11:4], [11:4])
+               );
+               endcase
+       endcase
+end
+
+endgenerate
+
+endmodule
diff --git a/techlibs/xilinx/lut4_lutrams.txt b/techlibs/xilinx/lut4_lutrams.txt
deleted file mode 100644 (file)
index 2b344a9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-bram $__XILINX_RAM16X1D
-  init 1
-  abits 4
-  dbits 1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-
-match $__XILINX_RAM16X1D
-  min bits 2
-  min wports 1
-  make_outreg
-endmatch
diff --git a/techlibs/xilinx/lut6_lutrams.txt b/techlibs/xilinx/lut6_lutrams.txt
deleted file mode 100644 (file)
index 3b3cb81..0000000
+++ /dev/null
@@ -1,143 +0,0 @@
-bram $__XILINX_RAM32X1D
-  init 1
-  abits 5
-  dbits 1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-bram $__XILINX_RAM64X1D
-  init 1
-  abits 6
-  dbits 1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-bram $__XILINX_RAM128X1D
-  init 1
-  abits 7
-  dbits 1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-
-bram $__XILINX_RAM32X6SDP
-  init 1
-  abits 5
-  dbits 6
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-bram $__XILINX_RAM64X3SDP
-  init 1
-  abits 6
-  dbits 3
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-bram $__XILINX_RAM32X2Q
-  init 1
-  abits 5
-  dbits 2
-  groups 2
-  ports  3 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-bram $__XILINX_RAM64X1Q
-  init 1
-  abits 6
-  dbits 1
-  groups 2
-  ports  3 1
-  wrmode 0 1
-  enable 0 1
-  transp 0 0
-  clocks 0 1
-  clkpol 0 2
-endbram
-
-
-match $__XILINX_RAM32X1D
-  min bits 3
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAM64X1D
-  min bits 5
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAM128X1D
-  min bits 9
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-
-match $__XILINX_RAM32X6SDP
-  min bits 5
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAM64X3SDP
-  min bits 6
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAM32X2Q
-  min bits 5
-  min rports 2
-  min wports 1
-  make_outreg
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAM64X1Q
-  min bits 5
-  min rports 2
-  min wports 1
-  make_outreg
-endmatch
diff --git a/techlibs/xilinx/lutrams_map.v b/techlibs/xilinx/lutrams_map.v
deleted file mode 100644 (file)
index 3ac1143..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-
-module \$__XILINX_RAM16X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [15:0] INIT = 16'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [3:0] A1ADDR;
-       output A1DATA;
-
-       input [3:0] B1ADDR;
-       input B1DATA;
-       input B1EN;
-
-       RAM16X1D #(
-               .INIT(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .DPRA0(A1ADDR[0]),
-               .DPRA1(A1ADDR[1]),
-               .DPRA2(A1ADDR[2]),
-               .DPRA3(A1ADDR[3]),
-               .DPO(A1DATA),
-
-               .A0(B1ADDR[0]),
-               .A1(B1ADDR[1]),
-               .A2(B1ADDR[2]),
-               .A3(B1ADDR[3]),
-               .D(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM32X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [31:0] INIT = 32'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [4:0] A1ADDR;
-       output A1DATA;
-
-       input [4:0] B1ADDR;
-       input B1DATA;
-       input B1EN;
-
-       RAM32X1D #(
-               .INIT(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .DPRA0(A1ADDR[0]),
-               .DPRA1(A1ADDR[1]),
-               .DPRA2(A1ADDR[2]),
-               .DPRA3(A1ADDR[3]),
-               .DPRA4(A1ADDR[4]),
-               .DPO(A1DATA),
-
-               .A0(B1ADDR[0]),
-               .A1(B1ADDR[1]),
-               .A2(B1ADDR[2]),
-               .A3(B1ADDR[3]),
-               .A4(B1ADDR[4]),
-               .D(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM64X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0] INIT = 64'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [5:0] A1ADDR;
-       output A1DATA;
-
-       input [5:0] B1ADDR;
-       input B1DATA;
-       input B1EN;
-
-       RAM64X1D #(
-               .INIT(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .DPRA0(A1ADDR[0]),
-               .DPRA1(A1ADDR[1]),
-               .DPRA2(A1ADDR[2]),
-               .DPRA3(A1ADDR[3]),
-               .DPRA4(A1ADDR[4]),
-               .DPRA5(A1ADDR[5]),
-               .DPO(A1DATA),
-
-               .A0(B1ADDR[0]),
-               .A1(B1ADDR[1]),
-               .A2(B1ADDR[2]),
-               .A3(B1ADDR[3]),
-               .A4(B1ADDR[4]),
-               .A5(B1ADDR[5]),
-               .D(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM128X1D (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [127:0] INIT = 128'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [6:0] A1ADDR;
-       output A1DATA;
-
-       input [6:0] B1ADDR;
-       input B1DATA;
-       input B1EN;
-
-       RAM128X1D #(
-               .INIT(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .DPRA(A1ADDR),
-               .DPO(A1DATA),
-
-               .A(B1ADDR),
-               .D(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-
-module \$__XILINX_RAM32X6SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [32*6-1:0] INIT = {32*6{1'bx}};
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [4:0] A1ADDR;
-       output [5:0] A1DATA;
-
-       input [4:0] B1ADDR;
-       input [5:0] B1DATA;
-       input B1EN;
-
-       wire [1:0] DOD_unused;
-
-       RAM32M #(
-               .INIT_A({INIT[187:186], INIT[181:180], INIT[175:174], INIT[169:168], INIT[163:162], INIT[157:156], INIT[151:150], INIT[145:144], INIT[139:138], INIT[133:132], INIT[127:126], INIT[121:120], INIT[115:114], INIT[109:108], INIT[103:102], INIT[ 97: 96], INIT[ 91: 90], INIT[ 85: 84], INIT[ 79: 78], INIT[ 73: 72], INIT[ 67: 66], INIT[ 61: 60], INIT[ 55: 54], INIT[ 49: 48], INIT[ 43: 42], INIT[ 37: 36], INIT[ 31: 30], INIT[ 25: 24], INIT[ 19: 18], INIT[ 13: 12], INIT[  7:  6], INIT[  1:  0]}),
-               .INIT_B({INIT[189:188], INIT[183:182], INIT[177:176], INIT[171:170], INIT[165:164], INIT[159:158], INIT[153:152], INIT[147:146], INIT[141:140], INIT[135:134], INIT[129:128], INIT[123:122], INIT[117:116], INIT[111:110], INIT[105:104], INIT[ 99: 98], INIT[ 93: 92], INIT[ 87: 86], INIT[ 81: 80], INIT[ 75: 74], INIT[ 69: 68], INIT[ 63: 62], INIT[ 57: 56], INIT[ 51: 50], INIT[ 45: 44], INIT[ 39: 38], INIT[ 33: 32], INIT[ 27: 26], INIT[ 21: 20], INIT[ 15: 14], INIT[  9:  8], INIT[  3:  2]}),
-               .INIT_C({INIT[191:190], INIT[185:184], INIT[179:178], INIT[173:172], INIT[167:166], INIT[161:160], INIT[155:154], INIT[149:148], INIT[143:142], INIT[137:136], INIT[131:130], INIT[125:124], INIT[119:118], INIT[113:112], INIT[107:106], INIT[101:100], INIT[ 95: 94], INIT[ 89: 88], INIT[ 83: 82], INIT[ 77: 76], INIT[ 71: 70], INIT[ 65: 64], INIT[ 59: 58], INIT[ 53: 52], INIT[ 47: 46], INIT[ 41: 40], INIT[ 35: 34], INIT[ 29: 28], INIT[ 23: 22], INIT[ 17: 16], INIT[ 11: 10], INIT[  5:  4]}),
-               .INIT_D(64'bx),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .ADDRA(A1ADDR),
-               .ADDRB(A1ADDR),
-               .ADDRC(A1ADDR),
-               .DOA(A1DATA[1:0]),
-               .DOB(A1DATA[3:2]),
-               .DOC(A1DATA[5:4]),
-               .DOD(DOD_unused),
-
-               .ADDRD(B1ADDR),
-               .DIA(B1DATA[1:0]),
-               .DIB(B1DATA[3:2]),
-               .DIC(B1DATA[5:4]),
-               .DID(2'b00),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM64X3SDP (CLK1, A1ADDR, A1DATA, B1ADDR, B1DATA, B1EN);
-       parameter [64*3-1:0] INIT = {64*3{1'bx}};
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [5:0] A1ADDR;
-       output [2:0] A1DATA;
-
-       input [5:0] B1ADDR;
-       input [2:0] B1DATA;
-       input B1EN;
-
-       wire DOD_unused;
-
-       RAM64M #(
-               .INIT_A({INIT[189], INIT[186], INIT[183], INIT[180], INIT[177], INIT[174], INIT[171], INIT[168], INIT[165], INIT[162], INIT[159], INIT[156], INIT[153], INIT[150], INIT[147], INIT[144], INIT[141], INIT[138], INIT[135], INIT[132], INIT[129], INIT[126], INIT[123], INIT[120], INIT[117], INIT[114], INIT[111], INIT[108], INIT[105], INIT[102], INIT[ 99], INIT[ 96], INIT[ 93], INIT[ 90], INIT[ 87], INIT[ 84], INIT[ 81], INIT[ 78], INIT[ 75], INIT[ 72], INIT[ 69], INIT[ 66], INIT[ 63], INIT[ 60], INIT[ 57], INIT[ 54], INIT[ 51], INIT[ 48], INIT[ 45], INIT[ 42], INIT[ 39], INIT[ 36], INIT[ 33], INIT[ 30], INIT[ 27], INIT[ 24], INIT[ 21], INIT[ 18], INIT[ 15], INIT[ 12], INIT[  9], INIT[  6], INIT[  3], INIT[  0]}),
-               .INIT_B({INIT[190], INIT[187], INIT[184], INIT[181], INIT[178], INIT[175], INIT[172], INIT[169], INIT[166], INIT[163], INIT[160], INIT[157], INIT[154], INIT[151], INIT[148], INIT[145], INIT[142], INIT[139], INIT[136], INIT[133], INIT[130], INIT[127], INIT[124], INIT[121], INIT[118], INIT[115], INIT[112], INIT[109], INIT[106], INIT[103], INIT[100], INIT[ 97], INIT[ 94], INIT[ 91], INIT[ 88], INIT[ 85], INIT[ 82], INIT[ 79], INIT[ 76], INIT[ 73], INIT[ 70], INIT[ 67], INIT[ 64], INIT[ 61], INIT[ 58], INIT[ 55], INIT[ 52], INIT[ 49], INIT[ 46], INIT[ 43], INIT[ 40], INIT[ 37], INIT[ 34], INIT[ 31], INIT[ 28], INIT[ 25], INIT[ 22], INIT[ 19], INIT[ 16], INIT[ 13], INIT[ 10], INIT[  7], INIT[  4], INIT[  1]}),
-               .INIT_C({INIT[191], INIT[188], INIT[185], INIT[182], INIT[179], INIT[176], INIT[173], INIT[170], INIT[167], INIT[164], INIT[161], INIT[158], INIT[155], INIT[152], INIT[149], INIT[146], INIT[143], INIT[140], INIT[137], INIT[134], INIT[131], INIT[128], INIT[125], INIT[122], INIT[119], INIT[116], INIT[113], INIT[110], INIT[107], INIT[104], INIT[101], INIT[ 98], INIT[ 95], INIT[ 92], INIT[ 89], INIT[ 86], INIT[ 83], INIT[ 80], INIT[ 77], INIT[ 74], INIT[ 71], INIT[ 68], INIT[ 65], INIT[ 62], INIT[ 59], INIT[ 56], INIT[ 53], INIT[ 50], INIT[ 47], INIT[ 44], INIT[ 41], INIT[ 38], INIT[ 35], INIT[ 32], INIT[ 29], INIT[ 26], INIT[ 23], INIT[ 20], INIT[ 17], INIT[ 14], INIT[ 11], INIT[  8], INIT[  5], INIT[  2]}),
-               .INIT_D(64'bx),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .ADDRA(A1ADDR),
-               .ADDRB(A1ADDR),
-               .ADDRC(A1ADDR),
-               .DOA(A1DATA[0]),
-               .DOB(A1DATA[1]),
-               .DOC(A1DATA[2]),
-               .DOD(DOD_unused),
-
-               .ADDRD(B1ADDR),
-               .DIA(B1DATA[0]),
-               .DIB(B1DATA[1]),
-               .DIC(B1DATA[2]),
-               .DID(1'b0),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM32X2Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0] INIT = 64'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [4:0] A1ADDR, A2ADDR, A3ADDR;
-       output [1:0] A1DATA, A2DATA, A3DATA;
-
-       input [4:0] B1ADDR;
-       input [1:0] B1DATA;
-       input B1EN;
-
-       RAM32M #(
-               .INIT_A(INIT),
-               .INIT_B(INIT),
-               .INIT_C(INIT),
-               .INIT_D(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .ADDRA(A1ADDR),
-               .ADDRB(A2ADDR),
-               .ADDRC(A3ADDR),
-               .DOA(A1DATA),
-               .DOB(A2DATA),
-               .DOC(A3DATA),
-
-               .ADDRD(B1ADDR),
-               .DIA(B1DATA),
-               .DIB(B1DATA),
-               .DIC(B1DATA),
-               .DID(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
-
-module \$__XILINX_RAM64X1Q (CLK1, A1ADDR, A1DATA, A2ADDR, A2DATA, A3ADDR, A3DATA, B1ADDR, B1DATA, B1EN);
-       parameter [63:0] INIT = 64'bx;
-       parameter CLKPOL2 = 1;
-       input CLK1;
-
-       input [5:0] A1ADDR, A2ADDR, A3ADDR;
-       output A1DATA, A2DATA, A3DATA;
-
-       input [5:0] B1ADDR;
-       input B1DATA;
-       input B1EN;
-
-       RAM64M #(
-               .INIT_A(INIT),
-               .INIT_B(INIT),
-               .INIT_C(INIT),
-               .INIT_D(INIT),
-               .IS_WCLK_INVERTED(!CLKPOL2)
-       ) _TECHMAP_REPLACE_ (
-               .ADDRA(A1ADDR),
-               .ADDRB(A2ADDR),
-               .ADDRC(A3ADDR),
-               .DOA(A1DATA),
-               .DOB(A2DATA),
-               .DOC(A3DATA),
-
-               .ADDRD(B1ADDR),
-               .DIA(B1DATA),
-               .DIB(B1DATA),
-               .DIC(B1DATA),
-               .DID(B1DATA),
-               .WCLK(CLK1),
-               .WE(B1EN)
-       );
-endmodule
diff --git a/techlibs/xilinx/lutrams_xc5v.txt b/techlibs/xilinx/lutrams_xc5v.txt
new file mode 100644 (file)
index 0000000..8ab8076
--- /dev/null
@@ -0,0 +1,100 @@
+# LUT RAMs for Virtex 5, Virtex 6, Spartan 6, Series 7.
+# The corresponding mapping file is lutrams_xc5v_map.v
+
+# Single-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_SP_ {
+       cost 8;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 8 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 4 global;
+       }
+       option "ABITS" 7 {
+               abits 7;
+               widths 2 global;
+       }
+       option "ABITS" 8 {
+               abits 8;
+               widths 1 global;
+       }
+       init no_undef;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+}
+
+# Dual-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_DP_ {
+       cost 8;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 4 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 2 global;
+       }
+       option "ABITS" 7 {
+               abits 7;
+               widths 1 global;
+       }
+       init no_undef;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
+
+# Quad-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_QP_ {
+       cost 7;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 2 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 1 global;
+       }
+       init no_undef;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R0" "R1" "R2" {
+       }
+}
+
+# Simple dual port RAMs.
+
+ram distributed $__XILINX_LUTRAM_SDP_ {
+       cost 8;
+       widthscale 7;
+       option "ABITS" 5 {
+               abits 5;
+               widths 6 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 3 global;
+       }
+       init no_undef;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
diff --git a/techlibs/xilinx/lutrams_xc5v_map.v b/techlibs/xilinx/lutrams_xc5v_map.v
new file mode 100644 (file)
index 0000000..18ce3a5
--- /dev/null
@@ -0,0 +1,901 @@
+// LUT RAMs for Virtex 5, Virtex 6, Spartan 6, Series 7, Ultrascale.
+// The definitions are in lutrams_xc5v.txt (everything but Ultrascale)
+// and lutrams_xcu.txt (Ultrascale).
+
+
+module $__XILINX_LUTRAM_SP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 5;
+parameter WIDTH = 8;
+parameter BITS_USED = 0;
+
+output [WIDTH-1:0] PORT_RW_RD_DATA;
+input [WIDTH-1:0] PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+function [(1 << OPTION_ABITS)-1:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice[i] = INIT[i * WIDTH + idx];
+endfunction
+
+function [(2 << OPTION_ABITS)-1:0] init_slice2;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice2[2 * i +: 2] = INIT[i * WIDTH + idx * 2 +: 2];
+endfunction
+
+generate
+case(OPTION_ABITS)
+5: if (WIDTH == 8)
+       RAM32M
+       #(
+               .INIT_D(init_slice2(0)),
+               .INIT_C(init_slice2(1)),
+               .INIT_B(init_slice2(2)),
+               .INIT_A(init_slice2(3)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_RW_RD_DATA[7:6]),
+               .DOB(PORT_RW_RD_DATA[5:4]),
+               .DOC(PORT_RW_RD_DATA[3:2]),
+               .DOD(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[7:6]),
+               .DIB(PORT_RW_WR_DATA[5:4]),
+               .DIC(PORT_RW_WR_DATA[3:2]),
+               .DID(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_RW_ADDR),
+               .ADDRB(PORT_RW_ADDR),
+               .ADDRC(PORT_RW_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+else
+       RAM32M16
+       #(
+               .INIT_H(init_slice2(0)),
+               .INIT_G(init_slice2(1)),
+               .INIT_F(init_slice2(2)),
+               .INIT_E(init_slice2(3)),
+               .INIT_D(init_slice2(4)),
+               .INIT_C(init_slice2(5)),
+               .INIT_B(init_slice2(6)),
+               .INIT_A(init_slice2(7)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_RW_RD_DATA[15:14]),
+               .DOB(PORT_RW_RD_DATA[13:12]),
+               .DOC(PORT_RW_RD_DATA[11:10]),
+               .DOD(PORT_RW_RD_DATA[9:8]),
+               .DOE(PORT_RW_RD_DATA[7:6]),
+               .DOF(PORT_RW_RD_DATA[5:4]),
+               .DOG(PORT_RW_RD_DATA[3:2]),
+               .DOH(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[15:14]),
+               .DIB(PORT_RW_WR_DATA[13:12]),
+               .DIC(PORT_RW_WR_DATA[11:10]),
+               .DID(PORT_RW_WR_DATA[9:8]),
+               .DIE(PORT_RW_WR_DATA[7:6]),
+               .DIF(PORT_RW_WR_DATA[5:4]),
+               .DIG(PORT_RW_WR_DATA[3:2]),
+               .DIH(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_RW_ADDR),
+               .ADDRB(PORT_RW_ADDR),
+               .ADDRC(PORT_RW_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .ADDRE(PORT_RW_ADDR),
+               .ADDRF(PORT_RW_ADDR),
+               .ADDRG(PORT_RW_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+6: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM64X1S
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A0(PORT_RW_ADDR[0]),
+                               .A1(PORT_RW_ADDR[1]),
+                               .A2(PORT_RW_ADDR[2]),
+                               .A3(PORT_RW_ADDR[3]),
+                               .A4(PORT_RW_ADDR[4]),
+                               .A5(PORT_RW_ADDR[5]),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .O(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                       );
+end
+7: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM128X1S
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A0(PORT_RW_ADDR[0]),
+                               .A1(PORT_RW_ADDR[1]),
+                               .A2(PORT_RW_ADDR[2]),
+                               .A3(PORT_RW_ADDR[3]),
+                               .A4(PORT_RW_ADDR[4]),
+                               .A5(PORT_RW_ADDR[5]),
+                               .A6(PORT_RW_ADDR[6]),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .O(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                       );
+end
+8: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM256X1S
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A(PORT_RW_ADDR),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .O(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                       );
+end
+9: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM512X1S
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A(PORT_RW_ADDR),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .O(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                       );
+end
+default:
+       $error("invalid OPTION_ABITS/WIDTH combination");
+endcase
+endgenerate
+
+endmodule
+
+
+module $__XILINX_LUTRAM_DP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 5;
+parameter WIDTH = 4;
+parameter BITS_USED = 0;
+
+output [WIDTH-1:0] PORT_RW_RD_DATA;
+input [WIDTH-1:0] PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+output [WIDTH-1:0] PORT_R_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R_ADDR;
+
+function [(1 << OPTION_ABITS)-1:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice[i] = INIT[i * WIDTH + idx];
+endfunction
+
+function [(2 << OPTION_ABITS)-1:0] init_slice2;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice2[2 * i +: 2] = INIT[i * WIDTH + idx * 2 +: 2];
+endfunction
+
+generate
+case (OPTION_ABITS)
+5: if (WIDTH == 4)
+       RAM32M
+       #(
+               .INIT_D(init_slice2(0)),
+               .INIT_C(init_slice2(0)),
+               .INIT_B(init_slice2(1)),
+               .INIT_A(init_slice2(1)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[3:2]),
+               .DOB(PORT_RW_RD_DATA[3:2]),
+               .DOC(PORT_R_RD_DATA[1:0]),
+               .DOD(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[3:2]),
+               .DIB(PORT_RW_WR_DATA[3:2]),
+               .DIC(PORT_RW_WR_DATA[1:0]),
+               .DID(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_RW_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+else
+       RAM32M16
+       #(
+               .INIT_H(init_slice2(0)),
+               .INIT_G(init_slice2(0)),
+               .INIT_F(init_slice2(1)),
+               .INIT_E(init_slice2(1)),
+               .INIT_D(init_slice2(2)),
+               .INIT_C(init_slice2(2)),
+               .INIT_B(init_slice2(3)),
+               .INIT_A(init_slice2(3)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[7:6]),
+               .DOB(PORT_RW_RD_DATA[7:6]),
+               .DOC(PORT_R_RD_DATA[5:4]),
+               .DOD(PORT_RW_RD_DATA[5:4]),
+               .DOE(PORT_R_RD_DATA[3:2]),
+               .DOF(PORT_RW_RD_DATA[3:2]),
+               .DOG(PORT_R_RD_DATA[1:0]),
+               .DOH(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[7:6]),
+               .DIB(PORT_RW_WR_DATA[7:6]),
+               .DIC(PORT_RW_WR_DATA[5:4]),
+               .DID(PORT_RW_WR_DATA[5:4]),
+               .DIE(PORT_RW_WR_DATA[3:2]),
+               .DIF(PORT_RW_WR_DATA[3:2]),
+               .DIG(PORT_RW_WR_DATA[1:0]),
+               .DIH(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_RW_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .ADDRE(PORT_R_ADDR),
+               .ADDRF(PORT_RW_ADDR),
+               .ADDRG(PORT_R_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+6: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM64X1D
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A0(PORT_RW_ADDR[0]),
+                               .A1(PORT_RW_ADDR[1]),
+                               .A2(PORT_RW_ADDR[2]),
+                               .A3(PORT_RW_ADDR[3]),
+                               .A4(PORT_RW_ADDR[4]),
+                               .A5(PORT_RW_ADDR[5]),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .SPO(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                               .DPRA0(PORT_R_ADDR[0]),
+                               .DPRA1(PORT_R_ADDR[1]),
+                               .DPRA2(PORT_R_ADDR[2]),
+                               .DPRA3(PORT_R_ADDR[3]),
+                               .DPRA4(PORT_R_ADDR[4]),
+                               .DPRA5(PORT_R_ADDR[5]),
+                               .DPO(PORT_R_RD_DATA[i]),
+                       );
+end
+7: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM128X1D
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A(PORT_RW_ADDR),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .SPO(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                               .DPRA(PORT_R_ADDR),
+                               .DPO(PORT_R_RD_DATA[i]),
+                       );
+end
+8: begin
+       genvar i;
+       for (i = 0; i < WIDTH; i = i + 1)
+               if (BITS_USED[i])
+                       RAM256X1D
+                       #(
+                               .INIT(init_slice(i)),
+                       )
+                       slice
+                       (
+                               .A(PORT_RW_ADDR),
+                               .D(PORT_RW_WR_DATA[i]),
+                               .SPO(PORT_RW_RD_DATA[i]),
+                               .WE(PORT_RW_WR_EN),
+                               .WCLK(PORT_RW_CLK),
+                               .DPRA(PORT_R_ADDR),
+                               .DPO(PORT_R_RD_DATA[i]),
+                       );
+end
+default:
+       $error("invalid OPTION_ABITS/WIDTH combination");
+endcase
+endgenerate
+
+endmodule
+
+
+module $__XILINX_LUTRAM_QP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 5;
+parameter WIDTH = 2;
+parameter BITS_USED = 0;
+
+output [WIDTH-1:0] PORT_RW_RD_DATA;
+input [WIDTH-1:0] PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+output [WIDTH-1:0] PORT_R0_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R0_ADDR;
+output [WIDTH-1:0] PORT_R1_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R1_ADDR;
+output [WIDTH-1:0] PORT_R2_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R2_ADDR;
+
+function [(1 << OPTION_ABITS)-1:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice[i] = INIT[i * WIDTH + idx];
+endfunction
+
+function [(2 << OPTION_ABITS)-1:0] init_slice2;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice2[2 * i +: 2] = INIT[i * WIDTH + idx * 2 +: 2];
+endfunction
+
+generate
+case (OPTION_ABITS)
+5: if (WIDTH == 2)
+       RAM32M
+       #(
+               .INIT_D(init_slice2(0)),
+               .INIT_C(init_slice2(0)),
+               .INIT_B(init_slice2(0)),
+               .INIT_A(init_slice2(0)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R2_RD_DATA[1:0]),
+               .DOB(PORT_R1_RD_DATA[1:0]),
+               .DOC(PORT_R0_RD_DATA[1:0]),
+               .DOD(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[1:0]),
+               .DIB(PORT_RW_WR_DATA[1:0]),
+               .DIC(PORT_RW_WR_DATA[1:0]),
+               .DID(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_R2_ADDR),
+               .ADDRB(PORT_R1_ADDR),
+               .ADDRC(PORT_R0_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+else
+       RAM32M16
+       #(
+               .INIT_H(init_slice2(0)),
+               .INIT_G(init_slice2(0)),
+               .INIT_F(init_slice2(0)),
+               .INIT_E(init_slice2(0)),
+               .INIT_D(init_slice2(1)),
+               .INIT_C(init_slice2(1)),
+               .INIT_B(init_slice2(1)),
+               .INIT_A(init_slice2(1)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R2_RD_DATA[3:2]),
+               .DOB(PORT_R1_RD_DATA[3:2]),
+               .DOC(PORT_R0_RD_DATA[3:2]),
+               .DOD(PORT_RW_RD_DATA[3:2]),
+               .DOE(PORT_R2_RD_DATA[1:0]),
+               .DOF(PORT_R1_RD_DATA[1:0]),
+               .DOG(PORT_R0_RD_DATA[1:0]),
+               .DOH(PORT_RW_RD_DATA[1:0]),
+               .DIA(PORT_RW_WR_DATA[3:2]),
+               .DIB(PORT_RW_WR_DATA[3:2]),
+               .DIC(PORT_RW_WR_DATA[3:2]),
+               .DID(PORT_RW_WR_DATA[3:2]),
+               .DIE(PORT_RW_WR_DATA[1:0]),
+               .DIF(PORT_RW_WR_DATA[1:0]),
+               .DIG(PORT_RW_WR_DATA[1:0]),
+               .DIH(PORT_RW_WR_DATA[1:0]),
+               .ADDRA(PORT_R2_ADDR),
+               .ADDRB(PORT_R1_ADDR),
+               .ADDRC(PORT_R0_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .ADDRE(PORT_R2_ADDR),
+               .ADDRF(PORT_R1_ADDR),
+               .ADDRG(PORT_R0_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+6: if (WIDTH == 1)
+       RAM64M
+       #(
+               .INIT_D(init_slice(0)),
+               .INIT_C(init_slice(0)),
+               .INIT_B(init_slice(0)),
+               .INIT_A(init_slice(0)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R2_RD_DATA[0]),
+               .DOB(PORT_R1_RD_DATA[0]),
+               .DOC(PORT_R0_RD_DATA[0]),
+               .DOD(PORT_RW_RD_DATA[0]),
+               .DIA(PORT_RW_WR_DATA[0]),
+               .DIB(PORT_RW_WR_DATA[0]),
+               .DIC(PORT_RW_WR_DATA[0]),
+               .DID(PORT_RW_WR_DATA[0]),
+               .ADDRA(PORT_R2_ADDR),
+               .ADDRB(PORT_R1_ADDR),
+               .ADDRC(PORT_R0_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+else
+       RAM64M8
+       #(
+               .INIT_H(init_slice(0)),
+               .INIT_G(init_slice(0)),
+               .INIT_F(init_slice(0)),
+               .INIT_E(init_slice(0)),
+               .INIT_D(init_slice(1)),
+               .INIT_C(init_slice(1)),
+               .INIT_B(init_slice(1)),
+               .INIT_A(init_slice(1)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R2_RD_DATA[1]),
+               .DOB(PORT_R1_RD_DATA[1]),
+               .DOC(PORT_R0_RD_DATA[1]),
+               .DOD(PORT_RW_RD_DATA[1]),
+               .DOE(PORT_R2_RD_DATA[0]),
+               .DOF(PORT_R1_RD_DATA[0]),
+               .DOG(PORT_R0_RD_DATA[0]),
+               .DOH(PORT_RW_RD_DATA[0]),
+               .DIA(PORT_RW_WR_DATA[1]),
+               .DIB(PORT_RW_WR_DATA[1]),
+               .DIC(PORT_RW_WR_DATA[1]),
+               .DID(PORT_RW_WR_DATA[1]),
+               .DIE(PORT_RW_WR_DATA[0]),
+               .DIF(PORT_RW_WR_DATA[0]),
+               .DIG(PORT_RW_WR_DATA[0]),
+               .DIH(PORT_RW_WR_DATA[0]),
+               .ADDRA(PORT_R2_ADDR),
+               .ADDRB(PORT_R1_ADDR),
+               .ADDRC(PORT_R0_ADDR),
+               .ADDRD(PORT_RW_ADDR),
+               .ADDRE(PORT_R2_ADDR),
+               .ADDRF(PORT_R1_ADDR),
+               .ADDRG(PORT_R0_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+default:
+       $error("invalid OPTION_ABITS/WIDTH combination");
+endcase
+endgenerate
+
+endmodule
+
+
+module $__XILINX_LUTRAM_OP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 5;
+parameter WIDTH = 2;
+parameter BITS_USED = 0;
+
+output [WIDTH-1:0] PORT_RW_RD_DATA;
+input [WIDTH-1:0] PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+output [WIDTH-1:0] PORT_R0_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R0_ADDR;
+output [WIDTH-1:0] PORT_R1_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R1_ADDR;
+output [WIDTH-1:0] PORT_R2_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R2_ADDR;
+output [WIDTH-1:0] PORT_R3_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R3_ADDR;
+output [WIDTH-1:0] PORT_R4_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R4_ADDR;
+output [WIDTH-1:0] PORT_R5_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R5_ADDR;
+output [WIDTH-1:0] PORT_R6_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R6_ADDR;
+
+generate
+case (OPTION_ABITS)
+5:     RAM32M16
+       #(
+               .INIT_H(INIT),
+               .INIT_G(INIT),
+               .INIT_F(INIT),
+               .INIT_E(INIT),
+               .INIT_D(INIT),
+               .INIT_C(INIT),
+               .INIT_B(INIT),
+               .INIT_A(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R6_RD_DATA),
+               .DOB(PORT_R5_RD_DATA),
+               .DOC(PORT_R4_RD_DATA),
+               .DOD(PORT_R3_RD_DATA),
+               .DOE(PORT_R2_RD_DATA),
+               .DOF(PORT_R1_RD_DATA),
+               .DOG(PORT_R0_RD_DATA),
+               .DOH(PORT_RW_RD_DATA),
+               .DIA(PORT_RW_WR_DATA),
+               .DIB(PORT_RW_WR_DATA),
+               .DIC(PORT_RW_WR_DATA),
+               .DID(PORT_RW_WR_DATA),
+               .DIE(PORT_RW_WR_DATA),
+               .DIF(PORT_RW_WR_DATA),
+               .DIG(PORT_RW_WR_DATA),
+               .DIH(PORT_RW_WR_DATA),
+               .ADDRA(PORT_R6_ADDR),
+               .ADDRB(PORT_R5_ADDR),
+               .ADDRC(PORT_R4_ADDR),
+               .ADDRD(PORT_R3_ADDR),
+               .ADDRE(PORT_R2_ADDR),
+               .ADDRF(PORT_R1_ADDR),
+               .ADDRG(PORT_R0_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+6:     RAM64M8
+       #(
+               .INIT_H(INIT),
+               .INIT_G(INIT),
+               .INIT_F(INIT),
+               .INIT_E(INIT),
+               .INIT_D(INIT),
+               .INIT_C(INIT),
+               .INIT_B(INIT),
+               .INIT_A(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R6_RD_DATA),
+               .DOB(PORT_R5_RD_DATA),
+               .DOC(PORT_R4_RD_DATA),
+               .DOD(PORT_R3_RD_DATA),
+               .DOE(PORT_R2_RD_DATA),
+               .DOF(PORT_R1_RD_DATA),
+               .DOG(PORT_R0_RD_DATA),
+               .DOH(PORT_RW_RD_DATA),
+               .DIA(PORT_RW_WR_DATA),
+               .DIB(PORT_RW_WR_DATA),
+               .DIC(PORT_RW_WR_DATA),
+               .DID(PORT_RW_WR_DATA),
+               .DIE(PORT_RW_WR_DATA),
+               .DIF(PORT_RW_WR_DATA),
+               .DIG(PORT_RW_WR_DATA),
+               .DIH(PORT_RW_WR_DATA),
+               .ADDRA(PORT_R6_ADDR),
+               .ADDRB(PORT_R5_ADDR),
+               .ADDRC(PORT_R4_ADDR),
+               .ADDRD(PORT_R3_ADDR),
+               .ADDRE(PORT_R2_ADDR),
+               .ADDRF(PORT_R1_ADDR),
+               .ADDRG(PORT_R0_ADDR),
+               .ADDRH(PORT_RW_ADDR),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+default:
+       $error("invalid OPTION_ABITS/WIDTH combination");
+endcase
+endgenerate
+
+endmodule
+
+
+module $__XILINX_LUTRAM_SDP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 5;
+parameter WIDTH = 6;
+parameter BITS_USED = 0;
+
+input [WIDTH-1:0] PORT_W_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_W_ADDR;
+input PORT_W_WR_EN;
+input PORT_W_CLK;
+
+output [WIDTH-1:0] PORT_R_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R_ADDR;
+
+function [(1 << OPTION_ABITS)-1:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice[i] = INIT[i * WIDTH + idx];
+endfunction
+
+function [(2 << OPTION_ABITS)-1:0] init_slice2;
+       input integer idx;
+       integer i;
+       for (i = 0; i < (1 << OPTION_ABITS); i = i + 1)
+               init_slice2[2 * i +: 2] = INIT[i * WIDTH + idx * 2 +: 2];
+endfunction
+
+generate
+case (OPTION_ABITS)
+5: if (WIDTH == 6)
+       RAM32M
+       #(
+               .INIT_C(init_slice2(0)),
+               .INIT_B(init_slice2(1)),
+               .INIT_A(init_slice2(2)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[5:4]),
+               .DOB(PORT_R_RD_DATA[3:2]),
+               .DOC(PORT_R_RD_DATA[1:0]),
+               .DIA(PORT_W_WR_DATA[5:4]),
+               .DIB(PORT_W_WR_DATA[3:2]),
+               .DIC(PORT_W_WR_DATA[1:0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_R_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_W_ADDR),
+               .WE(PORT_W_WR_EN),
+               .WCLK(PORT_W_CLK),
+       );
+else
+       RAM32M16
+       #(
+               .INIT_G(init_slice2(0)),
+               .INIT_F(init_slice2(1)),
+               .INIT_E(init_slice2(2)),
+               .INIT_D(init_slice2(3)),
+               .INIT_C(init_slice2(4)),
+               .INIT_B(init_slice2(5)),
+               .INIT_A(init_slice2(6)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[13:12]),
+               .DOB(PORT_R_RD_DATA[11:10]),
+               .DOC(PORT_R_RD_DATA[9:8]),
+               .DOD(PORT_R_RD_DATA[7:6]),
+               .DOE(PORT_R_RD_DATA[5:4]),
+               .DOF(PORT_R_RD_DATA[3:2]),
+               .DOG(PORT_R_RD_DATA[1:0]),
+               .DIA(PORT_W_WR_DATA[13:12]),
+               .DIB(PORT_W_WR_DATA[11:10]),
+               .DIC(PORT_W_WR_DATA[9:8]),
+               .DID(PORT_W_WR_DATA[7:6]),
+               .DIE(PORT_W_WR_DATA[5:4]),
+               .DIF(PORT_W_WR_DATA[3:2]),
+               .DIG(PORT_W_WR_DATA[1:0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_R_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_R_ADDR),
+               .ADDRE(PORT_R_ADDR),
+               .ADDRF(PORT_R_ADDR),
+               .ADDRG(PORT_R_ADDR),
+               .ADDRH(PORT_W_ADDR),
+               .WE(PORT_W_WR_EN),
+               .WCLK(PORT_W_CLK),
+       );
+6: if (WIDTH == 3)
+       RAM64M
+       #(
+               .INIT_C(init_slice(0)),
+               .INIT_B(init_slice(1)),
+               .INIT_A(init_slice(2)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[2]),
+               .DOB(PORT_R_RD_DATA[1]),
+               .DOC(PORT_R_RD_DATA[0]),
+               .DIA(PORT_W_WR_DATA[2]),
+               .DIB(PORT_W_WR_DATA[1]),
+               .DIC(PORT_W_WR_DATA[0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_R_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_W_ADDR),
+               .WE(PORT_W_WR_EN),
+               .WCLK(PORT_W_CLK),
+       );
+else
+       RAM64M8
+       #(
+               .INIT_G(init_slice(0)),
+               .INIT_F(init_slice(1)),
+               .INIT_E(init_slice(2)),
+               .INIT_D(init_slice(3)),
+               .INIT_C(init_slice(4)),
+               .INIT_B(init_slice(5)),
+               .INIT_A(init_slice(6)),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .DOA(PORT_R_RD_DATA[6]),
+               .DOB(PORT_R_RD_DATA[5]),
+               .DOC(PORT_R_RD_DATA[4]),
+               .DOD(PORT_R_RD_DATA[3]),
+               .DOE(PORT_R_RD_DATA[2]),
+               .DOF(PORT_R_RD_DATA[1]),
+               .DOG(PORT_R_RD_DATA[0]),
+               .DIA(PORT_W_WR_DATA[6]),
+               .DIB(PORT_W_WR_DATA[5]),
+               .DIC(PORT_W_WR_DATA[4]),
+               .DID(PORT_W_WR_DATA[3]),
+               .DIE(PORT_W_WR_DATA[2]),
+               .DIF(PORT_W_WR_DATA[1]),
+               .DIG(PORT_W_WR_DATA[0]),
+               .ADDRA(PORT_R_ADDR),
+               .ADDRB(PORT_R_ADDR),
+               .ADDRC(PORT_R_ADDR),
+               .ADDRD(PORT_R_ADDR),
+               .ADDRE(PORT_R_ADDR),
+               .ADDRF(PORT_R_ADDR),
+               .ADDRG(PORT_R_ADDR),
+               .ADDRH(PORT_W_ADDR),
+               .WE(PORT_W_WR_EN),
+               .WCLK(PORT_W_CLK),
+       );
+default:
+       $error("invalid OPTION_ABITS/WIDTH combination");
+endcase
+endgenerate
+
+endmodule
+
+
+module $__XILINX_LUTRAM_64X8SW_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 9;
+parameter PORT_RW_WR_WIDTH = 1;
+parameter PORT_RW_RD_WIDTH = 8;
+
+output [PORT_RW_RD_WIDTH-1:0] PORT_RW_RD_DATA;
+input [PORT_RW_WR_WIDTH-1:0] PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+function [63:0] init_slice;
+       input integer idx;
+       integer i;
+       for (i = 0; i < 64; i = i + 1)
+               init_slice[i] = INIT[i * 8 + idx];
+endfunction
+
+RAM64X8SW
+#(
+       .INIT_A(init_slice(7)),
+       .INIT_B(init_slice(6)),
+       .INIT_C(init_slice(5)),
+       .INIT_D(init_slice(4)),
+       .INIT_E(init_slice(3)),
+       .INIT_F(init_slice(2)),
+       .INIT_G(init_slice(1)),
+       .INIT_H(init_slice(0)),
+)
+_TECHMAP_REPLACE_
+(
+       .A(PORT_RW_ADDR[8:3]),
+       .WSEL(PORT_RW_ADDR[2:0]),
+       .D(PORT_RW_WR_DATA),
+       .O(PORT_RW_RD_DATA),
+       .WE(PORT_RW_WR_EN),
+       .WCLK(PORT_RW_CLK),
+);
+
+endmodule
+
+
+module $__XILINX_LUTRAM_32X16DR8_ (...);
+
+parameter OPTION_ABITS = 6;
+parameter BITS_USED = 0;
+parameter PORT_W_WIDTH = 14;
+parameter PORT_R_WIDTH = 7;
+
+input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_W_ADDR;
+input PORT_W_WR_EN;
+input PORT_W_CLK;
+
+output [PORT_R_WIDTH-1:0] PORT_R_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R_ADDR;
+
+RAM32X16DR8 _TECHMAP_REPLACE_
+(
+       .DOA(PORT_R_RD_DATA[6]),
+       .DOB(PORT_R_RD_DATA[5]),
+       .DOC(PORT_R_RD_DATA[4]),
+       .DOD(PORT_R_RD_DATA[3]),
+       .DOE(PORT_R_RD_DATA[2]),
+       .DOF(PORT_R_RD_DATA[1]),
+       .DOG(PORT_R_RD_DATA[0]),
+       .DIA({PORT_W_WR_DATA[13], PORT_W_WR_DATA[6]}),
+       .DIB({PORT_W_WR_DATA[12], PORT_W_WR_DATA[5]}),
+       .DIC({PORT_W_WR_DATA[11], PORT_W_WR_DATA[4]}),
+       .DID({PORT_W_WR_DATA[10], PORT_W_WR_DATA[3]}),
+       .DIE({PORT_W_WR_DATA[9], PORT_W_WR_DATA[2]}),
+       .DIF({PORT_W_WR_DATA[8], PORT_W_WR_DATA[1]}),
+       .DIG({PORT_W_WR_DATA[7], PORT_W_WR_DATA[0]}),
+       .ADDRA(PORT_R_ADDR),
+       .ADDRB(PORT_R_ADDR),
+       .ADDRC(PORT_R_ADDR),
+       .ADDRD(PORT_R_ADDR),
+       .ADDRE(PORT_R_ADDR),
+       .ADDRF(PORT_R_ADDR),
+       .ADDRG(PORT_R_ADDR),
+       .ADDRH(PORT_W_ADDR[5:1]),
+       .WE(PORT_W_WR_EN),
+       .WCLK(PORT_W_CLK),
+);
+
+endmodule
diff --git a/techlibs/xilinx/lutrams_xcu.txt b/techlibs/xilinx/lutrams_xcu.txt
new file mode 100644 (file)
index 0000000..8062250
--- /dev/null
@@ -0,0 +1,162 @@
+# LUT RAMs for Ultrascale.
+# The corresponding mapping file is lutrams_xc5v_map.v
+
+# Single-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_SP_ {
+       cost 16;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 16 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 8 global;
+       }
+       option "ABITS" 7 {
+               abits 7;
+               widths 4 global;
+       }
+       option "ABITS" 8 {
+               abits 8;
+               widths 2 global;
+       }
+       option "ABITS" 16 {
+               abits 16;
+               widths 1 global;
+       }
+       init any;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+}
+
+# Dual-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_DP_ {
+       cost 16;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 8 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 4 global;
+       }
+       option "ABITS" 7 {
+               abits 7;
+               widths 2 global;
+       }
+       option "ABITS" 8 {
+               abits 8;
+               widths 1 global;
+       }
+       init any;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
+
+# Quad-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_QP_ {
+       cost 16;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 4 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 2 global;
+       }
+       init any;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R0" "R1" "R2" {
+       }
+}
+
+# Octal-port RAMs.
+
+ram distributed $__XILINX_LUTRAM_OP_ {
+       cost 16;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 2 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 1 global;
+       }
+       init any;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R0" "R1" "R2" "R3" "R4" "R5" "R6" {
+       }
+}
+
+# Simple dual port RAMs.
+
+ram distributed $__XILINX_LUTRAM_SDP_ {
+       cost 16;
+       widthscale;
+       option "ABITS" 5 {
+               abits 5;
+               widths 14 global;
+       }
+       option "ABITS" 6 {
+               abits 6;
+               widths 7 global;
+       }
+       init any;
+       prune_rom;
+       port sw "W" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
+
+# Wide-read RAM.
+
+ram distributed $__XILINX_LUTRAM_64X8SW_ {
+       cost 16;
+       abits 9;
+       widths 1 2 4 8 per_port;
+       init any;
+       prune_rom;
+       port arsw "RW" {
+               width rd 8 wr 1;
+               clock posedge;
+       }
+}
+
+# Wide-write RAM.
+
+ram distributed $__XILINX_LUTRAM_32X16DR8_ {
+       cost 16;
+       widthscale;
+       abits 6;
+       widths 7 14 per_port;
+       # Yes, no initialization capability.
+       prune_rom;
+       port sw "W" {
+               width 14;
+               clock posedge;
+       }
+       port ar "R" {
+               width 7;
+       }
+}
diff --git a/techlibs/xilinx/lutrams_xcv.txt b/techlibs/xilinx/lutrams_xcv.txt
new file mode 100644 (file)
index 0000000..0bf17ae
--- /dev/null
@@ -0,0 +1,59 @@
+# LUT RAMs for Virtex, Virtex 2, Spartan 3, Virtex 4.
+# The corresponding mapping file is lutrams_xcv_map.v
+
+ram distributed $__XILINX_LUTRAM_SP_ {
+       width 1;
+       option "ABITS" 4 {
+               abits 4;
+               cost 3;
+       }
+       option "ABITS" 5 {
+               abits 5;
+               cost 5;
+       }
+       ifndef IS_VIRTEX {
+               option "ABITS" 6 {
+                       abits 6;
+                       cost 9;
+               }
+       }
+       ifdef IS_VIRTEX2 {
+               # RAM128X1S
+               option "ABITS" 7 {
+                       abits 7;
+                       cost 17;
+               }
+       }
+       init no_undef;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+}
+
+ram distributed $__XILINX_LUTRAM_DP_ {
+       width 1;
+       option "ABITS" 4 {
+               abits 4;
+               cost 5;
+       }
+       ifdef IS_VIRTEX2 {
+               # RAM32X1D
+               option "ABITS" 5 {
+                       abits 5;
+                       cost 9;
+               }
+               # RAM64X1D
+               option "ABITS" 6 {
+                       abits 6;
+                       cost 17;
+               }
+       }
+       init no_undef;
+       prune_rom;
+       port arsw "RW" {
+               clock posedge;
+       }
+       port ar "R" {
+       }
+}
diff --git a/techlibs/xilinx/lutrams_xcv_map.v b/techlibs/xilinx/lutrams_xcv_map.v
new file mode 100644 (file)
index 0000000..91a9694
--- /dev/null
@@ -0,0 +1,177 @@
+// LUT RAMs for Virtex, Virtex 2, Spartan 3, Virtex 4.
+// The corresponding definition file is lutrams_xcv.txt
+
+module $__XILINX_LUTRAM_SP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 4;
+
+output PORT_RW_RD_DATA;
+input PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+generate
+case(OPTION_ABITS)
+4: RAM16X1S
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .D(PORT_RW_WR_DATA),
+               .O(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+5: RAM32X1S
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .A4(PORT_RW_ADDR[4]),
+               .D(PORT_RW_WR_DATA),
+               .O(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+6: RAM64X1S
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .A4(PORT_RW_ADDR[4]),
+               .A5(PORT_RW_ADDR[5]),
+               .D(PORT_RW_WR_DATA),
+               .O(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+7: RAM128X1S
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .A4(PORT_RW_ADDR[4]),
+               .A5(PORT_RW_ADDR[5]),
+               .A6(PORT_RW_ADDR[6]),
+               .D(PORT_RW_WR_DATA),
+               .O(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+       );
+default:
+       $error("invalid OPTION_ABITS");
+endcase
+endgenerate
+
+endmodule
+
+module $__XILINX_LUTRAM_DP_ (...);
+
+parameter INIT = 0;
+parameter OPTION_ABITS = 4;
+
+output PORT_RW_RD_DATA;
+input PORT_RW_WR_DATA;
+input [OPTION_ABITS-1:0] PORT_RW_ADDR;
+input PORT_RW_WR_EN;
+input PORT_RW_CLK;
+
+output PORT_R_RD_DATA;
+input [OPTION_ABITS-1:0] PORT_R_ADDR;
+
+generate
+case (OPTION_ABITS)
+4: RAM16X1D
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .D(PORT_RW_WR_DATA),
+               .SPO(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+               .DPRA0(PORT_R_ADDR[0]),
+               .DPRA1(PORT_R_ADDR[1]),
+               .DPRA2(PORT_R_ADDR[2]),
+               .DPRA3(PORT_R_ADDR[3]),
+               .DPO(PORT_R_RD_DATA),
+       );
+5: RAM32X1D
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .A4(PORT_RW_ADDR[4]),
+               .D(PORT_RW_WR_DATA),
+               .SPO(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+               .DPRA0(PORT_R_ADDR[0]),
+               .DPRA1(PORT_R_ADDR[1]),
+               .DPRA2(PORT_R_ADDR[2]),
+               .DPRA3(PORT_R_ADDR[3]),
+               .DPRA4(PORT_R_ADDR[4]),
+               .DPO(PORT_R_RD_DATA),
+       );
+6: RAM64X1D
+       #(
+               .INIT(INIT),
+       )
+       _TECHMAP_REPLACE_
+       (
+               .A0(PORT_RW_ADDR[0]),
+               .A1(PORT_RW_ADDR[1]),
+               .A2(PORT_RW_ADDR[2]),
+               .A3(PORT_RW_ADDR[3]),
+               .A4(PORT_RW_ADDR[4]),
+               .A5(PORT_RW_ADDR[5]),
+               .D(PORT_RW_WR_DATA),
+               .SPO(PORT_RW_RD_DATA),
+               .WE(PORT_RW_WR_EN),
+               .WCLK(PORT_RW_CLK),
+               .DPRA0(PORT_R_ADDR[0]),
+               .DPRA1(PORT_R_ADDR[1]),
+               .DPRA2(PORT_R_ADDR[2]),
+               .DPRA3(PORT_R_ADDR[3]),
+               .DPRA4(PORT_R_ADDR[4]),
+               .DPRA5(PORT_R_ADDR[5]),
+               .DPO(PORT_R_RD_DATA),
+       );
+default:
+       $error("invalid OPTION_ABITS");
+endcase
+endgenerate
+
+endmodule
index 6a060c8fee6c9060fca4a5b1aa575ccfd2b85263..6214e1411ced77ce75ed1540ab57ca413cbce070 100644 (file)
@@ -450,56 +450,97 @@ struct SynthXilinxPass : public ScriptPass
                        run("opt_clean");
                }
 
-               if (check_label("map_uram", "(only if '-uram')")) {
+               if (check_label("map_memory")) {
+                       std::string params = "";
+                       std::string lutrams_map = "+/xilinx/lutrams_<family>_map.v";
+                       std::string brams_map = "+/xilinx/brams_<family>_map.v";
                        if (help_mode) {
-                               run("memory_bram -rules +/xilinx/{family}_urams.txt");
-                               run("techmap -map +/xilinx/{family}_urams_map.v");
-                       } else if (uram) {
-                               if (family == "xcup") {
-                                       run("memory_bram -rules +/xilinx/xcup_urams.txt");
-                                       run("techmap -map +/xilinx/xcup_urams_map.v");
-                               } else {
-                                       log_warning("UltraRAM inference not supported for family %s.\n", family.c_str());
-                               }
-                       }
-               }
-
-               if (check_label("map_bram", "(skip if '-nobram')")) {
-                       if (help_mode) {
-                               run("memory_bram -rules +/xilinx/{family}_brams.txt");
-                               run("techmap -map +/xilinx/{family}_brams_map.v");
-                       } else if (!nobram) {
-                               if (family == "xc2v" || family == "xc2vp" || family == "xc3s" || family == "xc3se") {
-                                       run("memory_bram -rules +/xilinx/xc2v_brams.txt");
-                                       run("techmap -map +/xilinx/xc2v_brams_map.v");
+                               params = " [...]";
+                       } else {
+                               if (family == "xcv" || family == "xcve") {
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       params += " -D IS_VIRTEX";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xcv.txt";
+                                       brams_map = "+/xilinx/brams_xcv_map.v";
+                               } else if (family == "xc2v" || family == "xc2vp") {
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       params += " -D IS_VIRTEX2";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xc2v.txt";
+                                       brams_map = "+/xilinx/brams_xc2v_map.v";
+                               } else if (family == "xc3s" || family == "xc3se") {
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xc2v.txt";
+                                       brams_map = "+/xilinx/brams_xc2v_map.v";
                                } else if (family == "xc3sa") {
-                                       // Superset of Virtex 2 primitives â€” uses common map file.
-                                       run("memory_bram -rules +/xilinx/xc3sa_brams.txt");
-                                       run("techmap -map +/xilinx/xc2v_brams_map.v");
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xc2v.txt";
+                                       params += " -D HAS_BE";
+                                       brams_map = "+/xilinx/brams_xc2v_map.v";
                                } else if (family == "xc3sda") {
-                                       // Supported block RAMs for Spartan 3A DSP are
-                                       // a subset of Spartan 6's ones.
-                                       run("memory_bram -rules +/xilinx/xc3sda_brams.txt");
-                                       run("techmap -map +/xilinx/xc6s_brams_map.v");
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xc3sda.txt";
+                                       brams_map = "+/xilinx/brams_xc3sda_map.v";
                                } else if (family == "xc6s") {
-                                       run("memory_bram -rules +/xilinx/xc6s_brams.txt");
-                                       run("techmap -map +/xilinx/xc6s_brams_map.v");
+                                       params += " -logic-cost-rom 0.015625";
+                                       params += " -lib +/xilinx/lutrams_xc5v.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xc5v_map.v";
+                                       params += " -lib +/xilinx/brams_xc3sda.txt";
+                                       params += " -D IS_SPARTAN6";
+                                       brams_map = "+/xilinx/brams_xc3sda_map.v";
+                               } else if (family == "xc4v") {
+                                       params += " -lib +/xilinx/lutrams_xcv.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xcv_map.v";
+                                       params += " -lib +/xilinx/brams_xc4v.txt";
+                                       params += " -D HAS_CASCADE";
+                                       brams_map = "+/xilinx/brams_xc4v_map.v";
+                               } else if (family == "xc5v") {
+                                       params += " -logic-cost-rom 0.015625";
+                                       params += " -lib +/xilinx/lutrams_xc5v.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xc5v_map.v";
+                                       params += " -lib +/xilinx/brams_xc4v.txt";
+                                       params += " -D HAS_SIZE_36";
+                                       params += " -D HAS_CASCADE";
+                                       brams_map = "+/xilinx/brams_xc5v_map.v";
                                } else if (family == "xc6v" || family == "xc7") {
-                                       run("memory_bram -rules +/xilinx/xc7_xcu_brams.txt");
-                                       run("techmap -map +/xilinx/xc7_brams_map.v");
+                                       params += " -logic-cost-rom 0.015625";
+                                       params += " -lib +/xilinx/lutrams_xc5v.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xc5v_map.v";
+                                       params += " -lib +/xilinx/brams_xc4v.txt";
+                                       params += " -D HAS_SIZE_36";
+                                       params += " -D HAS_CASCADE";
+                                       params += " -D HAS_CONFLICT_BUG";
+                                       params += " -D HAS_MIXWIDTH_SDP";
+                                       brams_map = "+/xilinx/brams_xc6v_map.v";
                                } else if (family == "xcu" || family == "xcup") {
-                                       run("memory_bram -rules +/xilinx/xc7_xcu_brams.txt");
-                                       run("techmap -map +/xilinx/xcu_brams_map.v");                                   
-                               } else {
-                                       log_warning("Block RAM inference not yet supported for family %s.\n", family.c_str());
+                                       params += " -logic-cost-rom 0.015625";
+                                       params += " -lib +/xilinx/lutrams_xcu.txt";
+                                       lutrams_map = "+/xilinx/lutrams_xc5v_map.v";
+                                       params += " -lib +/xilinx/brams_xc4v.txt";
+                                       params += " -D HAS_SIZE_36";
+                                       params += " -D HAS_MIXWIDTH_SDP";
+                                       params += " -D HAS_ADDRCE";
+                                       brams_map = "+/xilinx/brams_xcu_map.v";
+                                       if (family == "xcup") {
+                                               params += " -lib +/xilinx/urams.txt";
+                                       }
                                }
-                       }
-               }
-
-               if (check_label("map_lutram", "(skip if '-nolutram')")) {
-                       if (!nolutram || help_mode) {
-                               run("memory_bram -rules +/xilinx/lut" + lut_size_s + "_lutrams.txt");
-                               run("techmap -map +/xilinx/lutrams_map.v");
+                               if (nolutram)
+                                       params += " -no-auto-distributed";
+                               if (nobram)
+                                       params += " -no-auto-block";
+                               if (!uram)
+                                       params += " -no-auto-huge";
+                       }
+                       run("memory_libmap" + params);
+                       run("techmap -map " + lutrams_map);
+                       run("techmap -map " + brams_map);
+                       if (family == "xcup") {
+                               run("techmap -map +/xilinx/urams_map.v");
                        }
                }
 
diff --git a/techlibs/xilinx/urams.txt b/techlibs/xilinx/urams.txt
new file mode 100644 (file)
index 0000000..6a59204
--- /dev/null
@@ -0,0 +1,37 @@
+ram huge $__XILINX_URAM_ {
+       abits 12;
+       width 72;
+       cost 1024;
+       option "BYTEWIDTH" 8 byte 8;
+       option "BYTEWIDTH" 9 byte 9;
+       init zero;
+       port srsw "A" {
+               clock anyedge "C";
+               clken;
+               rdwr no_change;
+               rdinit zero;
+               portoption "RST_MODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               portoption "RST_MODE" "ASYNC" {
+                       rdarst zero;
+               }
+               wrtrans all new;
+               wrbe_separate;
+       }
+       port srsw "B" {
+               clock anyedge "C";
+               clken;
+               rdwr no_change;
+               rdinit zero;
+               portoption "RST_MODE" "SYNC" {
+                       rdsrst zero ungated;
+               }
+               portoption "RST_MODE" "ASYNC" {
+                       rdarst zero;
+               }
+               wrtrans all old;
+               wrprio "A";
+               wrbe_separate;
+       }
+}
diff --git a/techlibs/xilinx/urams_map.v b/techlibs/xilinx/urams_map.v
new file mode 100644 (file)
index 0000000..3ecbe70
--- /dev/null
@@ -0,0 +1,152 @@
+module $__XILINX_URAM_ (...);
+       parameter OPTION_BYTEWIDTH = 8;
+       localparam WR_BE_WIDTH = 72 / OPTION_BYTEWIDTH;
+
+       parameter CLK_C_POL = 1;
+       parameter PORT_A_CLK_POL = 1;
+       parameter PORT_A_OPTION_RST_MODE = "SYNC";
+       parameter PORT_B_CLK_POL = 1;
+       parameter PORT_B_OPTION_RST_MODE = "SYNC";
+
+       input CLK_C;
+
+       input PORT_A_CLK;
+       input PORT_A_CLK_EN;
+       input PORT_A_RD_SRST;
+       input PORT_A_RD_ARST;
+       input PORT_A_WR_EN;
+       input [WR_BE_WIDTH-1:0] PORT_A_WR_BE;
+       input [11:0] PORT_A_ADDR;
+       input [71:0] PORT_A_WR_DATA;
+       output [71:0] PORT_A_RD_DATA;
+
+       input PORT_B_CLK;
+       input PORT_B_CLK_EN;
+       input PORT_B_RD_SRST;
+       input PORT_B_RD_ARST;
+       input PORT_B_WR_EN;
+       input [WR_BE_WIDTH-1:0] PORT_B_WR_BE;
+       input [11:0] PORT_B_ADDR;
+       input [71:0] PORT_B_WR_DATA;
+       output [71:0] PORT_B_RD_DATA;
+
+       wire [71:0] DIN_A, DIN_B, DOUT_A, DOUT_B;
+
+       generate
+               if (OPTION_BYTEWIDTH == 8) begin
+                       assign DIN_A = PORT_A_WR_DATA;
+                       assign DIN_B = PORT_B_WR_DATA;
+                       assign PORT_A_RD_DATA = DOUT_A;
+                       assign PORT_B_RD_DATA = DOUT_B;
+               end else begin
+                       assign DIN_A = {
+                               PORT_A_WR_DATA[71],
+                               PORT_A_WR_DATA[62],
+                               PORT_A_WR_DATA[53],
+                               PORT_A_WR_DATA[44],
+                               PORT_A_WR_DATA[35],
+                               PORT_A_WR_DATA[26],
+                               PORT_A_WR_DATA[17],
+                               PORT_A_WR_DATA[8],
+                               PORT_A_WR_DATA[70:63],
+                               PORT_A_WR_DATA[61:54],
+                               PORT_A_WR_DATA[52:45],
+                               PORT_A_WR_DATA[43:36],
+                               PORT_A_WR_DATA[34:27],
+                               PORT_A_WR_DATA[25:18],
+                               PORT_A_WR_DATA[16:9],
+                               PORT_A_WR_DATA[7:0]
+                       };
+                       assign DIN_B = {
+                               PORT_B_WR_DATA[71],
+                               PORT_B_WR_DATA[62],
+                               PORT_B_WR_DATA[53],
+                               PORT_B_WR_DATA[44],
+                               PORT_B_WR_DATA[35],
+                               PORT_B_WR_DATA[26],
+                               PORT_B_WR_DATA[17],
+                               PORT_B_WR_DATA[8],
+                               PORT_B_WR_DATA[70:63],
+                               PORT_B_WR_DATA[61:54],
+                               PORT_B_WR_DATA[52:45],
+                               PORT_B_WR_DATA[43:36],
+                               PORT_B_WR_DATA[34:27],
+                               PORT_B_WR_DATA[25:18],
+                               PORT_B_WR_DATA[16:9],
+                               PORT_B_WR_DATA[7:0]
+                       };
+                       assign PORT_A_RD_DATA = {
+                               DOUT_A[71],
+                               DOUT_A[63:56],
+                               DOUT_A[70],
+                               DOUT_A[55:48],
+                               DOUT_A[69],
+                               DOUT_A[47:40],
+                               DOUT_A[68],
+                               DOUT_A[39:32],
+                               DOUT_A[67],
+                               DOUT_A[31:24],
+                               DOUT_A[66],
+                               DOUT_A[23:16],
+                               DOUT_A[65],
+                               DOUT_A[15:8],
+                               DOUT_A[64],
+                               DOUT_A[7:0]
+                       };
+                       assign PORT_B_RD_DATA = {
+                               DOUT_B[71],
+                               DOUT_B[63:56],
+                               DOUT_B[70],
+                               DOUT_B[55:48],
+                               DOUT_B[69],
+                               DOUT_B[47:40],
+                               DOUT_B[68],
+                               DOUT_B[39:32],
+                               DOUT_B[67],
+                               DOUT_B[31:24],
+                               DOUT_B[66],
+                               DOUT_B[23:16],
+                               DOUT_B[65],
+                               DOUT_B[15:8],
+                               DOUT_B[64],
+                               DOUT_B[7:0]
+                       };
+               end
+       endgenerate
+
+       URAM288 #(
+               .BWE_MODE_A(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
+               .BWE_MODE_B(OPTION_BYTEWIDTH == 8 ? "PARITY_INDEPENDENT" : "PARITY_INTERLEAVED"),
+               .EN_AUTO_SLEEP_MODE("FALSE"),
+               .IREG_PRE_A("FALSE"),
+               .IREG_PRE_B("FALSE"),
+               .IS_CLK_INVERTED(!CLK_C_POL),
+               .OREG_A("FALSE"),
+               .OREG_B("FALSE"),
+               .RST_MODE_A(PORT_A_OPTION_RST_MODE),
+               .RST_MODE_B(PORT_B_OPTION_RST_MODE),
+       ) _TECHMAP_REPLACE_ (
+               .ADDR_A({11'b0, PORT_A_ADDR}),
+               .BWE_A(PORT_A_WR_BE),
+               .EN_A(PORT_A_CLK_EN),
+               .RDB_WR_A(PORT_A_WR_EN),
+               .INJECT_DBITERR_A(1'b0),
+               .INJECT_SBITERR_A(1'b0),
+               .RST_A(PORT_A_OPTION_RST_MODE == "SYNC" ? PORT_A_RD_SRST : PORT_A_RD_ARST),
+               .DIN_A(DIN_A),
+               .DOUT_A(DOUT_A),
+
+               .ADDR_B({11'b0, PORT_B_ADDR}),
+               .BWE_B(PORT_B_WR_BE),
+               .EN_B(PORT_B_CLK_EN),
+               .RDB_WR_B(PORT_B_WR_EN),
+               .INJECT_DBITERR_B(1'b0),
+               .INJECT_SBITERR_B(1'b0),
+               .RST_B(PORT_B_OPTION_RST_MODE == "SYNC" ? PORT_B_RD_SRST : PORT_B_RD_ARST),
+               .DIN_B(DIN_B),
+               .DOUT_B(DOUT_B),
+
+               .CLK(CLK_C),
+               .SLEEP(1'b0)
+       );
+endmodule
diff --git a/techlibs/xilinx/xc2v_brams.txt b/techlibs/xilinx/xc2v_brams.txt
deleted file mode 100644 (file)
index ac8cfb5..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# Virtex 2, Virtex 2 Pro, Spartan 3, Spartan 3E block RAM rules.
-
-bram $__XILINX_RAMB16
-  init 1
-  abits  9     @a9d36
-  dbits 36     @a9d36
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__XILINX_RAMB16
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-endmatch
diff --git a/techlibs/xilinx/xc2v_brams_map.v b/techlibs/xilinx/xc2v_brams_map.v
deleted file mode 100644 (file)
index dc698f9..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-// Virtex 2, Virtex 2 Pro, Spartan 3, Spartan 3E, Spartan 3A block RAM
-// mapping (Spartan 3A is a superset of the other four).
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB16 (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_B = 1;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       generate if (CFG_DBITS == 1) begin
-               wire DOB;
-               RAMB16_S1_S1 #(
-                       `include "brams_init_16.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(1'd0),
-                       .DOA(A1DATA),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB(B1DATA),
-                       .DOB(DOB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 2) begin
-               wire [1:0] DOB;
-               RAMB16_S2_S2 #(
-                       `include "brams_init_16.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(2'd0),
-                       .DOA(A1DATA),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB(B1DATA),
-                       .DOB(DOB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 4) begin
-               wire [3:0] DOB;
-               RAMB16_S4_S4 #(
-                       `include "brams_init_16.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(4'd0),
-                       .DOA(A1DATA),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB(B1DATA),
-                       .DOB(DOB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 9) begin
-               wire [7:0] DOB;
-               wire DOPB;
-               RAMB16_S9_S9 #(
-                       `include "brams_init_18.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(8'd0),
-                       .DIPA(1'd0),
-                       .DOA(A1DATA[7:0]),
-                       .DOPA(A1DATA[8]),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB(B1DATA[7:0]),
-                       .DIPB(B1DATA[8]),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 18) begin
-               wire [15:0] DOB;
-               wire [1:0] DOPB;
-               RAMB16_S18_S18 #(
-                       `include "brams_init_18.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(16'd0),
-                       .DIPA(2'd0),
-                       .DOA({A1DATA[16:9], A1DATA[7:0]}),
-                       .DOPA({A1DATA[17], A1DATA[8]}),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB({B1DATA[16:9], B1DATA[7:0]}),
-                       .DIPB({B1DATA[17], B1DATA[8]}),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 36) begin
-               wire [31:0] DOB;
-               wire [3:0] DOPB;
-               RAMB16_S36_S36 #(
-                       `include "brams_init_18.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(32'd0),
-                       .DIPA(4'd0),
-                       .DOA({A1DATA[34:27], A1DATA[25:18], A1DATA[16:9], A1DATA[7:0]}),
-                       .DOPA({A1DATA[35], A1DATA[26], A1DATA[17], A1DATA[8]}),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(1'b0),
-
-                       .DIB({B1DATA[34:27], B1DATA[25:18], B1DATA[16:9], B1DATA[7:0]}),
-                       .DIPB({B1DATA[35], B1DATA[26], B1DATA[17], B1DATA[8]}),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else begin
-               $error("Strange block RAM data width.");
-       end endgenerate
-endmodule
-
-
-// Version with separate byte enables, only available on Spartan 3A.
-
-module \$__XILINX_RAMB16BWE (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_B = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       generate if (CFG_DBITS == 18) begin
-               wire [15:0] DOB;
-               wire [1:0] DOPB;
-               RAMB16BWE_S18_S18 #(
-                       `include "brams_init_18.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(16'd0),
-                       .DIPA(2'd0),
-                       .DOA({A1DATA[16:9], A1DATA[7:0]}),
-                       .DOPA({A1DATA[17], A1DATA[8]}),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(2'b00),
-
-                       .DIB({B1DATA[16:9], B1DATA[7:0]}),
-                       .DIPB({B1DATA[17], B1DATA[8]}),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else if (CFG_DBITS == 36) begin
-               wire [31:0] DOB;
-               wire [3:0] DOPB;
-               RAMB16BWE_S36_S36 #(
-                       `include "brams_init_18.vh"
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(32'd0),
-                       .DIPA(4'd0),
-                       .DOA({A1DATA[34:27], A1DATA[25:18], A1DATA[16:9], A1DATA[7:0]}),
-                       .DOPA({A1DATA[35], A1DATA[26], A1DATA[17], A1DATA[8]}),
-                       .ADDRA(A1ADDR),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .SSRA(|0),
-                       .WEA(4'b0000),
-
-                       .DIB({B1DATA[34:27], B1DATA[25:18], B1DATA[16:9], B1DATA[7:0]}),
-                       .DIPB({B1DATA[35], B1DATA[26], B1DATA[17], B1DATA[8]}),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .SSRB(|0),
-                       .WEB(B1EN)
-               );
-       end else begin
-               $error("Strange block RAM data width.");
-       end endgenerate
-endmodule
diff --git a/techlibs/xilinx/xc3sa_brams.txt b/techlibs/xilinx/xc3sa_brams.txt
deleted file mode 100644 (file)
index 22a62bd..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-# Spartan 3A block RAM rules.
-
-bram $__XILINX_RAMB16
-  init 1
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB16BWE
-  init 1
-  abits  9     @a9d36
-  dbits 36     @a9d36
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4   @a9d36
-  enable 1 2   @a10d18
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__XILINX_RAMB16
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB16BWE
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-endmatch
diff --git a/techlibs/xilinx/xc3sda_brams.txt b/techlibs/xilinx/xc3sda_brams.txt
deleted file mode 100644 (file)
index 12c68ff..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# Spartan 3A DSP block RAM rules.
-
-bram $__XILINX_RAMB16BWER_TDP
-  init 1
-  abits  9     @a9d36
-  dbits 36     @a9d36
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4   @a9d36
-  enable 1 2   @a10d18
-  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__XILINX_RAMB16BWER_TDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-endmatch
diff --git a/techlibs/xilinx/xc6s_brams.txt b/techlibs/xilinx/xc6s_brams.txt
deleted file mode 100644 (file)
index 6457097..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-# Spartan 6 block RAM rules.
-
-bram $__XILINX_RAMB8BWER_SDP
-  init 1
-  abits 8
-  dbits 36
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB16BWER_TDP
-  init 1
-  abits  9     @a9d36
-  dbits 36     @a9d36
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4   @a9d36
-  enable 1 2   @a10d18
-  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB8BWER_TDP
-  init 1
-  abits  9     @a9d18
-  dbits 18     @a9d18
-  abits 10     @a10d9
-  dbits  9     @a10d9
-  abits 11     @a11d4
-  dbits  4     @a11d4
-  abits 12     @a12d2
-  dbits  2     @a12d2
-  abits 13     @a13d1
-  dbits  1     @a13d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 2   @a9d18
-  enable 1 1   @a10d9 @a11d4 @a12d2 @a13d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-match $__XILINX_RAMB8BWER_SDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB16BWER_TDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB8BWER_TDP
-  min bits 4096
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-endmatch
-
diff --git a/techlibs/xilinx/xc6s_brams_map.v b/techlibs/xilinx/xc6s_brams_map.v
deleted file mode 100644 (file)
index 9577eeb..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-// Spartan 3A DSP and Spartan 6 block RAM mapping (Spartan 6 is a superset of
-// Spartan 3A DSP).
-
-module \$__XILINX_RAMB8BWER_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [9215:0] INIT = 9216'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [7:0] A1ADDR;
-       output [35:0] A1DATA;
-       input A1EN;
-
-       input [7:0] B1ADDR;
-       input [35:0] B1DATA;
-       input [3:0] B1EN;
-
-       wire [12:0] A1ADDR_13 = {A1ADDR, 5'b0};
-       wire [12:0] B1ADDR_13 = {B1ADDR, 5'b0};
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       RAMB8BWER #(
-               .RAM_MODE("SDP"),
-               .DATA_WIDTH_A(36),
-               .DATA_WIDTH_B(36),
-               .WRITE_MODE_A("READ_FIRST"),
-               .WRITE_MODE_B("READ_FIRST"),
-               `include "brams_init_9.vh"
-       ) _TECHMAP_REPLACE_ (
-               .DOBDO(DO[31:16]),
-               .DOADO(DO[15:0]),
-               .DOPBDOP(DOP[3:2]),
-               .DOPADOP(DOP[1:0]),
-               .DIBDI(DI[31:16]),
-               .DIADI(DI[15:0]),
-               .DIPBDIP(DIP[3:2]),
-               .DIPADIP(DIP[1:0]),
-               .WEBWEU(B1EN[3:2]),
-               .WEAWEL(B1EN[1:0]),
-
-               .ADDRAWRADDR(B1ADDR_13),
-               .CLKAWRCLK(CLK3 ^ !CLKPOL3),
-               .ENAWREN(|1),
-               .REGCEA(|0),
-               .RSTA(|0),
-
-               .ADDRBRDADDR(A1ADDR_13),
-               .CLKBRDCLK(CLK2 ^ !CLKPOL2),
-               .ENBRDEN(A1EN),
-               .REGCEBREGCE(|1),
-               .RSTBRST(|0)
-       );
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB16BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_B = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
-       wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
-       wire [3:0] B1EN_4 = {4{B1EN}};
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       wire [31:0] DOB;
-       wire [3:0] DOPB;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB16BWER #(
-                       .DATA_WIDTH_A(CFG_DBITS),
-                       .DATA_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       `include "brams_init_18.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(32'd0),
-                       .DIPA(4'd0),
-                       .DOA(DO[31:0]),
-                       .DOPA(DOP[3:0]),
-                       .ADDRA(A1ADDR_14),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .REGCEA(|1),
-                       .RSTA(|0),
-                       .WEA(4'b0),
-
-                       .DIB(DI),
-                       .DIPB(DIP),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR_14),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .REGCEB(|0),
-                       .RSTB(|0),
-                       .WEB(B1EN_4)
-               );
-       end else begin
-               RAMB16BWER #(
-                       .DATA_WIDTH_A(CFG_DBITS),
-                       .DATA_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       `include "brams_init_16.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DIA(32'd0),
-                       .DIPA(4'd0),
-                       .DOA(DO[31:0]),
-                       .DOPA(DOP[3:0]),
-                       .ADDRA(A1ADDR_14),
-                       .CLKA(CLK2 ^ !CLKPOL2),
-                       .ENA(A1EN),
-                       .REGCEA(|1),
-                       .RSTA(|0),
-                       .WEA(4'b0),
-
-                       .DIB(DI),
-                       .DIPB(DIP),
-                       .DOB(DOB),
-                       .DOPB(DOPB),
-                       .ADDRB(B1ADDR_14),
-                       .CLKB(CLK3 ^ !CLKPOL3),
-                       .ENB(|1),
-                       .REGCEB(|0),
-                       .RSTB(|0),
-                       .WEB(B1EN_4)
-               );
-       end endgenerate
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB8BWER_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 9;
-       parameter CFG_DBITS = 18;
-       parameter CFG_ENABLE_B = 2;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [9215:0] INIT = 9216'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       wire [12:0] A1ADDR_13 = A1ADDR << (13 - CFG_ABITS);
-       wire [12:0] B1ADDR_13 = B1ADDR << (13 - CFG_ABITS);
-       wire [1:0] B1EN_2 = {2{B1EN}};
-
-       wire [1:0] DIP, DOP;
-       wire [15:0] DI, DO;
-
-       wire [15:0] DOBDO;
-       wire [1:0] DOPBDOP;
-
-       assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB8BWER #(
-                       .RAM_MODE("TDP"),
-                       .DATA_WIDTH_A(CFG_DBITS),
-                       .DATA_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       `include "brams_init_9.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(16'b0),
-                       .DIPADIP(2'b0),
-                       .DOADO(DO),
-                       .DOPADOP(DOP),
-                       .ADDRAWRADDR(A1ADDR_13),
-                       .CLKAWRCLK(CLK2 ^ !CLKPOL2),
-                       .ENAWREN(A1EN),
-                       .REGCEA(|1),
-                       .RSTA(|0),
-                       .WEAWEL(2'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBRDADDR(B1ADDR_13),
-                       .CLKBRDCLK(CLK3 ^ !CLKPOL3),
-                       .ENBRDEN(|1),
-                       .REGCEBREGCE(|0),
-                       .RSTBRST(|0),
-                       .WEBWEU(B1EN_2)
-               );
-       end else begin
-               RAMB8BWER #(
-                       .RAM_MODE("TDP"),
-                       .DATA_WIDTH_A(CFG_DBITS),
-                       .DATA_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       `include "brams_init_8.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(16'b0),
-                       .DIPADIP(2'b0),
-                       .DOADO(DO),
-                       .DOPADOP(DOP),
-                       .ADDRAWRADDR(A1ADDR_13),
-                       .CLKAWRCLK(CLK2 ^ !CLKPOL2),
-                       .ENAWREN(A1EN),
-                       .REGCEA(|1),
-                       .RSTA(|0),
-                       .WEAWEL(2'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBRDADDR(B1ADDR_13),
-                       .CLKBRDCLK(CLK3 ^ !CLKPOL3),
-                       .ENBRDEN(|1),
-                       .REGCEBREGCE(|0),
-                       .RSTBRST(|0),
-                       .WEBWEU(B1EN_2)
-               );
-       end endgenerate
-endmodule
diff --git a/techlibs/xilinx/xc7_brams_map.v b/techlibs/xilinx/xc7_brams_map.v
deleted file mode 100644 (file)
index 982a5a0..0000000
+++ /dev/null
@@ -1,363 +0,0 @@
-// Virtex 6 and Series 7 block RAM mapping.
-
-module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [36863:0] INIT = 36864'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [8:0] A1ADDR;
-       output [71:0] A1DATA;
-       input A1EN;
-
-       input [8:0] B1ADDR;
-       input [71:0] B1DATA;
-       input [7:0] B1EN;
-
-       // Set highest address bit to 1, as stated in UG473 (v1.14) July 3, 2019
-       wire [15:0] A1ADDR_16 = {1'b1, A1ADDR, 6'b0};
-       wire [15:0] B1ADDR_16 = {1'b1, B1ADDR, 6'b0};
-
-       wire [7:0] DIP, DOP;
-       wire [63:0] DI, DO;
-
-       assign A1DATA = { DOP[7], DO[63:56], DOP[6], DO[55:48], DOP[5], DO[47:40], DOP[4], DO[39:32],
-                         DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-
-       assign { DIP[7], DI[63:56], DIP[6], DI[55:48], DIP[5], DI[47:40], DIP[4], DI[39:32],
-                DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       RAMB36E1 #(
-               .RAM_MODE("SDP"),
-               .READ_WIDTH_A(72),
-               .WRITE_WIDTH_B(72),
-               .WRITE_MODE_A("READ_FIRST"),
-               .WRITE_MODE_B("READ_FIRST"),
-               .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-               .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-               `include "brams_init_36.vh"
-               .SIM_DEVICE("7SERIES")
-       ) _TECHMAP_REPLACE_ (
-               .DOBDO(DO[63:32]),
-               .DOADO(DO[31:0]),
-               .DOPBDOP(DOP[7:4]),
-               .DOPADOP(DOP[3:0]),
-               .DIBDI(DI[63:32]),
-               .DIADI(DI[31:0]),
-               .DIPBDIP(DIP[7:4]),
-               .DIPADIP(DIP[3:0]),
-
-               .ADDRARDADDR(A1ADDR_16),
-               .CLKARDCLK(CLK2),
-               .ENARDEN(A1EN),
-               .REGCEAREGCE(|1),
-               .RSTRAMARSTRAM(|0),
-               .RSTREGARSTREG(|0),
-               .WEA(4'b0),
-
-               .ADDRBWRADDR(B1ADDR_16),
-               .CLKBWRCLK(CLK3),
-               .ENBWREN(|1),
-               .REGCEB(|0),
-               .RSTRAMB(|0),
-               .RSTREGB(|0),
-               .WEBWE(B1EN)
-       );
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [8:0] A1ADDR;
-       output [35:0] A1DATA;
-       input A1EN;
-
-       input [8:0] B1ADDR;
-       input [35:0] B1DATA;
-       input [3:0] B1EN;
-
-       wire [13:0] A1ADDR_14 = {A1ADDR, 5'b0};
-       wire [13:0] B1ADDR_14 = {B1ADDR, 5'b0};
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       RAMB18E1 #(
-               .RAM_MODE("SDP"),
-               .READ_WIDTH_A(36),
-               .WRITE_WIDTH_B(36),
-               .WRITE_MODE_A("READ_FIRST"),
-               .WRITE_MODE_B("READ_FIRST"),
-               .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-               .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-               `include "brams_init_18.vh"
-               .SIM_DEVICE("7SERIES")
-       ) _TECHMAP_REPLACE_ (
-               .DOBDO(DO[31:16]),
-               .DOADO(DO[15:0]),
-               .DOPBDOP(DOP[3:2]),
-               .DOPADOP(DOP[1:0]),
-               .DIBDI(DI[31:16]),
-               .DIADI(DI[15:0]),
-               .DIPBDIP(DIP[3:2]),
-               .DIPADIP(DIP[1:0]),
-
-               .ADDRARDADDR(A1ADDR_14),
-               .CLKARDCLK(CLK2),
-               .ENARDEN(A1EN),
-               .REGCEAREGCE(|1),
-               .RSTRAMARSTRAM(|0),
-               .RSTREGARSTREG(|0),
-               .WEA(2'b0),
-
-               .ADDRBWRADDR(B1ADDR_14),
-               .CLKBWRCLK(CLK3),
-               .ENBWREN(|1),
-               .REGCEB(|0),
-               .RSTRAMB(|0),
-               .RSTREGB(|0),
-               .WEBWE(B1EN)
-       );
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_B = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [36863:0] INIT = 36864'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       // Set highest address bit to 1, as stated in UG473 (v1.14) July 3, 2019
-       wire [15:0] A1ADDR_16 = {1'b1, A1ADDR} << (15 - CFG_ABITS);
-       wire [15:0] B1ADDR_16 = {1'b1, B1ADDR} << (15 - CFG_ABITS);
-       wire [7:0] B1EN_8 = B1EN;
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       wire [31:0] DOBDO;
-       wire [3:0] DOPBDOP;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB36E1 #(
-                       .RAM_MODE("TDP"),
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_36.vh"
-                       .SIM_DEVICE("7SERIES")
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(32'd0),
-                       .DIPADIP(4'd0),
-                       .DOADO(DO[31:0]),
-                       .DOPADOP(DOP[3:0]),
-                       .ADDRARDADDR(A1ADDR_16),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(4'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_16),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_8)
-               );
-       end else begin
-               RAMB36E1 #(
-                       .RAM_MODE("TDP"),
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_32.vh"
-                       .SIM_DEVICE("7SERIES")
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(32'd0),
-                       .DIPADIP(4'd0),
-                       .DOADO(DO[31:0]),
-                       .DOPADOP(DOP[3:0]),
-                       .ADDRARDADDR(A1ADDR_16),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(4'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_16),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_8)
-               );
-       end endgenerate
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 18;
-       parameter CFG_ENABLE_B = 2;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
-       wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
-       wire [3:0] B1EN_4 = B1EN;
-
-       wire [1:0] DIP, DOP;
-       wire [15:0] DI, DO;
-
-       wire [15:0] DOBDO;
-       wire [1:0] DOPBDOP;
-
-       assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB18E1 #(
-                       .RAM_MODE("TDP"),
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_18.vh"
-                       .SIM_DEVICE("7SERIES")
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(16'b0),
-                       .DIPADIP(2'b0),
-                       .DOADO(DO),
-                       .DOPADOP(DOP),
-                       .ADDRARDADDR(A1ADDR_14),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(2'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_14),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_4)
-               );
-       end else begin
-               RAMB18E1 #(
-                       .RAM_MODE("TDP"),
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_16.vh"
-                       .SIM_DEVICE("7SERIES")
-               ) _TECHMAP_REPLACE_ (
-                       .DIADI(16'b0),
-                       .DIPADIP(2'b0),
-                       .DOADO(DO),
-                       .DOPADOP(DOP),
-                       .ADDRARDADDR(A1ADDR_14),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(2'b0),
-
-                       .DIBDI(DI),
-                       .DIPBDIP(DIP),
-                       .DOBDO(DOBDO),
-                       .DOPBDOP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_14),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_4)
-               );
-       end endgenerate
-endmodule
-
diff --git a/techlibs/xilinx/xc7_xcu_brams.txt b/techlibs/xilinx/xc7_xcu_brams.txt
deleted file mode 100644 (file)
index 650367a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-# Virtex 6, Series 7, Ultrascale, Ultrascale Plus block RAM rules.
-
-bram $__XILINX_RAMB36_SDP
-  init 1
-  abits 9
-  dbits 72
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 8
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB18_SDP
-  init 1
-  abits 9
-  dbits 36
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB36_TDP
-  init 1
-  abits 10     @a10d36
-  dbits 36     @a10d36
-  abits 11     @a11d18
-  dbits 18     @a11d18
-  abits 12     @a12d9
-  dbits  9     @a12d9
-  abits 13     @a13d4
-  dbits  4     @a13d4
-  abits 14     @a14d2
-  dbits  2     @a14d2
-  abits 15     @a15d1
-  dbits  1     @a15d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 4   @a10d36
-  enable 1 2   @a11d18
-  enable 1 1   @a12d9 @a13d4 @a14d2 @a15d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-bram $__XILINX_RAMB18_TDP
-  init 1
-  abits 10     @a10d18
-  dbits 18     @a10d18
-  abits 11     @a11d9
-  dbits  9     @a11d9
-  abits 12     @a12d4
-  dbits  4     @a12d4
-  abits 13     @a13d2
-  dbits  2     @a13d2
-  abits 14     @a14d1
-  dbits  1     @a14d1
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 2   @a10d18
-  enable 1 1   @a11d9 @a12d4 @a13d2 @a14d1
-  transp 0 0
-  clocks 2 3
-  clkpol 2 3
-endbram
-
-# The "min bits" value were taken from:
-# [[CITE]] 7 Series FPGAs Memory Resources User Guide (UG473),
-# v1.14 ed., p 29-30, July, 2019.
-# https://www.xilinx.com/support/documentation/user_guides/ug473_7Series_Memory_Resources.pdf
-
-match $__XILINX_RAMB36_SDP
-  attribute !ram_style
-  attribute !logic_block
-  min bits 1024
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB36_SDP
-  attribute ram_style=block ram_block
-  attribute !logic_block
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB18_SDP
-  attribute !ram_style
-  attribute !logic_block
-  min bits 1024
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB18_SDP
-  attribute ram_style=block ram_block
-  attribute !logic_block
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB36_TDP
-  attribute !ram_style
-  attribute !logic_block
-  min bits 1024
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB36_TDP
-  attribute ram_style=block ram_block
-  attribute !logic_block
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB18_TDP
-  attribute !ram_style
-  attribute !logic_block
-  min bits 1024
-  min efficiency 5
-  shuffle_enable B
-  make_transp
-  or_next_if_better
-endmatch
-
-match $__XILINX_RAMB18_TDP
-  attribute ram_style=block ram_block
-  attribute !logic_block
-  shuffle_enable B
-  make_transp
-endmatch
-
diff --git a/techlibs/xilinx/xcu_brams_map.v b/techlibs/xilinx/xcu_brams_map.v
deleted file mode 100644 (file)
index b6719b2..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-// Ultrascale and Ultrascale Plus block RAM mapping.
-
-module \$__XILINX_RAMB36_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [36863:0] INIT = 36864'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [8:0] A1ADDR;
-       output [71:0] A1DATA;
-       input A1EN;
-
-       input [8:0] B1ADDR;
-       input [71:0] B1DATA;
-       input [7:0] B1EN;
-
-       wire [15:0] A1ADDR_16 = {A1ADDR, 6'b0};
-       wire [15:0] B1ADDR_16 = {B1ADDR, 6'b0};
-
-       wire [7:0] DIP, DOP;
-       wire [63:0] DI, DO;
-
-       assign A1DATA = { DOP[7], DO[63:56], DOP[6], DO[55:48], DOP[5], DO[47:40], DOP[4], DO[39:32],
-                         DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-
-       assign { DIP[7], DI[63:56], DIP[6], DI[55:48], DIP[5], DI[47:40], DIP[4], DI[39:32],
-                DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       RAMB36E2 #(
-               .READ_WIDTH_A(72),
-               .WRITE_WIDTH_B(72),
-               .WRITE_MODE_A("READ_FIRST"),
-               .WRITE_MODE_B("READ_FIRST"),
-               .DOA_REG(0),
-               .DOB_REG(0),
-               .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-               .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-               `include "brams_init_36.vh"
-       ) _TECHMAP_REPLACE_ (
-               .DOUTBDOUT(DO[63:32]),
-               .DOUTADOUT(DO[31:0]),
-               .DOUTPBDOUTP(DOP[7:4]),
-               .DOUTPADOUTP(DOP[3:0]),
-               .DINBDIN(DI[63:32]),
-               .DINADIN(DI[31:0]),
-               .DINPBDINP(DIP[7:4]),
-               .DINPADINP(DIP[3:0]),
-
-               .ADDRARDADDR(A1ADDR_16),
-               .CLKARDCLK(CLK2),
-               .ENARDEN(A1EN),
-               .ADDRENA(|1),
-               .REGCEAREGCE(|1),
-               .RSTRAMARSTRAM(|0),
-               .RSTREGARSTREG(|0),
-               .WEA(4'b0),
-
-               .ADDRBWRADDR(B1ADDR_16),
-               .CLKBWRCLK(CLK3),
-               .ENBWREN(|1),
-               .ADDRENB(|1),
-               .REGCEB(|1),
-               .RSTRAMB(|0),
-               .RSTREGB(|0),
-               .WEBWE(B1EN),
-
-               .SLEEP(|0)
-       );
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB18_SDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'bx;
-
-       input CLK2;
-       input CLK3;
-
-       input [8:0] A1ADDR;
-       output [35:0] A1DATA;
-       input A1EN;
-
-       input [8:0] B1ADDR;
-       input [35:0] B1DATA;
-       input [3:0] B1EN;
-
-       wire [13:0] A1ADDR_14 = {A1ADDR, 5'b0};
-       wire [13:0] B1ADDR_14 = {B1ADDR, 5'b0};
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       RAMB18E2 #(
-               .READ_WIDTH_A(36),
-               .WRITE_WIDTH_B(36),
-               .WRITE_MODE_A("READ_FIRST"),
-               .WRITE_MODE_B("READ_FIRST"),
-               .DOA_REG(0),
-               .DOB_REG(0),
-               .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-               .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-               `include "brams_init_18.vh"
-       ) _TECHMAP_REPLACE_ (
-               .DOUTBDOUT(DO[31:16]),
-               .DOUTADOUT(DO[15:0]),
-               .DOUTPBDOUTP(DOP[3:2]),
-               .DOUTPADOUTP(DOP[1:0]),
-               .DINBDIN(DI[31:16]),
-               .DINADIN(DI[15:0]),
-               .DINPBDINP(DIP[3:2]),
-               .DINPADINP(DIP[1:0]),
-
-               .ADDRARDADDR(A1ADDR_14),
-               .CLKARDCLK(CLK2),
-               .ENARDEN(A1EN),
-               .ADDRENA(|1),
-               .REGCEAREGCE(|1),
-               .RSTRAMARSTRAM(|0),
-               .RSTREGARSTREG(|0),
-               .WEA(2'b0),
-
-               .ADDRBWRADDR(B1ADDR_14),
-               .CLKBWRCLK(CLK3),
-               .ENBWREN(|1),
-               .ADDRENB(|1),
-               .REGCEB(|1),
-               .RSTRAMB(|0),
-               .RSTREGB(|0),
-               .WEBWE(B1EN),
-
-               .SLEEP(|0)
-       );
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB36_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 36;
-       parameter CFG_ENABLE_B = 4;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [36863:0] INIT = 36864'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       wire [15:0] A1ADDR_16 = A1ADDR << (15 - CFG_ABITS);
-       wire [15:0] B1ADDR_16 = B1ADDR << (15 - CFG_ABITS);
-       wire [7:0] B1EN_8 = B1EN;
-
-       wire [3:0] DIP, DOP;
-       wire [31:0] DI, DO;
-
-       wire [31:0] DOBDO;
-       wire [3:0] DOPBDOP;
-
-       assign A1DATA = { DOP[3], DO[31:24], DOP[2], DO[23:16], DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[3], DI[31:24], DIP[2], DI[23:16], DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB36E2 #(
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .DOA_REG(0),
-                       .DOB_REG(0),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_36.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DINADIN(32'hFFFFFFFF),
-                       .DINPADINP(4'hF),
-                       .DOUTADOUT(DO[31:0]),
-                       .DOUTPADOUTP(DOP[3:0]),
-                       .ADDRARDADDR(A1ADDR_16),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .ADDRENA(|1),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(4'b0),
-
-                       .DINBDIN(DI),
-                       .DINPBDINP(DIP),
-                       .DOUTBDOUT(DOBDO),
-                       .DOUTPBDOUTP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_16),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .ADDRENB(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_8),
-
-                       .SLEEP(|0)
-               );
-       end else begin
-               RAMB36E2 #(
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .DOA_REG(0),
-                       .DOB_REG(0),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_32.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DINADIN(32'hFFFFFFFF),
-                       .DINPADINP(4'hF),
-                       .DOUTADOUT(DO[31:0]),
-                       .DOUTPADOUTP(DOP[3:0]),
-                       .ADDRARDADDR(A1ADDR_16),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .ADDRENA(|1),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(4'b0),
-
-                       .DINBDIN(DI),
-                       .DINPBDINP(DIP),
-                       .DOUTBDOUT(DOBDO),
-                       .DOUTPBDOUTP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_16),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .ADDRENB(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_8),
-
-                       .SLEEP(|0)
-               );
-       end endgenerate
-endmodule
-
-// ------------------------------------------------------------------------
-
-module \$__XILINX_RAMB18_TDP (CLK2, CLK3, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CFG_ABITS = 10;
-       parameter CFG_DBITS = 18;
-       parameter CFG_ENABLE_B = 2;
-
-       parameter CLKPOL2 = 1;
-       parameter CLKPOL3 = 1;
-       parameter [18431:0] INIT = 18432'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 [CFG_ENABLE_B-1:0] B1EN;
-
-       wire [13:0] A1ADDR_14 = A1ADDR << (14 - CFG_ABITS);
-       wire [13:0] B1ADDR_14 = B1ADDR << (14 - CFG_ABITS);
-       wire [3:0] B1EN_4 = B1EN;
-
-       wire [1:0] DIP, DOP;
-       wire [15:0] DI, DO;
-
-       wire [15:0] DOBDO;
-       wire [1:0] DOPBDOP;
-
-       assign A1DATA = { DOP[1], DO[15: 8], DOP[0], DO[ 7: 0] };
-       assign { DIP[1], DI[15: 8], DIP[0], DI[ 7: 0] } = B1DATA;
-
-       generate if (CFG_DBITS > 8) begin
-               RAMB18E2 #(
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .DOA_REG(0),
-                       .DOB_REG(0),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_18.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DINADIN(16'hFFFF),
-                       .DINPADINP(2'b11),
-                       .DOUTADOUT(DO),
-                       .DOUTPADOUTP(DOP),
-                       .ADDRARDADDR(A1ADDR_14),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .ADDRENA(|1),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(2'b0),
-
-                       .DINBDIN(DI),
-                       .DINPBDINP(DIP),
-                       .DOUTBDOUT(DOBDO),
-                       .DOUTPBDOUTP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_14),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .ADDRENB(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_4),
-
-                       .SLEEP(|0)
-               );
-       end else begin
-               RAMB18E2 #(
-                       //.RAM_MODE("TDP"),
-                       .READ_WIDTH_A(CFG_DBITS),
-                       .READ_WIDTH_B(CFG_DBITS),
-                       .WRITE_WIDTH_A(CFG_DBITS),
-                       .WRITE_WIDTH_B(CFG_DBITS),
-                       .WRITE_MODE_A("READ_FIRST"),
-                       .WRITE_MODE_B("READ_FIRST"),
-                       .DOA_REG(0),
-                       .DOB_REG(0),
-                       .IS_CLKARDCLK_INVERTED(!CLKPOL2),
-                       .IS_CLKBWRCLK_INVERTED(!CLKPOL3),
-                       `include "brams_init_16.vh"
-               ) _TECHMAP_REPLACE_ (
-                       .DINADIN(16'hFFFF),
-                       .DINPADINP(2'b11),
-                       .DOUTADOUT(DO),
-                       .DOUTPADOUTP(DOP),
-                       .ADDRARDADDR(A1ADDR_14),
-                       .CLKARDCLK(CLK2),
-                       .ENARDEN(A1EN),
-                       .ADDRENA(|1),
-                       .REGCEAREGCE(|1),
-                       .RSTRAMARSTRAM(|0),
-                       .RSTREGARSTREG(|0),
-                       .WEA(2'b0),
-
-                       .DINBDIN(DI),
-                       .DINPBDINP(DIP),
-                       .DOUTBDOUT(DOBDO),
-                       .DOUTPBDOUTP(DOPBDOP),
-                       .ADDRBWRADDR(B1ADDR_14),
-                       .CLKBWRCLK(CLK3),
-                       .ENBWREN(|1),
-                       .ADDRENB(|1),
-                       .REGCEB(|0),
-                       .RSTRAMB(|0),
-                       .RSTREGB(|0),
-                       .WEBWE(B1EN_4),
-
-                       .SLEEP(|0)
-               );
-       end endgenerate
-endmodule
-
diff --git a/techlibs/xilinx/xcup_urams.txt b/techlibs/xilinx/xcup_urams.txt
deleted file mode 100644 (file)
index 40c4742..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-bram $__XILINX_URAM288
-  init 0
-  abits 12
-  dbits 72
-  groups 2
-  ports  1 1
-  wrmode 0 1
-  enable 1 9
-  transp 0 0
-  clocks 2 2
-  clkpol 2 2
-endbram
-
-match $__XILINX_URAM288
-  min bits 131072
-  min efficiency 15
-  shuffle_enable B
-  make_transp
-endmatch
diff --git a/techlibs/xilinx/xcup_urams_map.v b/techlibs/xilinx/xcup_urams_map.v
deleted file mode 100644 (file)
index f15211b..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-module \$__XILINX_URAM288 (CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA, B1EN);
-       parameter CLKPOL2 = 1;
-
-       input CLK2;
-
-       input [11:0] A1ADDR;
-       output [71:0] A1DATA;
-       input A1EN;
-
-       input [11:0] B1ADDR;
-       input [71:0] B1DATA;
-       input [8:0] B1EN;
-
-
-       URAM288 #(
-               .BWE_MODE_A("PARITY_INDEPENDENT"),
-               .BWE_MODE_B("PARITY_INDEPENDENT"),
-               .EN_AUTO_SLEEP_MODE("FALSE"),
-               .IREG_PRE_A("FALSE"),
-               .IREG_PRE_B("FALSE"),
-               .IS_CLK_INVERTED(!CLKPOL2),
-               .OREG_A("FALSE"),
-               .OREG_B("FALSE")
-       ) _TECHMAP_REPLACE_ (
-               .ADDR_A({11'b0, A1ADDR}),
-               .BWE_A(9'b0),
-               .DIN_A(72'b0),
-               .EN_A(A1EN),
-               .RDB_WR_A(1'b0),
-               .INJECT_DBITERR_A(1'b0),
-               .INJECT_SBITERR_A(1'b0),
-               .RST_A(1'b0),
-               .DOUT_A(A1DATA),
-
-               .ADDR_B({11'b0, B1ADDR}),
-               .BWE_B(B1EN),
-               .DIN_B(B1DATA),
-               .EN_B(|B1EN),
-               .RDB_WR_B(1'b1),
-               .INJECT_DBITERR_B(1'b0),
-               .INJECT_SBITERR_B(1'b0),
-               .RST_B(1'b0),
-
-               .CLK(CLK2),
-               .SLEEP(1'b0)
-       );
-endmodule
index 44651ba253427da8a579985e974cde20546320c8..5cddcb9525f4175395f4552ed8bb59f1eceec561 100644 (file)
@@ -1,11 +1,11 @@
 # ================================ RAM ================================
-# RAM bits <= 18K; Data width <= 36; Address width <= 9: -> PDPW16KD
+# RAM bits <= 18K; Data width <= 36; Address width <= 9: -> DP16KD
 
 design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:PDPW16KD
+select -assert-count 1 t:DP16KD
 
 ## With parameters
 
@@ -13,7 +13,7 @@ design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 0 t:PDPW16KD # too inefficient
+select -assert-count 0 t:DP16KD # too inefficient
 select -assert-count 9 t:TRELLIS_DPR16X4
 
 design -reset; read_verilog -defer ../common/blockram.v
@@ -21,28 +21,29 @@ chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set syn_ramstyle "block_ram" m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:PDPW16KD
+select -assert-count 1 t:DP16KD
 
 design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set syn_ramstyle "Block_RAM" m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:PDPW16KD # any case works
+select -assert-count 1 t:DP16KD # any case works
 
 design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set ram_block 1 m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:PDPW16KD
+select -assert-count 0 t:DP16KD
+select -assert-count 9 t:TRELLIS_DPR16X4
 
 design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set syn_ramstyle "registers" m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 0 t:PDPW16KD # requested FFRAM explicitly
+select -assert-count 0 t:DP16KD # requested FFRAM explicitly
 select -assert-count 180 t:TRELLIS_FF
 
 design -reset; read_verilog -defer ../common/blockram.v
@@ -50,37 +51,9 @@ chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set logic_block 1 m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 0 t:PDPW16KD # requested FFRAM explicitly
+select -assert-count 0 t:DP16KD # requested FFRAM explicitly
 select -assert-count 180 t:TRELLIS_FF
 
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_romstyle "ebr" m:memory
-synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set rom_block 1 m:memory
-synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set ram_block 1 m:memory
-synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
 # RAM bits <= 18K; Data width <= 18; Address width <= 10: -> DP16KD
 
 design -reset; read_verilog -defer ../common/blockram.v
@@ -141,7 +114,8 @@ chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
 hierarchy -top sync_ram_sdp
 setattr -set ram_block 1 m:memory
 synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:DP16KD
+select -assert-count 0 t:DP16KD # too inefficient
+select -assert-count 5 t:TRELLIS_DPR16X4
 
 design -reset; read_verilog -defer ../common/blockram.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
@@ -159,34 +133,6 @@ synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
 select -assert-count 0 t:DP16KD # requested FFRAM explicitly
 select -assert-count 90 t:TRELLIS_FF
 
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_romstyle "ebr" m:memory
-synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set rom_block 1 m:memory
-synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set ram_block 1 m:memory
-synth_ecp5 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
 # RAM bits <= 64; Data width <= 4; Address width <= 4: -> DPR16X4
 
 design -reset; read_verilog -defer ../common/blockram.v
@@ -220,21 +166,14 @@ synth_ecp5 -top sync_ram_sdp; cd sync_ram_sdp
 select -assert-count 0 t:TRELLIS_DPR16X4 # requested FFRAM explicitly
 select -assert-count 68 t:TRELLIS_FF
 
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 4 -set DATA_WIDTH 4 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_ramstyle "distributed" m:memory
-synth_ecp5 -top sync_ram_sdp -nolutram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested LUTRAM but LUTRAM is disabled
-
 # ================================ ROM ================================
-# ROM bits <= 18K; Data width <= 36; Address width <= 9: -> PDPW16KD
+# ROM bits <= 18K; Data width <= 36; Address width <= 9: -> DP16KD
 
 design -reset; read_verilog -defer ../common/blockrom.v
 chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:PDPW16KD
+select -assert-count 1 t:DP16KD
 
 ## With parameters
 
@@ -242,7 +181,7 @@ design -reset; read_verilog -defer ../common/blockrom.v
 chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 0 t:PDPW16KD # too inefficient
+select -assert-count 0 t:DP16KD # too inefficient
 select -assert-min 18 t:LUT4
 
 design -reset; read_verilog -defer ../common/blockrom.v
@@ -250,21 +189,21 @@ chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 setattr -set syn_romstyle "ebr" m:memory
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:PDPW16KD
+select -assert-count 1 t:DP16KD
 
 design -reset; read_verilog -defer ../common/blockrom.v
 chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 setattr -set rom_block 1 m:memory
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:PDPW16KD
+select -assert-count 1 t:DP16KD
 
 design -reset; read_verilog -defer ../common/blockrom.v
 chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 setattr -set syn_romstyle "logic" m:memory
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 0 t:PDPW16KD # requested LUTROM explicitly
+select -assert-count 0 t:DP16KD # requested LUTROM explicitly
 select -assert-min 18 t:LUT4
 
 design -reset; read_verilog -defer ../common/blockrom.v
@@ -272,37 +211,9 @@ chparam -set ADDRESS_WIDTH 3 -set DATA_WIDTH 36 sync_rom
 hierarchy -top sync_rom
 setattr -set logic_block 1 m:memory
 synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 0 t:PDPW16KD # requested LUTROM explicitly
+select -assert-count 0 t:DP16KD # requested LUTROM explicitly
 select -assert-min 18 t:LUT4
 
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
-hierarchy -top sync_rom
-setattr -set ram_block 1 m:memory
-synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_ramstyle "block_rom" m:memory
-synth_ecp5 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 36 sync_rom
-hierarchy -top sync_rom
-setattr -set rom_block 1 m:memory
-synth_ecp5 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
-
 # ROM bits <= 18K; Data width <= 18; Address width <= 10: -> DP16KD
 
 design -reset; read_verilog -defer ../common/blockrom.v
@@ -349,31 +260,3 @@ setattr -set logic_block 1 m:memory
 synth_ecp5 -top sync_rom; cd sync_rom
 select -assert-count 0 t:DP16KD # requested LUTROM explicitly
 select -assert-min 9 t:LUT4
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
-hierarchy -top sync_rom
-setattr -set ram_block 1 m:memory
-synth_ecp5 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_ramstyle "block_rom" m:memory
-synth_ecp5 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 18 sync_rom
-hierarchy -top sync_rom
-setattr -set rom_block 1 m:memory
-synth_ecp5 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
index dcf647ce0f9ed54c68bc269422db1e4518edbb87..8412d138958250e749c94a97296600deb60686c7 100644 (file)
@@ -1,17 +1,6 @@
 read_verilog ../common/lutram.v
 hierarchy -top lutram_1w1r
-proc
-memory -nomap
-equiv_opt -run :prove -map +/efinix/cells_sim.v synth_efinix
-memory
-opt -full
-
-miter -equiv -flatten -make_assert -make_outputs gold gate miter
-#ERROR: Called with -verify and proof did fail!
-#sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
-sat -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter
-
-design -load postopt
+synth_efinix
 cd lutram_1w1r
 select -assert-count 1 t:EFX_GBUFCE
 select -assert-count 1 t:EFX_RAM_5K
index 4920a45e35d76e025c1abf8baf8475ba6fcd36ec..d480a3abe100b18944ab672c4d8386fa3be05e00 100644 (file)
@@ -71,34 +71,6 @@ synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
 select -assert-count 0 t:SB_RAM40_4K # requested FFRAM explicitly
 select -assert-min 1 t:SB_DFFE
 
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_romstyle "ebr" m:memory
-synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set rom_block 1 m:memory
-synth_ice40 -top sync_ram_sdp; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BROM but this is a RAM
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ice40 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockram.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_ram_sdp
-hierarchy -top sync_ram_sdp
-setattr -set ram_block 1 m:memory
-synth_ice40 -top sync_ram_sdp -nobram; cd sync_ram_sdp
-select -assert-count 1 t:$mem_v2 # requested BRAM but BRAM is disabled
-
 # ================================ ROM ================================
 # ROM bits <= 4K; Data width <= 16; Address width <= 11: -> SB_RAM40_4K
 
@@ -164,31 +136,3 @@ setattr -set logic_block 1 m:memory
 synth_ice40 -top sync_rom; cd sync_rom
 select -assert-count 0 t:SB_RAM40_4K # requested LUTROM explicitly
 select -assert-min 1 t:SB_LUT4
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_ramstyle "block_ram" m:memory
-synth_ice40 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
-hierarchy -top sync_rom
-setattr -set ram_block 1 m:memory
-synth_ice40 -top sync_rom; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BRAM but this is a ROM
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
-hierarchy -top sync_rom
-setattr -set syn_romstyle "ebr" m:memory
-synth_ice40 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
-
-design -reset; read_verilog -defer ../common/blockrom.v
-chparam -set ADDRESS_WIDTH 2 -set DATA_WIDTH 8 sync_rom
-hierarchy -top sync_rom
-setattr -set rom_block 1 m:memory
-synth_ice40 -top sync_rom -nobram; cd sync_rom
-select -assert-count 1 t:$mem_v2 # requested BROM but BRAM is disabled
index 9540136d544f343ee503b40a3339618fa71f194e..a85b5141e7e9a07f003d1fced2f5bff446146ebb 100644 (file)
@@ -3,7 +3,7 @@ design -save read
 
 # Check that we use the right dual and single clock variants
 
-chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_ram_sdp
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp
 synth_nexus -top sync_ram_sdp
 cd sync_ram_sdp
 select -assert-count 1 t:PDPSC16K
@@ -11,7 +11,7 @@ select -assert-none t:PDPSC16K t:INV t:IB t:OB t:VLO t:VHI %% t:* %D
 
 design -reset
 read_verilog blockram_dc.v
-chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 18 sync_ram_sdp_dc
+chparam -set ADDRESS_WIDTH 9 -set DATA_WIDTH 36 sync_ram_sdp_dc
 synth_nexus -top sync_ram_sdp_dc
 cd sync_ram_sdp_dc
 select -assert-count 1 t:PDP16K
index 58552d8fbd14cfcdf92a4a22fb21bef7c3321ab9..74861850f547d45f4809ea8428194c048a53f08c 100644 (file)
@@ -11,7 +11,7 @@ read_verilog ../common/memory_attributes/attributes_test.v
 hierarchy -top distributed_ram
 synth_xilinx -top distributed_ram -noiopad
 cd distributed_ram # Constrain all select calls below inside the top module
-select -assert-count 8 t:RAM32X1D
+select -assert-count 1 t:RAM32M
  
 # Set ram_style distributed to blockram memory; will be implemented as distributed
 design -reset
@@ -19,7 +19,7 @@ read_verilog ../common/memory_attributes/attributes_test.v
 setattr -set ram_style "distributed" block_ram/m:*
 synth_xilinx -top block_ram -noiopad
 cd block_ram # Constrain all select calls below inside the top module
-select -assert-count 32 t:RAM128X1D
+select -assert-count 16 t:RAM256X1S
  
 # Set synthesis, logic_block to blockram memory; will be implemented as distributed
 design -reset
@@ -28,7 +28,6 @@ setattr -set logic_block 1 block_ram/m:*
 synth_xilinx -top block_ram -noiopad
 cd block_ram # Constrain all select calls below inside the top module
 select -assert-count 0 t:RAMB18E1
-select -assert-count 32 t:RAM128X1D
  
 # Set ram_style block to a distributed memory; will be implemented as blockram
 design -reset
@@ -36,10 +35,3 @@ read_verilog ../common/memory_attributes/attributes_test.v
 synth_xilinx -top distributed_ram_manual -noiopad
 cd distributed_ram_manual # Constrain all select calls below inside the top module
 select -assert-count 1 t:RAMB18E1
-# Set synthesis, ram_block block to a distributed memory; will be implemented as blockram
-design -reset
-read_verilog ../common/memory_attributes/attributes_test.v
-synth_xilinx -top distributed_ram_manual_syn -noiopad
-cd distributed_ram_manual_syn # Constrain all select calls below inside the top module
-select -assert-count 1 t:RAMB18E1
index ed743cf44f66013fb4b01ed9d48d8dfd339dddb8..c2b7aede7a195a51593a6ab1756580e87c19a2c5 100644 (file)
@@ -2,7 +2,7 @@
 ###       currently. Checking instance counts instead.
 # Memory bits <= 18K; Data width <= 36; Address width <= 14: -> RAMB18E1
 read_verilog ../common/blockram.v
-chparam -set ADDRESS_WIDTH 10 -set DATA_WIDTH 1 sync_ram_sdp
+chparam -set ADDRESS_WIDTH 12 -set DATA_WIDTH 1 sync_ram_sdp
 synth_xilinx -top sync_ram_sdp -noiopad
 cd sync_ram_sdp
 select -assert-count 1 t:RAMB18E1
@@ -35,7 +35,7 @@ chparam -set ADDRESS_WIDTH 8 -set DATA_WIDTH 2 sync_ram_sdp
 synth_xilinx -top sync_ram_sdp -noiopad
 cd sync_ram_sdp
 select -assert-count 0 t:RAMB18E1
-select -assert-count 4 t:RAM128X1D
+select -assert-count 4 t:RAM64M
 
 # More than 18K bits, data width <= 36 (TDP), and address width from 10 to 15b (non-cascaded) -> RAMB36E1
 design -reset
@@ -50,7 +50,7 @@ select -assert-count 1 t:RAMB36E1
 
 design -reset
 read_verilog ../common/blockram.v
-hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1 
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 12 -chparam DATA_WIDTH 1 
 setattr -set ram_style "block" m:memory
 synth_xilinx -top sync_ram_sdp -noiopad
 cd sync_ram_sdp
@@ -58,23 +58,7 @@ select -assert-count 1 t:RAMB18E1
 
 design -reset
 read_verilog ../common/blockram.v
-hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1 
-setattr -set ram_block 1 m:memory
-synth_xilinx -top sync_ram_sdp -noiopad
-cd sync_ram_sdp
-select -assert-count 1 t:RAMB18E1
-
-design -reset
-read_verilog ../common/blockram.v
-hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1 
-setattr -set ram_style "dont_infer_a_ram_pretty_please" m:memory
-synth_xilinx -top sync_ram_sdp -noiopad
-cd sync_ram_sdp
-select -assert-count 0 t:RAMB18E1
-
-design -reset
-read_verilog ../common/blockram.v
-hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 10 -chparam DATA_WIDTH 1 
+hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 12 -chparam DATA_WIDTH 1 
 setattr -set logic_block 1 m:memory
 synth_xilinx -top sync_ram_sdp -noiopad
 cd sync_ram_sdp
@@ -87,11 +71,3 @@ setattr -set ram_style "block" m:memory
 synth_xilinx -top sync_ram_sdp -noiopad
 cd sync_ram_sdp
 select -assert-count 1 t:RAMB18E1
-
-design -reset
-read_verilog ../common/blockram.v
-hierarchy -top sync_ram_sdp -chparam ADDRESS_WIDTH 8 -chparam DATA_WIDTH 1
-setattr -set ram_block 1 m:memory
-synth_xilinx -top sync_ram_sdp -noiopad
-cd sync_ram_sdp
-select -assert-count 1 t:RAMB18E1
index cc73545017f0c4e702867a75a51bc27b8e3bb3e5..34caa8c6cab45e87019a012d93a535c6161a2eb1 100644 (file)
@@ -33,8 +33,8 @@ design -load postopt
 cd lutram_1w1r
 select -assert-count 1 t:BUFG
 select -assert-count 8 t:FDRE
-select -assert-count 8 t:RAM32X1D
-select -assert-none t:BUFG t:FDRE t:RAM32X1D %% t:* %D
+select -assert-count 1 t:RAM32M
+select -assert-none t:BUFG t:FDRE t:RAM32M %% t:* %D
 
 
 design -reset
@@ -51,10 +51,11 @@ sat -verify -prove-asserts -seq 3 -set-init-zero -show-inputs -show-outputs mite
 
 design -load postopt
 cd lutram_1w1r
+dump
 select -assert-count 1 t:BUFG
 select -assert-count 8 t:FDRE
-select -assert-count 8 t:RAM64X1D
-select -assert-none t:BUFG t:FDRE t:RAM64X1D %% t:* %D
+select -assert-count 8 t:RAM64X1S
+select -assert-none t:BUFG t:FDRE t:RAM64X1S %% t:* %D
 
 
 design -reset
@@ -133,8 +134,8 @@ design -load postopt
 cd lutram_1w1r
 select -assert-count 1 t:BUFG
 select -assert-count 6 t:FDRE
-select -assert-count 2 t:RAM64M
-select -assert-none t:BUFG t:FDRE t:RAM64M %% t:* %D
+select -assert-count 6 t:RAM64X1S
+select -assert-none t:BUFG t:FDRE t:RAM64X1S %% t:* %D
 
 
 design -reset
@@ -153,5 +154,5 @@ design -load postopt
 cd lutram_1w1r
 select -assert-count 1 t:BUFG
 select -assert-count 8 t:FDRE
-select -assert-count 8 t:RAM16X1D
-select -assert-none t:BUFG t:FDRE t:RAM16X1D %% t:* %D
+select -assert-count 8 t:RAM16X1S
+select -assert-none t:BUFG t:FDRE t:RAM16X1S %% t:* %D
diff --git a/tests/memlib/.gitignore b/tests/memlib/.gitignore
new file mode 100644 (file)
index 0000000..03dbe82
--- /dev/null
@@ -0,0 +1,5 @@
+t_*.log
+t_*.out
+t_*.v
+t_*.ys
+run-test.mk
diff --git a/tests/memlib/generate.py b/tests/memlib/generate.py
new file mode 100644 (file)
index 0000000..3414865
--- /dev/null
@@ -0,0 +1,900 @@
+# TODO:
+
+# - memory initialization
+# - clock polarity combinations
+# - CE/srst/rdwr/be interactions
+# - priority logic
+# - byte enables, wrbe_separate
+# - duplication for read ports
+# - abits/dbits determination
+# - mixed width
+# - swizzles for weird width progressions
+
+
+class Test:
+    def __init__(self, name, src, libs, defs, cells):
+        self.name = name
+        self.src = src
+        self.libs = libs
+        self.defs = defs
+        self.cells = cells
+
+TESTS = []
+
+### basic sanity tests
+
+ASYNC = """
+module top(clk, ra, wa, rd, wd, we);
+
+localparam ABITS = {abits};
+localparam DBITS = {dbits};
+
+input wire clk;
+input wire we;
+input wire [ABITS-1:0] ra, wa;
+input wire [DBITS-1:0] wd;
+output wire [DBITS-1:0] rd;
+
+reg [DBITS-1:0] mem [0:2**ABITS-1];
+
+always @(posedge clk)
+    if (we)
+        mem[wa] <= wd;
+
+assign rd = mem[ra];
+
+endmodule
+"""
+
+ASYNC_SMALL = ASYNC.format(abits=6, dbits=6)
+ASYNC_BIG = ASYNC.format(abits=11, dbits=10)
+
+TESTS += [
+    Test("async_big", ASYNC_BIG, ["lut", "block_tdp"], [], {"RAM_LUT": 384}),
+    Test("async_big_block", ASYNC_BIG, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}),
+    Test("async_small", ASYNC_SMALL, ["lut", "block_tdp"], [], {"RAM_LUT": 8}),
+    Test("async_small_block", ASYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 0}),
+]
+
+SYNC = """
+module top(clk, ra, wa, rd, wd, we);
+
+localparam ABITS = {abits};
+localparam DBITS = {dbits};
+
+input wire clk;
+input wire we;
+input wire [ABITS-1:0] ra, wa;
+input wire [DBITS-1:0] wd;
+output reg [DBITS-1:0] rd;
+
+{attr}
+reg [DBITS-1:0] mem [0:2**ABITS-1];
+
+always @(posedge clk)
+    if (we)
+        mem[wa] <= wd;
+
+always @(posedge clk)
+    rd <= mem[ra];
+
+endmodule
+"""
+
+SYNC_SMALL = SYNC.format(abits=6, dbits=6, attr="")
+SYNC_SMALL_BLOCK = SYNC.format(abits=6, dbits=6, attr='(* ram_style="block" *)')
+SYNC_BIG = SYNC.format(abits=11, dbits=10, attr="")
+SYNC_MID = SYNC.format(abits=6, dbits=16, attr="")
+
+TESTS += [
+    Test("sync_big", SYNC_BIG, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 20}),
+    Test("sync_big_sdp", SYNC_BIG, ["lut", "block_sdp"], [], {"RAM_BLOCK_SDP": 20}),
+    Test("sync_big_lut", SYNC_BIG, ["lut"], [], {"RAM_LUT": 384}),
+    Test("sync_small", SYNC_SMALL, ["lut", "block_tdp"], [], {"RAM_LUT": 8}),
+    Test("sync_small_block", SYNC_SMALL, ["block_tdp"], [], {"RAM_BLOCK_TDP": 1}),
+    Test("sync_small_block_attr", SYNC_SMALL_BLOCK, ["lut", "block_tdp"], [], {"RAM_BLOCK_TDP": 1}),
+]
+
+### basic TDP test
+
+TDP = """
+module top(clka, clkb, addra, addrb, rda, rdb, wda, wdb, wea, web);
+
+localparam ABITS = 6;
+localparam DBITS = 6;
+
+input wire clka, clkb;
+input wire wea, web;
+input wire [ABITS-1:0] addra, addrb;
+input wire [DBITS-1:0] wda, wdb;
+output reg [DBITS-1:0] rda, rdb;
+
+reg [DBITS-1:0] mem [0:2**ABITS-1];
+
+always @(posedge clka)
+    if (wea)
+        mem[addra] <= wda;
+    else
+        rda <= mem[addra];
+
+always @(posedge clkb)
+    if (web)
+        mem[addrb] <= wdb;
+    else
+        rdb <= mem[addrb];
+
+endmodule
+"""
+
+TESTS += [
+    Test("tdp", TDP, ["block_tdp", "block_sdp"], [], {"RAM_BLOCK_TDP": 1}),
+]
+
+# shared clock
+
+SYNC_2CLK = """
+module top(rclk, wclk, ra, wa, rd, wd, we);
+
+localparam ABITS = 6;
+localparam DBITS = 16;
+
+input wire rclk, wclk;
+input wire we;
+input wire [ABITS-1:0] ra, wa;
+input wire [DBITS-1:0] wd;
+output reg [DBITS-1:0] rd;
+
+reg [DBITS-1:0] mem [0:2**ABITS-1];
+
+always @(posedge wclk)
+    if (we)
+        mem[wa] <= wd;
+
+always @(posedge rclk)
+    rd <= mem[ra];
+
+endmodule
+"""
+
+TESTS += [
+        Test("sync_2clk", SYNC_2CLK, ["block_sdp"], [], {"RAM_BLOCK_SDP": 1}),
+        Test("sync_shared", SYNC_MID, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}),
+        Test("sync_2clk_shared", SYNC_2CLK, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 0}),
+]
+
+# inter-port transparency
+
+SYNC_TRANS = """
+module top(clk, ra, wa, rd, wd, we);
+
+localparam ABITS = 6;
+localparam DBITS = 16;
+
+input wire clk;
+input wire we;
+input wire [ABITS-1:0] ra, wa;
+input wire [DBITS-1:0] wd;
+output reg [DBITS-1:0] rd;
+
+reg [DBITS-1:0] mem [0:2**ABITS-1];
+
+always @(negedge clk)
+    if (we)
+        mem[wa] <= wd;
+
+always @(negedge clk) begin
+    rd <= mem[ra];
+    if (we && ra == wa)
+        rd <= wd;
+end
+
+endmodule
+"""
+
+TESTS += [
+        Test("sync_trans_old_old", SYNC_MID, ["block_sdp_1clk"], ["TRANS_OLD"], {"RAM_BLOCK_SDP_1CLK": (1, {"OPTION_TRANS": 0})}),
+        Test("sync_trans_old_new", SYNC_MID, ["block_sdp_1clk"], ["TRANS_NEW"], {"RAM_BLOCK_SDP_1CLK": 1}),
+        Test("sync_trans_old_none", SYNC_MID, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}),
+        Test("sync_trans_new_old", SYNC_TRANS, ["block_sdp_1clk"], ["TRANS_OLD"], {"RAM_BLOCK_SDP_1CLK": 1}),
+        Test("sync_trans_new_new", SYNC_TRANS, ["block_sdp_1clk"], ["TRANS_NEW"], {"RAM_BLOCK_SDP_1CLK": (1, {"OPTION_TRANS": 1})}),
+        Test("sync_trans_new_none", SYNC_TRANS, ["block_sdp_1clk"], [], {"RAM_BLOCK_SDP_1CLK": 1}),
+]
+
+# rdwr checks
+
+SP_NO_CHANGE = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+    else
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_NO_CHANGE_BE = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire [1:0] we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    if (we) begin
+        if (we[0])
+            mem[addr][7:0] <= wd[7:0];
+        if (we[1])
+            mem[addr][15:8] <= wd[15:8];
+    end else
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_NEW = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    if (we) begin
+        mem[addr] <= wd;
+        rd <= wd;
+    end else
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_NEW_BE = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire [1:0] we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    rd <= mem[addr];
+    if (we[0]) begin
+        mem[addr][7:0] <= wd[7:0];
+        rd[7:0] <= wd[7:0];
+    end
+    if (we[1]) begin
+        mem[addr][15:8] <= wd[15:8];
+        rd[15:8] <= wd[15:8];
+    end
+end
+
+endmodule
+"""
+
+SP_OLD = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+    rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_OLD_BE = """
+module top(clk, addr, rd, wd, we);
+
+input wire clk;
+input wire [1:0] we;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+always @(negedge clk) begin
+    if (we[0])
+        mem[addr][7:0] <= wd[7:0];
+    if (we[1])
+        mem[addr][15:8] <= wd[15:8];
+    rd <= mem[addr];
+end
+
+endmodule
+"""
+
+TESTS += [
+        Test("sp_nc_none", SP_NO_CHANGE, ["block_sp"], [], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_none", SP_NEW, ["block_sp"], [], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_none", SP_OLD, ["block_sp"], [], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_nc", SP_NO_CHANGE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_nc", SP_NEW, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_nc", SP_OLD, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_new", SP_NO_CHANGE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_new", SP_NEW, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_new", SP_OLD, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_old", SP_NO_CHANGE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_old", SP_NEW, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_old", SP_OLD, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_nc_new_only", SP_NO_CHANGE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_new_only", SP_NEW, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_new_only", SP_OLD, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_new_only_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_new_only_be", SP_NEW_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 2}),
+        Test("sp_old_new_only_be", SP_OLD_BE, ["block_sp"], ["RDWR_NEW_ONLY"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_new_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_new_be", SP_NEW_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_new_be", SP_OLD_BE, ["block_sp"], ["RDWR_NEW"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_old_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_old_be", SP_NEW_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_old_old_be", SP_OLD_BE, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_nc_nc_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_nc_be", SP_NEW_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 2}),
+        Test("sp_old_nc_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE"], {"RAM_BLOCK_SP": 0}),
+        Test("sp_nc_auto", SP_NO_CHANGE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_auto", SP_NEW, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "NEW"})}),
+        Test("sp_old_auto", SP_OLD, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}),
+        Test("sp_nc_auto_be", SP_NO_CHANGE_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": 1}),
+        Test("sp_new_auto_be", SP_NEW_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "NEW"})}),
+        Test("sp_old_auto_be", SP_OLD_BE, ["block_sp"], ["RDWR_NO_CHANGE", "RDWR_OLD", "RDWR_NEW"], {"RAM_BLOCK_SP": (1, {"OPTION_RDWR": "OLD"})}),
+]
+
+SP_INIT = """
+module top(clk, addr, rd, wd, we, re);
+
+input wire clk;
+input wire we, re;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+initial rd = {ival};
+
+always @(posedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+    if (re)
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_INIT_X = SP_INIT.format(ival="16'hxxxx")
+SP_INIT_0 = SP_INIT.format(ival="16'h0000")
+SP_INIT_V = SP_INIT.format(ival="16'h55aa")
+
+TESTS += [
+    Test("sp_init_x_x", SP_INIT_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_x_x_re", SP_INIT_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_x_x_ce", SP_INIT_X, ["block_sp"], ["CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_x", SP_INIT_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_x_re", SP_INIT_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_0", SP_INIT_0, ["block_sp"], ["RDINIT_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_0_re", SP_INIT_0, ["block_sp"], ["RDINIT_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_any", SP_INIT_0, ["block_sp"], ["RDINIT_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_0_any_re", SP_INIT_0, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_x", SP_INIT_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_x_re", SP_INIT_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_0", SP_INIT_V, ["block_sp"], ["RDINIT_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_0_re", SP_INIT_V, ["block_sp"], ["RDINIT_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_any", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_init_v_any_re", SP_INIT_V, ["block_sp"], ["RDINIT_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+]
+
+SP_ARST = """
+module top(clk, addr, rd, wd, we, re, ar);
+
+input wire clk;
+input wire we, re, ar;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+initial rd = {ival};
+
+always @(posedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+end
+always @(posedge clk, posedge ar) begin
+    if (ar)
+        rd <= {aval};
+    else if (re)
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_ARST_X = SP_ARST.format(ival="16'hxxxx", aval="16'hxxxx")
+SP_ARST_0 = SP_ARST.format(ival="16'hxxxx", aval="16'h0000")
+SP_ARST_V = SP_ARST.format(ival="16'hxxxx", aval="16'h55aa")
+SP_ARST_E = SP_ARST.format(ival="16'h55aa", aval="16'h55aa")
+SP_ARST_N = SP_ARST.format(ival="16'h1234", aval="16'h55aa")
+
+TESTS += [
+    Test("sp_arst_x_x", SP_ARST_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_x_x_re", SP_ARST_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_x", SP_ARST_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_x_re", SP_ARST_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_0", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_0_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_any", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_any_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_init", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_0_init_re", SP_ARST_0, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_x", SP_ARST_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_x_re", SP_ARST_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_0", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_0_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_any", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_any_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_init", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_v_init_re", SP_ARST_V, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_x", SP_ARST_E, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_x_re", SP_ARST_E, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_0", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_0_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_any", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_any_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_init", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_e_init_re", SP_ARST_E, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_x", SP_ARST_N, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_x_re", SP_ARST_N, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_0", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_0_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_any", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_any_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_init", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_arst_n_init_re", SP_ARST_N, ["block_sp"], ["RDINIT_ANY", "RDARST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+]
+
+SP_SRST = """
+module top(clk, addr, rd, wd, we, re, sr);
+
+input wire clk;
+input wire we, re, sr;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+initial rd = {ival};
+
+always @(posedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+end
+always @(posedge clk) begin
+    if (sr)
+        rd <= {sval};
+    else if (re)
+        rd <= mem[addr];
+end
+
+endmodule
+"""
+
+SP_SRST_G = """
+module top(clk, addr, rd, wd, we, re, sr);
+
+input wire clk;
+input wire we, re, sr;
+input wire [3:0] addr;
+input wire [15:0] wd;
+output reg [15:0] rd;
+
+reg [15:0] mem [0:15];
+
+initial rd = {ival};
+
+always @(posedge clk) begin
+    if (we)
+        mem[addr] <= wd;
+end
+always @(posedge clk) begin
+    if (re) begin
+        if (sr)
+            rd <= {sval};
+        else
+            rd <= mem[addr];
+    end
+end
+
+endmodule
+"""
+
+SP_SRST_X = SP_SRST.format(ival="16'hxxxx", sval="16'hxxxx")
+SP_SRST_0 = SP_SRST.format(ival="16'hxxxx", sval="16'h0000")
+SP_SRST_V = SP_SRST.format(ival="16'hxxxx", sval="16'h55aa")
+SP_SRST_E = SP_SRST.format(ival="16'h55aa", sval="16'h55aa")
+SP_SRST_N = SP_SRST.format(ival="16'h1234", sval="16'h55aa")
+SP_SRST_GV = SP_SRST_G.format(ival="16'hxxxx", sval="16'h55aa")
+
+TESTS += [
+    Test("sp_srst_x_x", SP_SRST_X, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_x_x_re", SP_SRST_X, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_x", SP_SRST_0, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_x_re", SP_SRST_0, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_0", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_0_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_any", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_any_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_init", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_0_init_re", SP_SRST_0, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_x", SP_SRST_V, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_x_re", SP_SRST_V, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_0", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_0_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_any", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_any_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_any_re_gated", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_RE", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_any_ce", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_any_ce_gated", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_CE", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_init", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_v_init_re", SP_SRST_V, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_x", SP_SRST_E, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_x_re", SP_SRST_E, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_0", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_0_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_any", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_any_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_init", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_e_init_re", SP_SRST_E, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_x", SP_SRST_N, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_x_re", SP_SRST_N, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_0", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_0_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_any", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_any_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_init", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_n_init_re", SP_SRST_N, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_x", SP_SRST_GV, ["block_sp"], ["RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_x_re", SP_SRST_GV, ["block_sp"], ["RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_0", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_0_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_0", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_any", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_any_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_any_re_gated", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_RE", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_any_ce", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_any_ce_gated", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_ANY_CE", "CLKEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_init", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+    Test("sp_srst_gv_init_re", SP_SRST_GV, ["block_sp"], ["RDINIT_ANY", "RDSRST_INIT", "RDEN", "RDWR_OLD"], {"RAM_BLOCK_SP": 1}),
+]
+
+WIDE_SDP = """
+module top(rclk, ra, rd, re, rr, wclk, wa, wd, we);
+
+input wire rclk, wclk, re, rr;
+input wire [2**({ww}-{bw})-1:0] we;
+input wire [{aw}-{rw}+{xw}-1:0] ra;
+input wire [{aw}-{ww}+{xw}-1:0] wa;
+input wire [2**{ww}-1:0] wd;
+output reg [2**{rw}-1:0] rd;
+
+reg mem [0:2**{aw}-1];
+
+initial mem[3] = 0;
+initial mem[17] = 1;
+initial mem[23] = 0;
+initial mem[24] = 1;
+
+integer i, j;
+always @(posedge wclk)
+    for (i = 0; i < 2**{ww}; i = i + 2**{bw})
+        if (we[i >> {bw}])
+            for (j = 0; j < 2**{bw}; j = j + 1)
+                mem[wa << {ww} | i | j] <= wd[i | j];
+
+always @(posedge rclk)
+    if (rr)
+        rd <= {sval};
+    else if (re)
+        for (i = 0; i < 2**{rw}; i = i + 1)
+            rd[i] <= mem[ra << {rw} | i];
+
+endmodule
+"""
+
+for (aw, rw, ww, bw, xw, sval, cnt) in [
+    (6, 1, 1, 1, 1, "2'h1", 1),
+    (7, 1, 1, 1, 1, "2'h2", 2),
+    (8, 1, 1, 1, 1, "2'h3", 4),
+    (6, 0, 0, 0, 0, "2'h0", 1),
+    (6, 1, 0, 0, 0, "2'h0", 1),
+    (6, 2, 0, 0, 0, "2'h0", 1),
+    (6, 3, 0, 0, 0, "2'h0", 1),
+    (6, 4, 0, 0, 0, "2'h0", 1),
+    (6, 5, 0, 0, 0, "2'h0", 2),
+    (6, 0, 1, 0, 0, "2'h0", 2),
+    (6, 0, 1, 1, 0, "2'h0", 1),
+    (6, 0, 2, 0, 0, "2'h0", 4),
+    (6, 0, 2, 2, 0, "2'h0", 1),
+    (6, 0, 3, 2, 0, "2'h0", 1),
+    (6, 0, 4, 2, 0, "2'h0", 1),
+    (6, 0, 5, 2, 0, "2'h0", 2),
+    (7, 0, 0, 0, 0, "2'h0", 2),
+    (7, 1, 0, 0, 0, "2'h0", 2),
+    (7, 2, 0, 0, 0, "2'h0", 2),
+    (7, 3, 0, 0, 0, "2'h0", 2),
+    (7, 4, 0, 0, 0, "2'h0", 2),
+    (7, 5, 0, 0, 0, "2'h0", 2),
+    (7, 0, 1, 0, 0, "2'h0", 2),
+    (7, 0, 1, 1, 0, "2'h0", 2),
+    (7, 0, 2, 0, 0, "2'h0", 4),
+    (7, 0, 2, 2, 0, "2'h0", 2),
+    (7, 0, 3, 2, 0, "2'h0", 2),
+    (7, 0, 4, 2, 0, "2'h0", 2),
+    (7, 0, 5, 2, 0, "2'h0", 2),
+]:
+    TESTS.append(Test(
+        f"wide_sdp_a{aw}r{rw}w{ww}b{bw}x{xw}",
+        WIDE_SDP.format(aw=aw, rw=rw, ww=ww, bw=bw, xw=xw, sval=sval),
+        ["wide_sdp"], [],
+        {"RAM_WIDE_SDP": cnt}
+    ))
+
+WIDE_SP = """
+module top(clk, a, rd, re, rr, wd, we);
+
+input wire clk, re, rr;
+input wire [2**({ww}-{bw})-1:0] we;
+input wire [{aw}-1:0] a;
+input wire [2**{ww}-1:0] wd;
+output reg [2**{rw}-1:0] rd;
+
+reg mem [0:2**{aw}-1];
+
+initial mem[3] = 0;
+initial mem[17] = 1;
+initial mem[23] = 0;
+initial mem[24] = 1;
+
+integer i, j;
+always @(posedge clk) begin
+    for (i = 0; i < 2**{ww}; i = i + 2**{bw})
+        if (we[i >> {bw}])
+            for (j = 0; j < 2**{bw}; j = j + 1)
+                mem[a & ~((1 << {ww}) - 1) | i | j] <= wd[i | j];
+    if (rr)
+        rd <= {sval};
+    else if (re)
+        for (i = 0; i < 2**{rw}; i = i + 1)
+            rd[i] <= mem[a & ~((1 << {rw}) - 1) | i];
+end
+
+endmodule
+"""
+
+for (aw, rw, ww, bw, sval, cnt) in [
+    (6, 1, 1, 1, "2'h1", 1),
+    (7, 1, 1, 1, "2'h2", 2),
+    (8, 1, 1, 1, "2'h3", 4),
+    (6, 0, 0, 0, "2'h0", 1),
+    (6, 1, 0, 0, "2'h0", 1),
+    (6, 2, 0, 0, "2'h0", 1),
+    (6, 3, 0, 0, "2'h0", 1),
+    (6, 4, 0, 0, "2'h0", 1),
+    (6, 5, 0, 0, "2'h0", 2),
+    (6, 0, 1, 0, "2'h0", 2),
+    (6, 0, 1, 1, "2'h0", 1),
+    (6, 0, 2, 0, "2'h0", 4),
+    (6, 0, 2, 2, "2'h0", 1),
+    (6, 0, 3, 2, "2'h0", 1),
+    (6, 0, 4, 2, "2'h0", 1),
+    (6, 0, 5, 2, "2'h0", 2),
+    (7, 0, 0, 0, "2'h0", 2),
+    (7, 1, 0, 0, "2'h0", 2),
+    (7, 2, 0, 0, "2'h0", 2),
+    (7, 3, 0, 0, "2'h0", 2),
+    (7, 4, 0, 0, "2'h0", 2),
+    (7, 5, 0, 0, "2'h0", 2),
+    (7, 0, 1, 0, "2'h0", 2),
+    (7, 0, 1, 1, "2'h0", 2),
+    (7, 0, 2, 0, "2'h0", 4),
+    (7, 0, 2, 2, "2'h0", 2),
+    (7, 0, 3, 2, "2'h0", 2),
+    (7, 0, 4, 2, "2'h0", 2),
+    (7, 0, 5, 2, "2'h0", 2),
+]:
+    TESTS.append(Test(
+        f"wide_sp_mix_a{aw}r{rw}w{ww}b{bw}",
+        WIDE_SP.format(aw=aw, rw=rw, ww=ww, bw=bw, sval=sval),
+        ["wide_sp"], ["WIDTH_MIX"],
+        {"RAM_WIDE_SP": cnt}
+    ))
+
+for (aw, rw, ww, bw, sval, cnt) in [
+    (6, 1, 1, 1, "2'h1", 1),
+    (7, 1, 1, 1, "2'h2", 2),
+    (8, 1, 1, 1, "2'h3", 4),
+    (6, 0, 0, 0, "2'h0", 1),
+    (6, 1, 0, 0, "2'h0", 2),
+    (6, 2, 0, 0, "2'h0", 4),
+    (6, 3, 0, 0, "2'h0", 4),
+    (6, 4, 0, 0, "2'h0", 4),
+    (6, 5, 0, 0, "2'h0", 8),
+    (6, 0, 1, 0, "2'h0", 2),
+    (6, 0, 1, 1, "2'h0", 1),
+    (6, 0, 2, 0, "2'h0", 4),
+    (6, 0, 2, 2, "2'h0", 1),
+    (6, 0, 3, 2, "2'h0", 1),
+    (6, 0, 4, 2, "2'h0", 1),
+    (6, 0, 5, 2, "2'h0", 2),
+    (7, 0, 0, 0, "2'h0", 2),
+    (7, 1, 0, 0, "2'h0", 2),
+    (7, 2, 0, 0, "2'h0", 4),
+    (7, 3, 0, 0, "2'h0", 8),
+    (7, 4, 0, 0, "2'h0", 8),
+    (7, 5, 0, 0, "2'h0", 8),
+    (7, 0, 1, 0, "2'h0", 2),
+    (7, 0, 1, 1, "2'h0", 2),
+    (7, 0, 2, 0, "2'h0", 4),
+    (7, 0, 2, 2, "2'h0", 2),
+    (7, 0, 3, 2, "2'h0", 2),
+    (7, 0, 4, 2, "2'h0", 2),
+    (7, 0, 5, 2, "2'h0", 2),
+]:
+    TESTS.append(Test(
+        f"wide_sp_tied_a{aw}r{rw}w{ww}b{bw}",
+        WIDE_SP.format(aw=aw, rw=rw, ww=ww, bw=bw, sval=sval),
+        ["wide_sp"], [],
+        {"RAM_WIDE_SP": cnt}
+    ))
+
+WIDE_RW = """
+module top(clk, a, rd, re, wd, we);
+
+input wire clk, re;
+input wire [2**({ww}-{bw})-1:0] we;
+input wire [{aw}-1:0] a;
+input wire [2**{ww}-1:0] wd;
+output reg [2**{rw}-1:0] rd;
+
+(* ram_block *)
+reg mem [0:2**{aw}-1];
+
+initial mem[3] = 0;
+initial mem[17] = 1;
+initial mem[23] = 0;
+initial mem[24] = 1;
+
+integer i, j;
+always @(posedge clk) begin
+    for (i = 0; i < 2**{ww}; i = i + 2**{bw})
+        if (we[i >> {bw}])
+            for (j = 0; j < 2**{bw}; j = j + 1)
+                mem[a & ~((1 << {ww}) - 1) | i | j] <= wd[i | j];
+    if (re)
+        for (i = 0; i < 2**{rw}; i = i + 1)
+            rd[i] <= mem[a & ~((1 << {rw}) - 1) | i];
+end
+
+endmodule
+"""
+
+for (aw, rw, ww, bw, cntww, cntwr) in [
+    (6, 1, 1, 1, 2, 1),
+    (7, 1, 1, 1, 4, 2),
+    (8, 1, 1, 1, 8, 4),
+    (6, 0, 0, 0, 4, 2),
+    (6, 1, 0, 0, 4, 2),
+    (6, 2, 0, 0, 4, 2),
+    (6, 3, 0, 0, 8, 2),
+    (6, 4, 0, 0, 16, 4),
+    (6, 5, 0, 0, 32, 8),
+    (6, 0, 1, 0, 4, 2),
+    (6, 0, 1, 1, 2, 1),
+    (6, 0, 2, 0, 4, 4),
+    (6, 0, 2, 2, 1, 2),
+    (6, 0, 3, 2, 1, 4),
+    (6, 0, 4, 2, 2, 8),
+    (6, 0, 5, 2, 4, 16),
+    (7, 0, 0, 0, 8, 4),
+    (7, 1, 0, 0, 8, 4),
+    (7, 2, 0, 0, 8, 4),
+    (7, 3, 0, 0, 8, 4),
+    (7, 4, 0, 0, 16, 4),
+    (7, 5, 0, 0, 32, 8),
+    (7, 0, 1, 0, 8, 4),
+    (7, 0, 1, 1, 4, 2),
+    (7, 0, 2, 0, 8, 4),
+    (7, 0, 2, 2, 2, 2),
+    (7, 0, 3, 2, 2, 4),
+    (7, 0, 4, 2, 2, 8),
+    (7, 0, 5, 2, 4, 16),
+]:
+    TESTS.append(Test(
+        f"wide_read_a{aw}r{rw}w{ww}b{bw}",
+        WIDE_RW.format(aw=aw, rw=rw, ww=ww, bw=bw),
+        ["wide_read"], [],
+        {"RAM_WIDE_READ": cntwr}
+    ))
+    TESTS.append(Test(
+        f"wide_write_a{aw}r{rw}w{ww}b{bw}",
+        WIDE_RW.format(aw=aw, rw=rw, ww=ww, bw=bw),
+        ["wide_write"], [],
+        {"RAM_WIDE_WRITE": cntww}
+    ))
+
+with open("run-test.mk", "w") as mf:
+    mf.write("ifneq ($(strip $(SEED)),)\n")
+    mf.write("SEEDOPT=-S$(SEED)\n")
+    mf.write("endif\n")
+    mf.write("all:")
+    for t in TESTS:
+        mf.write(" " + t.name)
+    mf.write("\n")
+    mf.write(".PHONY: all\n")
+
+
+    for t in TESTS:
+        with open("t_{}.v".format(t.name), "w") as tf:
+            tf.write(t.src)
+        with open("t_{}.ys".format(t.name), "w") as sf:
+            sf.write("proc\n")
+            sf.write("opt\n")
+            sf.write("opt -full\n")
+            sf.write("memory -nomap\n")
+            sf.write("dump\n")
+            sf.write("memory_libmap")
+            for lib in t.libs:
+                sf.write(" -lib ../memlib_{}.txt".format(lib))
+            for d in t.defs:
+                sf.write(" -D {}".format(d))
+            sf.write("\n")
+            sf.write("memory_map\n")
+            for k, v in t.cells.items():
+                if isinstance(v, tuple):
+                    (cc, ca) = v
+                    sf.write("select -assert-count {} t:{}\n".format(cc, k))
+                    for kk, vv in ca.items():
+                        sf.write("select -assert-count {} t:{} r:{}={} %i\n".format(cc, k, kk, vv))
+                else:
+                    sf.write("select -assert-count {} t:{}\n".format(v, k))
+        mf.write("{}:\n".format(t.name))
+        mf.write("\t@../tools/autotest.sh -G -j $(SEEDOPT) $(EXTRA_FLAGS) -p 'script ../t_{}.ys'".format(t.name))
+        for lib in t.libs:
+            mf.write(" -l memlib_{}.v".format(lib))
+        mf.write(" t_{}.v || (cat t_{}.err; exit 1)\n".format(t.name, t.name))
+        mf.write(".PHONY: {}\n".format(t.name))
diff --git a/tests/memlib/memlib_block_sdp.txt b/tests/memlib/memlib_block_sdp.txt
new file mode 100644 (file)
index 0000000..6c34c5a
--- /dev/null
@@ -0,0 +1,12 @@
+ram block \RAM_BLOCK_SDP {
+       cost 64;
+       abits 10;
+       widths 1 2 4 8 16 per_port;
+       init any;
+       port sw "W" {
+               clock anyedge;
+       }
+       port sr "R" {
+               clock anyedge;
+       }
+}
diff --git a/tests/memlib/memlib_block_sdp.v b/tests/memlib/memlib_block_sdp.v
new file mode 100644 (file)
index 0000000..d8dac68
--- /dev/null
@@ -0,0 +1,26 @@
+module RAM_BLOCK_SDP(
+       input PORT_R_CLK,
+       input [9:0] PORT_R_ADDR,
+       output reg [15:0] PORT_R_RD_DATA,
+       input PORT_W_CLK,
+       input PORT_W_WR_EN,
+       input [9:0] PORT_W_ADDR,
+       input [15:0] PORT_W_WR_DATA
+);
+
+parameter INIT = 0;
+parameter PORT_R_WIDTH = 1;
+parameter PORT_W_WIDTH = 1;
+parameter PORT_R_CLK_POL = 0;
+parameter PORT_W_CLK_POL = 0;
+
+reg [2**10-1:0] mem = INIT;
+
+always @(negedge (PORT_R_CLK ^ PORT_R_CLK_POL))
+       PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH];
+
+always @(negedge (PORT_W_CLK ^ PORT_W_CLK_POL))
+       if (PORT_W_WR_EN)
+               mem[PORT_W_ADDR+:PORT_W_WIDTH] <= PORT_W_WR_DATA;
+
+endmodule
diff --git a/tests/memlib/memlib_block_sdp_1clk.txt b/tests/memlib/memlib_block_sdp_1clk.txt
new file mode 100644 (file)
index 0000000..07c76c2
--- /dev/null
@@ -0,0 +1,22 @@
+ram block \RAM_BLOCK_SDP_1CLK {
+       cost 64;
+       abits 10;
+       widths 1 2 4 8 16 per_port;
+       init any;
+       port sw "W" {
+               clock anyedge "C";
+               ifdef TRANS_OLD {
+                       option "TRANS" 0 {
+                               wrtrans "R" old;
+                       }
+               }
+               ifdef TRANS_NEW {
+                       option "TRANS" 1 {
+                               wrtrans "R" new;
+                       }
+               }
+       }
+       port sr "R" {
+               clock anyedge "C";
+       }
+}
diff --git a/tests/memlib/memlib_block_sdp_1clk.v b/tests/memlib/memlib_block_sdp_1clk.v
new file mode 100644 (file)
index 0000000..5e8159f
--- /dev/null
@@ -0,0 +1,36 @@
+module RAM_BLOCK_SDP_1CLK(
+       input CLK_C,
+       input PORT_R_CLK,
+       input [9:0] PORT_R_ADDR,
+       output reg [15:0] PORT_R_RD_DATA,
+       input PORT_W_CLK,
+       input PORT_W_WR_EN,
+       input [9:0] PORT_W_ADDR,
+       input [15:0] PORT_W_WR_DATA
+);
+
+parameter PORT_R_CLK_POL = 0;
+parameter PORT_W_CLK_POL = 0;
+parameter CLK_C_POL = 0;
+parameter INIT = 0;
+parameter OPTION_TRANS = 2;
+parameter PORT_R_WIDTH = 1;
+parameter PORT_W_WIDTH = 1;
+
+reg [2**10-1:0] mem = INIT;
+
+always @(negedge (CLK_C ^ CLK_C_POL)) begin
+       if (OPTION_TRANS == 0)
+               PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH];
+       if (PORT_W_WR_EN)
+               mem[PORT_W_ADDR+:PORT_W_WIDTH] = 16'hx;
+       if (OPTION_TRANS == 2)
+               PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH];
+       if (PORT_W_WR_EN)
+               mem[PORT_W_ADDR+:PORT_W_WIDTH] = PORT_W_WR_DATA;
+       if (OPTION_TRANS == 1)
+               PORT_R_RD_DATA <= mem[PORT_R_ADDR+:PORT_R_WIDTH];
+end
+
+
+endmodule
diff --git a/tests/memlib/memlib_block_sp.txt b/tests/memlib/memlib_block_sp.txt
new file mode 100644 (file)
index 0000000..f99320d
--- /dev/null
@@ -0,0 +1,95 @@
+ram block \RAM_BLOCK_SP {
+       cost 2;
+       abits 4;
+       width 16;
+       byte 8;
+       port srsw "A" {
+               clock posedge;
+               ifdef CLKEN {
+                       clken;
+               }
+               ifdef RDEN {
+                       rden;
+               }
+               ifdef RDWR_NO_CHANGE {
+                       option "RDWR" "NO_CHANGE" {
+                               rdwr no_change;
+                       }
+               }
+               ifdef RDWR_OLD {
+                       option "RDWR" "OLD" {
+                               rdwr old;
+                       }
+               }
+               ifdef RDWR_NEW {
+                       option "RDWR" "NEW" {
+                               rdwr new;
+                       }
+               }
+               ifdef RDWR_NEW_ONLY {
+                       option "RDWR" "NEW_ONLY" {
+                               rdwr new_only;
+                       }
+               }
+               ifdef RDINIT_0 {
+                       option "RDINIT" "ZERO" {
+                               rdinit zero;
+                       }
+               }
+               ifdef RDINIT_ANY {
+                       option "RDINIT" "ANY" {
+                               rdinit any;
+                       }
+               }
+               ifdef RDARST_0 {
+                       option "RDARST" "ZERO" {
+                               rdarst zero;
+                       }
+               }
+               ifdef RDARST_ANY {
+                       option "RDARST" "ANY" {
+                               rdarst any;
+                       }
+               }
+               ifdef RDARST_INIT {
+                       option "RDARST" "INIT" {
+                               rdarst init;
+                       }
+               }
+               ifdef RDSRST_0 {
+                       option "SRST_GATE" 0 {
+                               option "RDSRST" "ZERO" {
+                                       rdsrst zero ungated;
+                               }
+                       }
+               }
+               ifdef RDSRST_ANY {
+                       option "SRST_GATE" 0 {
+                               option "RDSRST" "ANY" {
+                                       rdsrst any ungated;
+                               }
+                       }
+               }
+               ifdef RDSRST_INIT {
+                       option "SRST_GATE" 0 {
+                               option "RDSRST" "INIT" {
+                                       rdsrst init ungated;
+                               }
+                       }
+               }
+               ifdef RDSRST_ANY_CE {
+                       option "SRST_GATE" 1 {
+                               option "RDSRST" "ANY" {
+                                       rdsrst any gated_clken;
+                               }
+                       }
+               }
+               ifdef RDSRST_ANY_RE {
+                       option "SRST_GATE" 2 {
+                               option "RDSRST" "ANY" {
+                                       rdsrst any gated_rden;
+                               }
+                       }
+               }
+       }
+}
diff --git a/tests/memlib/memlib_block_sp.v b/tests/memlib/memlib_block_sp.v
new file mode 100644 (file)
index 0000000..1f78301
--- /dev/null
@@ -0,0 +1,81 @@
+module RAM_BLOCK_SP(
+       input PORT_A_CLK,
+       input PORT_A_CLK_EN,
+       input PORT_A_RD_EN,
+       input PORT_A_RD_ARST,
+       input PORT_A_RD_SRST,
+       input [1:0] PORT_A_WR_EN,
+       input [3:0] PORT_A_ADDR,
+       output reg [15:0] PORT_A_RD_DATA,
+       input [15:0] PORT_A_WR_DATA
+);
+
+parameter OPTION_RDWR = "UNDEFINED";
+parameter OPTION_RDINIT = "UNDEFINED";
+parameter OPTION_RDARST = "UNDEFINED";
+parameter OPTION_RDSRST = "UNDEFINED";
+parameter OPTION_SRST_GATE = 0;
+parameter PORT_A_RD_INIT_VALUE = 16'hxxxx;
+parameter PORT_A_RD_ARST_VALUE = 16'hxxxx;
+parameter PORT_A_RD_SRST_VALUE = 16'hxxxx;
+
+reg [15:0] mem [0:15];
+
+initial
+       if (OPTION_RDINIT == "ZERO")
+               PORT_A_RD_DATA = 0;
+       else if (OPTION_RDINIT == "ANY")
+               PORT_A_RD_DATA = PORT_A_RD_INIT_VALUE;
+
+localparam ARST_VALUE = 
+       (OPTION_RDARST == "ZERO") ? 16'h0000 :
+       (OPTION_RDARST == "INIT") ? PORT_A_RD_INIT_VALUE :
+       (OPTION_RDARST == "ANY") ? PORT_A_RD_ARST_VALUE :
+       16'hxxxx;
+
+localparam SRST_VALUE = 
+       (OPTION_RDSRST == "ZERO") ? 16'h0000 :
+       (OPTION_RDSRST == "INIT") ? PORT_A_RD_INIT_VALUE :
+       (OPTION_RDSRST == "ANY") ? PORT_A_RD_SRST_VALUE :
+       16'hxxxx;
+
+pullup (PORT_A_CLK_EN);
+pullup (PORT_A_RD_EN);
+pulldown (PORT_A_RD_ARST);
+pulldown (PORT_A_RD_SRST);
+
+always @(posedge PORT_A_CLK) begin
+       if (PORT_A_CLK_EN) begin
+               if (PORT_A_WR_EN[0])
+                       mem[PORT_A_ADDR][7:0] <= PORT_A_WR_DATA[7:0];
+               if (PORT_A_WR_EN[1])
+                       mem[PORT_A_ADDR][15:8] <= PORT_A_WR_DATA[15:8];
+               if (PORT_A_RD_EN && (!PORT_A_WR_EN || OPTION_RDWR != "NO_CHANGE")) begin
+                       PORT_A_RD_DATA <= mem[PORT_A_ADDR];
+                       if (PORT_A_WR_EN && OPTION_RDWR == "NEW_ONLY")
+                               PORT_A_RD_DATA <= 16'hx;
+                       if (PORT_A_WR_EN[0])
+                               case (OPTION_RDWR)
+                               "NEW": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0];
+                               "NEW_ONLY": PORT_A_RD_DATA[7:0] <= PORT_A_WR_DATA[7:0];
+                               "UNDEFINED": PORT_A_RD_DATA[7:0] <= 8'hx;
+                               endcase
+                       if (PORT_A_WR_EN[1])
+                               case (OPTION_RDWR)
+                               "NEW": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8];
+                               "NEW_ONLY": PORT_A_RD_DATA[15:8] <= PORT_A_WR_DATA[15:8];
+                               "UNDEFINED": PORT_A_RD_DATA[15:8] <= 8'hx;
+                               endcase
+               end
+       end
+       if (PORT_A_RD_SRST && (!OPTION_SRST_GATE || (OPTION_SRST_GATE == 2 && PORT_A_RD_EN) || (OPTION_SRST_GATE == 1 && PORT_A_CLK_EN)))
+               PORT_A_RD_DATA <= SRST_VALUE;
+end
+
+always @(PORT_A_RD_ARST)
+       if (PORT_A_RD_ARST)
+               force PORT_A_RD_DATA = ARST_VALUE;
+       else
+               release PORT_A_RD_DATA;
+
+endmodule
diff --git a/tests/memlib/memlib_block_tdp.txt b/tests/memlib/memlib_block_tdp.txt
new file mode 100644 (file)
index 0000000..80cc7e5
--- /dev/null
@@ -0,0 +1,10 @@
+ram block \RAM_BLOCK_TDP {
+       cost 64;
+       abits 10;
+       widths 1 2 4 8 16 per_port;
+       init any;
+       port srsw "A" "B" {
+               clock anyedge;
+               rdwr no_change;
+       }
+}
diff --git a/tests/memlib/memlib_block_tdp.v b/tests/memlib/memlib_block_tdp.v
new file mode 100644 (file)
index 0000000..c6b8763
--- /dev/null
@@ -0,0 +1,38 @@
+module RAM_BLOCK_TDP(
+       input PORT_A_CLK,
+       input PORT_A_WR_EN,
+       input [9:0] PORT_A_ADDR,
+       input [15:0] PORT_A_WR_DATA,
+       output reg [15:0] PORT_A_RD_DATA,
+       input PORT_B_CLK,
+       input PORT_B_WR_EN,
+       input [9:0] PORT_B_ADDR,
+       input [15:0] PORT_B_WR_DATA,
+       output reg [15:0] PORT_B_RD_DATA
+);
+
+parameter INIT = 0;
+parameter PORT_A_WIDTH = 1;
+parameter PORT_B_WIDTH = 1;
+parameter PORT_A_CLK_POL = 0;
+parameter PORT_B_CLK_POL = 0;
+
+reg [2**10-1:0] mem = INIT;
+
+always @(negedge (PORT_A_CLK ^ PORT_A_CLK_POL)) begin
+       if (PORT_A_WR_EN) begin
+               mem[PORT_A_ADDR+:PORT_A_WIDTH] <= PORT_A_WR_DATA;
+       end else begin
+               PORT_A_RD_DATA <= mem[PORT_A_ADDR+:PORT_A_WIDTH];
+       end
+end
+
+always @(negedge (PORT_B_CLK ^ PORT_B_CLK_POL)) begin
+       if (PORT_B_WR_EN) begin
+               mem[PORT_B_ADDR+:PORT_B_WIDTH] <= PORT_B_WR_DATA;
+       end else begin
+               PORT_B_RD_DATA <= mem[PORT_B_ADDR+:PORT_B_WIDTH];
+       end
+end
+
+endmodule
diff --git a/tests/memlib/memlib_lut.txt b/tests/memlib/memlib_lut.txt
new file mode 100644 (file)
index 0000000..0cc8fda
--- /dev/null
@@ -0,0 +1,12 @@
+ram distributed \RAM_LUT {
+       abits 4;
+       width 4;
+       init any;
+       cost 4;
+       port ar "R" {
+       }
+       port arsw "RW" {
+               clock anyedge;
+       }
+}
+
diff --git a/tests/memlib/memlib_lut.v b/tests/memlib/memlib_lut.v
new file mode 100644 (file)
index 0000000..1f20a11
--- /dev/null
@@ -0,0 +1,30 @@
+module RAM_LUT(
+       input [3:0] PORT_R_ADDR,
+       input [3:0] PORT_RW_ADDR,
+       input PORT_RW_CLK,
+       input PORT_RW_WR_EN,
+       input [3:0] PORT_RW_WR_DATA,
+       output [3:0] PORT_R_RD_DATA,
+       output [3:0] PORT_RW_RD_DATA
+);
+
+parameter INIT = 0;
+parameter PORT_RW_CLK_POL = 1;
+
+reg [3:0] mem [0:15];
+
+integer i;
+initial
+       for (i = 0; i < 16; i += 1)
+               mem[i] = INIT[i*4+:4];
+
+assign PORT_R_RD_DATA = mem[PORT_R_ADDR];
+assign PORT_RW_RD_DATA = mem[PORT_RW_ADDR];
+
+wire CLK = PORT_RW_CLK ~^ PORT_RW_CLK_POL;
+
+always @(posedge CLK)
+       if (PORT_RW_WR_EN)
+               mem[PORT_RW_ADDR] <= PORT_RW_WR_DATA;
+
+endmodule
diff --git a/tests/memlib/memlib_wide_read.txt b/tests/memlib/memlib_wide_read.txt
new file mode 100644 (file)
index 0000000..c110210
--- /dev/null
@@ -0,0 +1,12 @@
+ram block \RAM_WIDE_READ {
+       cost 2;
+       abits 6;
+       widths 1 2 4 8 per_port;
+       init any;
+       port srsw "A" {
+               width rd 8 wr 2;
+               clock posedge;
+               rden;
+               rdwr old;
+       }
+}
diff --git a/tests/memlib/memlib_wide_read.v b/tests/memlib/memlib_wide_read.v
new file mode 100644 (file)
index 0000000..e45f643
--- /dev/null
@@ -0,0 +1,25 @@
+module RAM_WIDE_READ #(
+       parameter [63:0] INIT = 64'hx,
+       parameter PORT_A_RD_WIDTH = 8,
+       parameter PORT_A_WR_WIDTH = 2
+) (
+       input PORT_A_CLK,
+       input PORT_A_RD_EN,
+       input [5:0] PORT_A_ADDR,
+       output reg [7:0] PORT_A_RD_DATA,
+       input PORT_A_WR_EN,
+       input [1:0] PORT_A_WR_DATA
+);
+
+reg [63:0] mem;
+
+initial mem = INIT;
+
+always @(posedge PORT_A_CLK) begin
+       if (PORT_A_RD_EN)
+               PORT_A_RD_DATA <= mem[{PORT_A_ADDR[5:3], 3'b000}+:8];
+       if (PORT_A_WR_EN)
+               mem[{PORT_A_ADDR[5:1],1'b0}+:2] <= PORT_A_WR_DATA;
+end
+
+endmodule
diff --git a/tests/memlib/memlib_wide_sdp.txt b/tests/memlib/memlib_wide_sdp.txt
new file mode 100644 (file)
index 0000000..ec90c45
--- /dev/null
@@ -0,0 +1,17 @@
+ram block \RAM_WIDE_SDP {
+       cost 2;
+       abits 6;
+       widths 1 2 5 10 20 per_port;
+       byte 5;
+       init any;
+       port sr "R" {
+               clock posedge;
+               rden;
+               rdsrst any ungated;
+       }
+       port sw "W" {
+               clock posedge;
+               wrtrans "R" old;
+               wrbe_separate;
+       }
+}
diff --git a/tests/memlib/memlib_wide_sdp.v b/tests/memlib/memlib_wide_sdp.v
new file mode 100644 (file)
index 0000000..4568531
--- /dev/null
@@ -0,0 +1,45 @@
+module RAM_WIDE_SDP #(
+       parameter [79:0] INIT = 80'hx,
+       parameter PORT_R_WIDTH = 1,
+       parameter PORT_W_WIDTH = 1,
+       parameter PORT_W_WR_BE_WIDTH = 1,
+       parameter PORT_R_RD_SRST_VALUE = 16'hx
+) (
+       input PORT_R_CLK,
+       input PORT_R_RD_EN,
+       input PORT_R_RD_SRST,
+       input [5:0] PORT_R_ADDR,
+       output reg [PORT_R_WIDTH-1:0] PORT_R_RD_DATA,
+       input PORT_W_CLK,
+       input PORT_W_WR_EN,
+       input [PORT_W_WR_BE_WIDTH-1:0] PORT_W_WR_BE,
+       input [5:0] PORT_W_ADDR,
+       input [PORT_W_WIDTH-1:0] PORT_W_WR_DATA
+);
+
+reg [79:0] mem;
+
+initial mem = INIT;
+
+always @(posedge PORT_R_CLK)
+       if (PORT_R_RD_SRST)
+               PORT_R_RD_DATA <= PORT_R_RD_SRST_VALUE;
+       else if (PORT_R_RD_EN)
+               PORT_R_RD_DATA <= mem[PORT_R_ADDR[5:2] * 5 + PORT_R_ADDR[1:0]+:PORT_R_WIDTH];
+
+generate
+       if (PORT_W_WIDTH < 5) begin
+               always @(posedge PORT_W_CLK)
+                       if (PORT_W_WR_EN && PORT_W_WR_BE[0])
+                               mem[PORT_W_ADDR[5:2] * 5 + PORT_W_ADDR[1:0]+:PORT_W_WIDTH] <= PORT_W_WR_DATA;
+       end else begin
+               integer i;
+               always @(posedge PORT_W_CLK)
+                       if (PORT_W_WR_EN)
+                               for (i = 0; i < PORT_W_WR_BE_WIDTH; i = i + 1)
+                                       if (PORT_W_WR_BE[i])
+                                               mem[(PORT_W_ADDR[5:2] + i) * 5+:5] <= PORT_W_WR_DATA[i * 5+:5];
+       end
+endgenerate
+
+endmodule
diff --git a/tests/memlib/memlib_wide_sp.txt b/tests/memlib/memlib_wide_sp.txt
new file mode 100644 (file)
index 0000000..7780e4f
--- /dev/null
@@ -0,0 +1,22 @@
+ram block \RAM_WIDE_SP {
+       cost 2;
+       abits 6;
+       widths 1 2 5 10 20 per_port;
+       byte 5;
+       init any;
+       port srsw "A" {
+               ifdef WIDTH_MIX {
+                       option "WIDTH_MIX" 1 {
+                               width mix;
+                       }
+               } else {
+                       option "WIDTH_MIX" 0 {
+                               width tied;
+                       }
+               }
+               clock posedge;
+               rden;
+               rdwr old;
+               rdsrst any ungated;
+       }
+}
diff --git a/tests/memlib/memlib_wide_sp.v b/tests/memlib/memlib_wide_sp.v
new file mode 100644 (file)
index 0000000..920a333
--- /dev/null
@@ -0,0 +1,54 @@
+module RAM_WIDE_SP #(
+       parameter [79:0] INIT = 80'hx,
+       parameter PORT_A_RD_WIDTH = 1,
+       parameter PORT_A_WR_WIDTH = 1,
+       parameter PORT_A_WIDTH = 1,
+       parameter OPTION_WIDTH_MIX = 0,
+       parameter PORT_A_WR_EN_WIDTH = 1,
+       parameter PORT_A_RD_SRST_VALUE = 16'hx,
+       parameter RD_WIDTH = OPTION_WIDTH_MIX ? PORT_A_RD_WIDTH : PORT_A_WIDTH,
+       parameter WR_WIDTH = OPTION_WIDTH_MIX ? PORT_A_WR_WIDTH : PORT_A_WIDTH
+) (
+       input PORT_A_CLK,
+       input PORT_A_RD_EN,
+       input PORT_A_RD_SRST,
+       input [5:0] PORT_A_ADDR,
+       output reg [RD_WIDTH-1:0] PORT_A_RD_DATA,
+       input [PORT_A_WR_EN_WIDTH-1:0] PORT_A_WR_EN,
+       input [WR_WIDTH-1:0] PORT_A_WR_DATA
+);
+
+reg [79:0] mem;
+
+initial mem = INIT;
+
+always @(posedge PORT_A_CLK)
+       if (PORT_A_RD_SRST)
+               PORT_A_RD_DATA <= PORT_A_RD_SRST_VALUE;
+       else if (PORT_A_RD_EN)
+               case (RD_WIDTH)
+               1: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1:0]+:1];
+               2: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1] * 2+:2];
+               5: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:2] * 5+:5];
+               10: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:3] * 10+:10];
+               20: PORT_A_RD_DATA <= mem[PORT_A_ADDR[5:4] * 20+:20];
+               endcase
+
+always @(posedge PORT_A_CLK)
+       case (WR_WIDTH)
+       1: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1:0]+:1] <= PORT_A_WR_DATA;
+       2: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5 + PORT_A_ADDR[1] * 2+:2] <= PORT_A_WR_DATA;
+       5: if (PORT_A_WR_EN) mem[PORT_A_ADDR[5:2] * 5+:5] <= PORT_A_WR_DATA;
+       10: begin
+               if (PORT_A_WR_EN[0]) mem[PORT_A_ADDR[5:3] * 10+:5] <= PORT_A_WR_DATA[4:0];
+               if (PORT_A_WR_EN[1]) mem[PORT_A_ADDR[5:3] * 10 + 5+:5] <= PORT_A_WR_DATA[9:5];
+       end
+       20: begin
+               if (PORT_A_WR_EN[0]) mem[PORT_A_ADDR[5:4] * 20+:5] <= PORT_A_WR_DATA[4:0];
+               if (PORT_A_WR_EN[1]) mem[PORT_A_ADDR[5:4] * 20 + 5+:5] <= PORT_A_WR_DATA[9:5];
+               if (PORT_A_WR_EN[2]) mem[PORT_A_ADDR[5:4] * 20 + 10+:5] <= PORT_A_WR_DATA[14:10];
+               if (PORT_A_WR_EN[3]) mem[PORT_A_ADDR[5:4] * 20 + 15+:5] <= PORT_A_WR_DATA[19:15];
+       end
+       endcase
+
+endmodule
diff --git a/tests/memlib/memlib_wide_write.txt b/tests/memlib/memlib_wide_write.txt
new file mode 100644 (file)
index 0000000..59222b7
--- /dev/null
@@ -0,0 +1,13 @@
+ram block \RAM_WIDE_WRITE {
+       cost 2;
+       abits 6;
+       widths 1 2 4 8 per_port;
+       byte 4;
+       init any;
+       port srsw "A" {
+               width rd 2 wr 8;
+               clock posedge;
+               rden;
+               rdwr old;
+       }
+}
diff --git a/tests/memlib/memlib_wide_write.v b/tests/memlib/memlib_wide_write.v
new file mode 100644 (file)
index 0000000..afed6d0
--- /dev/null
@@ -0,0 +1,29 @@
+module RAM_WIDE_WRITE #(
+       parameter [63:0] INIT = 64'hx,
+       parameter PORT_A_RD_WIDTH = 2,
+       parameter PORT_A_WR_WIDTH = 8,
+       parameter PORT_A_WR_EN_WIDTH = 2
+) (
+       input PORT_A_CLK,
+       input PORT_A_RD_EN,
+       input [5:0] PORT_A_ADDR,
+       output reg [1:0] PORT_A_RD_DATA,
+       input [1:0] PORT_A_WR_EN,
+       input [7:0] PORT_A_WR_DATA
+);
+
+reg [63:0] mem;
+
+initial mem = INIT;
+
+always @(posedge PORT_A_CLK) begin
+       if (PORT_A_RD_EN)
+               PORT_A_RD_DATA <= mem[{PORT_A_ADDR[5:1],1'b0}+:2];
+       if (PORT_A_WR_EN[0])
+               mem[{PORT_A_ADDR[5:3],3'b000}+:4] <= PORT_A_WR_DATA[3:0];
+       if (PORT_A_WR_EN[1])
+               mem[{PORT_A_ADDR[5:3],3'b100}+:4] <= PORT_A_WR_DATA[7:4];
+end
+
+endmodule
+
diff --git a/tests/memlib/run-test.sh b/tests/memlib/run-test.sh
new file mode 100755 (executable)
index 0000000..abe88a6
--- /dev/null
@@ -0,0 +1,15 @@
+#!/bin/bash
+set -eu
+
+OPTIND=1
+seed=""    # default to no seed specified
+while getopts "S:" opt
+do
+    case "$opt" in
+       S) seed="$OPTARG" ;;
+    esac
+done
+shift "$((OPTIND-1))"
+
+python3 generate.py
+exec ${MAKE:-make} -f run-test.mk SEED="$seed"
diff --git a/tests/opt/memory_bmux2rom.ys b/tests/opt/memory_bmux2rom.ys
new file mode 100644 (file)
index 0000000..0398859
--- /dev/null
@@ -0,0 +1,27 @@
+read_ilang << EOT
+
+module \top
+  wire width 4 input 0 \S
+  wire width 5 output 1 \Y
+
+  cell $bmux $0
+    parameter \WIDTH 5
+    parameter \S_WIDTH 4
+    connect \A 80'10110100011101110001110010001110101010111000110011111111111110100000110100111000
+    connect \S \S
+    connect \Y \Y
+  end
+end
+
+EOT
+
+hierarchy -auto-top
+
+design -save preopt
+memory_bmux2rom
+select -assert-count 1 t:$memrd_v2
+memory_map
+opt_dff
+design -stash postopt
+
+equiv_opt -assert -run prepare: dummy
diff --git a/tests/proc/proc_rom.ys b/tests/proc/proc_rom.ys
new file mode 100644 (file)
index 0000000..0ef2e2c
--- /dev/null
@@ -0,0 +1,189 @@
+read_verilog << EOT
+
+module top(input [3:0] a, input en, output [7:0] d);
+
+always @*
+       if (en)
+               case(a)
+                       4'h0: d <= 8'h12;
+                       4'h1: d <= 8'h34;
+                       4'h2: d <= 8'h56;
+                       4'h3: d <= 8'h78;
+                       4'h4: d <= 8'h9a;
+                       4'h5: d <= 8'hbc;
+                       4'h6: d <= 8'hde;
+                       4'h7: d <= 8'hff;
+                       4'h8: d <= 8'h61;
+                       4'h9: d <= 8'h49;
+                       4'ha: d <= 8'h36;
+                       4'hb: d <= 8'h81;
+                       4'hc: d <= 8'h8c;
+                       4'hd: d <= 8'ha9;
+                       4'he: d <= 8'h99;
+                       4'hf: d <= 8'h51;
+               endcase
+       else
+               d <= 0;
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+
+design -save orig
+proc
+select -assert-count 1 t:$memrd_v2
+memory
+opt_dff
+design -stash postopt
+design -load orig
+proc -norom
+design -stash preopt
+
+equiv_opt -assert -run prepare: dummy
+
+
+
+design -reset
+
+read_verilog << EOT
+
+module top(input [3:0] a, input en, output [7:0] d);
+
+always @*
+       if (en)
+               case(a)
+                       4'h0: d <= 8'h12;
+                       4'h1: d <= 8'h34;
+                       4'h2: d <= 8'h56;
+                       4'h3: d <= 8'h78;
+                       4'h4: d <= 8'h9a;
+                       4'h5: d <= 8'hbc;
+                       4'h6: d <= 8'hde;
+                       4'h7: d <= 8'hff;
+                       4'h8: d <= 8'h61;
+                       4'h9: d <= 8'h49;
+                       4'ha: d <= 8'h36;
+                       4'hb: d <= 8'h81;
+                       4'hc: d <= 8'h8c;
+                       default: d <= 8'h11;
+               endcase
+       else
+               d <= 0;
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+
+design -save orig
+proc
+select -assert-count 1 t:$memrd_v2
+memory
+opt_dff
+design -stash postopt
+design -load orig
+proc -norom
+design -stash preopt
+
+equiv_opt -assert -run prepare: dummy
+
+
+
+design -reset
+
+read_verilog << EOT
+
+module top(input [31:0] a, input en, output [7:0] d);
+
+always @*
+       if (en)
+               case(a)
+                       0: d <= 8'h12;
+                       1: d <= 8'h34;
+                       2: d <= 8'h56;
+                       3: d <= 8'h78;
+                       4: d <= 8'h9a;
+                       5: d <= 8'hbc;
+                       6: d <= 8'hde;
+                       7: d <= 8'hff;
+                       8: d <= 8'h61;
+                       9: d <= 8'h49;
+                       10: d <= 8'h36;
+                       11: d <= 8'h81;
+                       12: d <= 8'h8c;
+                       default: d <= 8'h11;
+               endcase
+       else
+               d <= 0;
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+
+design -save orig
+proc
+select -assert-count 1 t:$memrd_v2
+memory
+opt_dff
+design -stash postopt
+design -load orig
+proc -norom
+design -stash preopt
+
+equiv_opt -assert -run prepare: dummy
+
+
+design -reset
+
+read_verilog << EOT
+
+module top(input [3:0] a, input en, output [7:0] d);
+
+always @*
+       if (en)
+               case(a)
+                       'h0: d <= 8'h12;
+                       'h1: d <= 8'h34;
+                       'h2: d <= 8'h56;
+                       'h3: d <= 8'h78;
+                       'h4: d <= 8'h9a;
+                       'h5: d <= 8'hbc;
+                       'h6: d <= 8'hde;
+                       'h7: d <= 8'hff;
+                       'h8: d <= 8'h61;
+                       'h9: d <= 8'h49;
+                       'ha: d <= 8'h36;
+                       'hb: d <= 8'h81;
+                       'hc: d <= 8'h8c;
+                       'hd: d <= 8'ha9;
+                       'he: d <= 8'h99;
+                       'hf: d <= 8'h51;
+               endcase
+       else
+               d <= 0;
+
+endmodule
+
+EOT
+
+hierarchy -auto-top
+
+design -save orig
+proc
+select -assert-count 1 t:$memrd_v2
+memory
+opt_dff
+design -stash postopt
+design -load orig
+proc -norom
+design -stash preopt
+
+equiv_opt -assert -run prepare: dummy
+
+
+
index cc254049ab4c2973ccb592a49c4f453a76270c88..b1965c97d3a70e06df64f2ead01673b4f273f862 100644 (file)
@@ -3,5 +3,6 @@
 /*_pass
 /*_fail
 /*.ok
+/*.fst
 /vhdlpsl[0-9][0-9]
 /vhdlpsl[0-9][0-9].sby
index 1b217f746e55c2eb9cabd209e35cb232f7a4120b..dcabcf42ba463eb33cadabb11e83b0d3b349b2c6 100644 (file)
@@ -10,4 +10,5 @@ clean:
        rm -rf $(addsuffix .ok,$(TESTS)) $(addsuffix .sby,$(TESTS)) $(TESTS)
        rm -rf $(addsuffix _pass.sby,$(TESTS)) $(addsuffix _pass,$(TESTS))
        rm -rf $(addsuffix _fail.sby,$(TESTS)) $(addsuffix _fail,$(TESTS))
+       rm -rf $(addsuffix .fst,$(TESTS))
 
diff --git a/tests/sva/nested_clk_else.sv b/tests/sva/nested_clk_else.sv
new file mode 100644 (file)
index 0000000..4421cb3
--- /dev/null
@@ -0,0 +1,11 @@
+module top (input clk, a, b);
+       always @(posedge clk) begin
+        if (a);
+        else assume property (@(posedge clk) b);
+       end
+
+`ifndef FAIL
+    assume property (@(posedge clk) !a);
+`endif
+    assert property (@(posedge clk) b);
+endmodule
index 8ed7f8cbc79999af59dbcbbce50ea8f11cab8775..2ecc9780c5de124d9f9f542f7d02c4f63bbaf474 100644 (file)
@@ -57,7 +57,9 @@ generate_sby() {
        fi
 }
 
-if [ -f $prefix.sv ]; then
+if [ -f $prefix.ys ]; then
+       $PWD/../../yosys -q -e "Assert .* failed." -s $prefix.ys
+elif [ -f $prefix.sv ]; then
        generate_sby pass > ${prefix}_pass.sby
        generate_sby fail > ${prefix}_fail.sby
        sby --yosys $PWD/../../yosys -f ${prefix}_pass.sby
diff --git a/tests/sva/sva_value_change_changed.sv b/tests/sva/sva_value_change_changed.sv
new file mode 100644 (file)
index 0000000..8f3a05a
--- /dev/null
@@ -0,0 +1,17 @@
+module top (
+       input clk,
+       input a, b
+);
+       default clocking @(posedge clk); endclocking
+
+       assert property (
+               $changed(b)
+       );
+
+`ifndef FAIL
+       assume property (
+               b !== 'x ##1 $changed(b)
+       );
+`endif
+
+endmodule
diff --git a/tests/sva/sva_value_change_changed_wide.sv b/tests/sva/sva_value_change_changed_wide.sv
new file mode 100644 (file)
index 0000000..c9147c4
--- /dev/null
@@ -0,0 +1,22 @@
+module top (
+       input clk,
+       input [2:0] a,
+       input [2:0] b
+);
+       default clocking @(posedge clk); endclocking
+
+       assert property (
+               $changed(a)
+       );
+
+    assert property (
+        $changed(b) == ($changed(b[0]) || $changed(b[1]) || $changed(b[2]))
+    );
+
+`ifndef FAIL
+       assume property (
+               a !== 'x ##1 $changed(a)
+       );
+`endif
+
+endmodule
diff --git a/tests/sva/sva_value_change_rose.sv b/tests/sva/sva_value_change_rose.sv
new file mode 100644 (file)
index 0000000..d1c5290
--- /dev/null
@@ -0,0 +1,20 @@
+module top (
+       input clk,
+       input a, b
+);
+       default clocking @(posedge clk); endclocking
+
+    wire a_copy;
+    assign a_copy = a;
+
+       assert property (
+               $rose(a) |-> b
+       );
+
+`ifndef FAIL
+       assume property (
+               $rose(a_copy) |-> b
+       );
+`endif
+
+endmodule
diff --git a/tests/sva/sva_value_change_sim.sv b/tests/sva/sva_value_change_sim.sv
new file mode 100644 (file)
index 0000000..92fe30b
--- /dev/null
@@ -0,0 +1,70 @@
+module top (
+       input clk
+);
+
+reg [7:0] counter = 0;
+
+reg a = 0;
+reg b = 1;
+reg c;
+reg [2:0] wide_a = 3'b10x;
+reg [2:0] wide_b = 'x;
+
+wire a_fell; assign a_fell = $fell(a, @(posedge clk));
+wire a_rose; assign a_rose = $rose(a, @(posedge clk));
+wire a_stable; assign a_stable = $stable(a, @(posedge clk));
+
+wire b_fell; assign b_fell = $fell(b, @(posedge clk));
+wire b_rose; assign b_rose = $rose(b, @(posedge clk));
+wire b_stable; assign b_stable = $stable(b, @(posedge clk));
+
+wire c_fell; assign c_fell = $fell(c, @(posedge clk));
+wire c_rose; assign c_rose = $rose(c, @(posedge clk));
+wire c_stable; assign c_stable = $stable(c, @(posedge clk));
+
+wire wide_a_stable; assign wide_a_stable = $stable(wide_a, @(posedge clk));
+wire wide_b_stable; assign wide_b_stable = $stable(wide_b, @(posedge clk));
+
+always @(posedge clk) begin
+       counter <= counter + 1;
+
+       case (counter)
+               0: begin
+            assert property ( $fell(a) && !$rose(a) && !$stable(a));
+            assert property (!$fell(b) &&  $rose(b) && !$stable(b));
+            assert property (!$fell(c) && !$rose(c) &&  $stable(c));
+            assert property (!$stable(wide_a));
+            assert property ($stable(wide_b));
+            a <= 1; b <= 1; c <= 1;
+        end
+               1: begin
+            a <= 0; b <= 1; c <= 'x;
+            wide_a <= 3'b101; wide_b <= 3'bxx0;
+        end
+               2: begin
+            assert property ( $fell(a) && !$rose(a) && !$stable(a));
+            assert property (!$fell(b) && !$rose(b) &&  $stable(b));
+            assert property (!$fell(c) && !$rose(c) && !$stable(c));
+            assert property (!$stable(wide_a));
+            assert property (!$stable(wide_b));
+            a <= 0; b <= 0; c <= 0;
+        end
+               3: begin a <= 0; b <= 1; c <= 'x; end
+               4: begin
+            assert property (!$fell(a) && !$rose(a) &&  $stable(a));
+            assert property (!$fell(b) &&  $rose(b) && !$stable(b));
+            assert property (!$fell(c) && !$rose(c) && !$stable(c));
+            assert property ($stable(wide_a));
+            assert property ($stable(wide_b));
+            a <= 'x; b <= 'x; c <= 'x;
+            wide_a <= 'x; wide_b <= 'x;
+        end
+               5: begin
+            a <= 0; b <= 1; c <= 'x;
+            wide_a <= 3'b10x; wide_b <= 'x;
+            counter <= 0;
+        end
+       endcase;
+end
+
+endmodule
diff --git a/tests/sva/sva_value_change_sim.ys b/tests/sva/sva_value_change_sim.ys
new file mode 100644 (file)
index 0000000..e004520
--- /dev/null
@@ -0,0 +1,3 @@
+read -sv sva_value_change_sim.sv
+hierarchy -top top
+sim -clock clk -fst sva_value_change_sim.fst