diff --git a/.github/workflows/test-linux.yml b/.github/workflows/test-linux.yml index eee556794af..a16481726d3 100644 --- a/.github/workflows/test-linux.yml +++ b/.github/workflows/test-linux.yml @@ -43,6 +43,7 @@ jobs: sudo apt-get install $CC $CXX echo "CC=$CC" >> $GITHUB_ENV echo "CXX=$CXX" >> $GITHUB_ENV + echo "CXXFLAGS=-Wp,-D_GLIBCXX_ASSERTIONS" >> $GITHUB_ENV env: CC: ${{ matrix.compiler }} diff --git a/CHANGELOG b/CHANGELOG index 0b211771f0f..465918a36d8 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -2,9 +2,32 @@ List of major changes and improvements between releases ======================================================= -Yosys 0.31 .. Yosys 0.32-dev +Yosys 0.33 .. Yosys 0.34-dev -------------------------- +Yosys 0.32 .. Yosys 0.33 +-------------------------- + * Various + - Added "$print" cell, produced by "$display" and "$write" + Verilog tasks. + - Added "$print" cell handling in CXXRTL. + + * Lattice FPGA support + - Added generic "synth_lattice" pass (for now MachXO2/XO3/XO3D) + - Removed "synth_machxo2" pass + - Pass "ecp5_gsr" renamed to "lattice_gsr" + - "synth_machxo2" equivalent is "synth_lattice -family xo2" + +Yosys 0.31 .. Yosys 0.32 +-------------------------- + * Verific support + - Added sub option "-lib" to reading commands for VHDL and + SystemVerilog, that will later import all units/modules from + marked files as blackboxes. + + * Various + - Added support for $lt, $le, $gt, $ge to the code generating AIGs. + Yosys 0.30 .. Yosys 0.31 -------------------------- * New commands and options diff --git a/Makefile b/Makefile index 44a420a3dc3..a93930be0c9 100644 --- a/Makefile +++ b/Makefile @@ -141,7 +141,7 @@ LDLIBS += -lrt endif endif -YOSYS_VER := 0.31+45 +YOSYS_VER := 0.33+34 # Note: We arrange for .gitcommit to contain the (short) commit hash in # tarballs generated with git-archive(1) using .gitattributes. The git repo @@ -157,7 +157,7 @@ endif OBJS = kernel/version_$(GIT_REV).o bumpversion: - sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline f3c6b41.. | wc -l`/;" Makefile + sed -i "/^YOSYS_VER := / s/+[0-9][0-9]*$$/+`git log --oneline 2584903.. | wc -l`/;" Makefile # set 'ABCREV = default' to use abc/ as it is # @@ -165,7 +165,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = bb64142 +ABCREV = daad9ed ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 ABC_USE_NAMESPACE=abc VERBOSE=$(Q) @@ -606,31 +606,35 @@ Q = S = endif -$(eval $(call add_include_file,kernel/yosys.h)) -$(eval $(call add_include_file,kernel/hashlib.h)) -$(eval $(call add_include_file,kernel/log.h)) -$(eval $(call add_include_file,kernel/rtlil.h)) $(eval $(call add_include_file,kernel/binding.h)) -$(eval $(call add_include_file,kernel/register.h)) $(eval $(call add_include_file,kernel/cellaigs.h)) -$(eval $(call add_include_file,kernel/celltypes.h)) $(eval $(call add_include_file,kernel/celledges.h)) +$(eval $(call add_include_file,kernel/celltypes.h)) $(eval $(call add_include_file,kernel/consteval.h)) $(eval $(call add_include_file,kernel/constids.inc)) -$(eval $(call add_include_file,kernel/sigtools.h)) -$(eval $(call add_include_file,kernel/modtools.h)) -$(eval $(call add_include_file,kernel/macc.h)) -$(eval $(call add_include_file,kernel/utils.h)) -$(eval $(call add_include_file,kernel/satgen.h)) -$(eval $(call add_include_file,kernel/qcsat.h)) +$(eval $(call add_include_file,kernel/cost.h)) $(eval $(call add_include_file,kernel/ff.h)) $(eval $(call add_include_file,kernel/ffinit.h)) +$(eval $(call add_include_file,kernel/ffmerge.h)) +$(eval $(call add_include_file,kernel/fmt.h)) ifeq ($(ENABLE_ZLIB),1) $(eval $(call add_include_file,kernel/fstdata.h)) endif +$(eval $(call add_include_file,kernel/hashlib.h)) +$(eval $(call add_include_file,kernel/json.h)) +$(eval $(call add_include_file,kernel/log.h)) +$(eval $(call add_include_file,kernel/macc.h)) +$(eval $(call add_include_file,kernel/modtools.h)) $(eval $(call add_include_file,kernel/mem.h)) +$(eval $(call add_include_file,kernel/qcsat.h)) +$(eval $(call add_include_file,kernel/register.h)) +$(eval $(call add_include_file,kernel/rtlil.h)) +$(eval $(call add_include_file,kernel/satgen.h)) +$(eval $(call add_include_file,kernel/sigtools.h)) +$(eval $(call add_include_file,kernel/timinginfo.h)) +$(eval $(call add_include_file,kernel/utils.h)) +$(eval $(call add_include_file,kernel/yosys.h)) $(eval $(call add_include_file,kernel/yw.h)) -$(eval $(call add_include_file,kernel/json.h)) $(eval $(call add_include_file,libs/ezsat/ezsat.h)) $(eval $(call add_include_file,libs/ezsat/ezminisat.h)) ifeq ($(ENABLE_ZLIB),1) @@ -652,12 +656,7 @@ $(eval $(call add_include_file,backends/cxxrtl/cxxrtl_vcd_capi.h)) OBJS += kernel/driver.o kernel/register.o kernel/rtlil.o kernel/log.o kernel/calc.o kernel/yosys.o OBJS += kernel/binding.o -ifeq ($(ENABLE_ABC),1) -ifneq ($(ABCEXTERNAL),) -kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' -endif -endif -OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o +OBJS += kernel/cellaigs.o kernel/celledges.o kernel/satgen.o kernel/qcsat.o kernel/mem.o kernel/ffmerge.o kernel/ff.o kernel/yw.o kernel/json.o kernel/fmt.o ifeq ($(ENABLE_ZLIB),1) OBJS += kernel/fstdata.o endif @@ -669,6 +668,11 @@ endif kernel/log.o: CXXFLAGS += -DYOSYS_SRC='"$(YOSYS_SRC)"' kernel/yosys.o: CXXFLAGS += -DYOSYS_DATDIR='"$(DATDIR)"' -DYOSYS_PROGRAM_PREFIX='"$(PROGRAM_PREFIX)"' +ifeq ($(ENABLE_ABC),1) +ifneq ($(ABCEXTERNAL),) +kernel/yosys.o: CXXFLAGS += -DABCEXTERNAL='"$(ABCEXTERNAL)"' +endif +endif OBJS += libs/bigint/BigIntegerAlgorithms.o libs/bigint/BigInteger.o libs/bigint/BigIntegerUtils.o OBJS += libs/bigint/BigUnsigned.o libs/bigint/BigUnsignedInABase.o @@ -882,6 +886,7 @@ endif +cd tests/memfile && bash run-test.sh +cd tests/verilog && bash run-test.sh +cd tests/xprop && bash run-test.sh $(SEEDOPT) + +cd tests/fmt && bash run-test.sh @echo "" @echo " Passed \"make test\"." @echo "" diff --git a/backends/cxxrtl/cxxrtl.h b/backends/cxxrtl/cxxrtl.h index 5d0596f0d61..8f5e4035a34 100644 --- a/backends/cxxrtl/cxxrtl.h +++ b/backends/cxxrtl/cxxrtl.h @@ -518,6 +518,14 @@ struct value : public expr_base> { return count; } + size_t chunks_used() const { + for (size_t n = chunks; n > 0; n--) { + if (data[n - 1] != 0) + return n; + } + return 0; + } + template std::pair, bool /*CarryOut*/> alu(const value &other) const { value result; @@ -575,6 +583,84 @@ struct value : public expr_base> { result.data[result.chunks - 1] &= result.msb_mask; return result; } + + // parallel to BigUnsigned::divideWithRemainder; quotient is stored in q, + // *this is left with the remainder. See that function for commentary describing + // how/why this works. + void divideWithRemainder(const value &b, value &q) { + assert(this != &q); + + if (this == &b || &q == &b) { + value tmpB(b); + divideWithRemainder(tmpB, q); + return; + } + + q = value {0u}; + + size_t blen = b.chunks_used(); + if (blen == 0) { + return; + } + + size_t len = chunks_used(); + if (len < blen) { + return; + } + + size_t i, j, k; + size_t i2; + chunk_t temp; + bool borrowIn, borrowOut; + + size_t origLen = len; + len++; + chunk::type blk[len]; + std::copy(data, data + origLen, blk); + blk[origLen] = 0; + chunk::type subtractBuf[len]; + std::fill(subtractBuf, subtractBuf + len, 0); + + size_t qlen = origLen - blen + 1; + + i = qlen; + while (i > 0) { + i--; + i2 = chunk::bits; + while (i2 > 0) { + i2--; + for (j = 0, k = i, borrowIn = false; j <= blen; j++, k++) { + temp = blk[k] - getShiftedBlock(b, j, i2); + borrowOut = (temp > blk[k]); + if (borrowIn) { + borrowOut |= (temp == 0); + temp--; + } + subtractBuf[k] = temp; + borrowIn = borrowOut; + } + for (; k < origLen && borrowIn; k++) { + borrowIn = (blk[k] == 0); + subtractBuf[k] = blk[k] - 1; + } + if (!borrowIn) { + q.data[i] |= (chunk::type(1) << i2); + while (k > i) { + k--; + blk[k] = subtractBuf[k]; + } + } + } + } + + std::copy(blk, blk + origLen, data); + } + + static chunk::type getShiftedBlock(const value &num, size_t x, size_t y) { + chunk::type part1 = (x == 0 || y == 0) ? 0 : (num.data[x - 1] >> (chunk::bits - y)); + chunk::type part2 = (x == num.chunks) ? 0 : (num.data[x] << y); + return part1 | part2; + } }; // Expression template for a slice, usable as lvalue or rvalue, and composable with other expression templates here. @@ -707,6 +793,99 @@ std::ostream &operator<<(std::ostream &os, const value &val) { return os; } +template +struct value_formatted { + const value &val; + bool character; + bool justify_left; + char padding; + int width; + int base; + bool signed_; + bool plus; + + value_formatted(const value &val, bool character, bool justify_left, char padding, int width, int base, bool signed_, bool plus) : + val(val), character(character), justify_left(justify_left), padding(padding), width(width), base(base), signed_(signed_), plus(plus) {} + value_formatted(const value_formatted &) = delete; + value_formatted &operator=(const value_formatted &rhs) = delete; +}; + +template +std::ostream &operator<<(std::ostream &os, const value_formatted &vf) +{ + value val = vf.val; + + std::string buf; + + // We might want to replace some of these bit() calls with direct + // chunk access if it turns out to be slow enough to matter. + + if (!vf.character) { + size_t width = Bits; + if (vf.base != 10) { + width = 0; + for (size_t index = 0; index < Bits; index++) + if (val.bit(index)) + width = index + 1; + } + + if (vf.base == 2) { + for (size_t i = width; i > 0; i--) + buf += (val.bit(i - 1) ? '1' : '0'); + } else if (vf.base == 8 || vf.base == 16) { + size_t step = (vf.base == 16) ? 4 : 3; + for (size_t index = 0; index < width; index += step) { + uint8_t value = val.bit(index) | (val.bit(index + 1) << 1) | (val.bit(index + 2) << 2); + if (step == 4) + value |= val.bit(index + 3) << 3; + buf += "0123456789abcdef"[value]; + } + std::reverse(buf.begin(), buf.end()); + } else if (vf.base == 10) { + bool negative = vf.signed_ && val.is_neg(); + if (negative) + val = val.neg(); + if (val.is_zero()) + buf += '0'; + while (!val.is_zero()) { + value quotient; + val.divideWithRemainder(value{10u}, quotient); + buf += '0' + val.template trunc<(Bits > 4 ? 4 : Bits)>().val().template get(); + val = quotient; + } + if (negative || vf.plus) + buf += negative ? '-' : '+'; + std::reverse(buf.begin(), buf.end()); + } else assert(false); + } else { + buf.reserve(Bits/8); + for (int i = 0; i < Bits; i += 8) { + char ch = 0; + for (int j = 0; j < 8 && i + j < int(Bits); j++) + if (val.bit(i + j)) + ch |= 1 << j; + if (ch != 0) + buf.append({ch}); + } + std::reverse(buf.begin(), buf.end()); + } + + assert(vf.width == 0 || vf.padding != '\0'); + if (!vf.justify_left && buf.size() < vf.width) { + size_t pad_width = vf.width - buf.size(); + if (vf.padding == '0' && (buf.front() == '+' || buf.front() == '-')) { + os << buf.front(); + buf.erase(0, 1); + } + os << std::string(pad_width, vf.padding); + } + os << buf; + if (vf.justify_left && buf.size() < vf.width) + os << std::string(vf.width - buf.size(), vf.padding); + + return os; +} + template struct wire { static constexpr size_t bits = Bits; @@ -1091,7 +1270,10 @@ struct module { virtual bool eval() = 0; virtual bool commit() = 0; + unsigned int steps = 0; + size_t step() { + ++steps; size_t deltas = 0; bool converged = false; do { diff --git a/backends/cxxrtl/cxxrtl_backend.cc b/backends/cxxrtl/cxxrtl_backend.cc index 1b13985ab4e..7696ae5747c 100644 --- a/backends/cxxrtl/cxxrtl_backend.cc +++ b/backends/cxxrtl/cxxrtl_backend.cc @@ -24,6 +24,7 @@ #include "kernel/celltypes.h" #include "kernel/mem.h" #include "kernel/log.h" +#include "kernel/fmt.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN @@ -217,7 +218,7 @@ bool is_internal_cell(RTLIL::IdString type) bool is_effectful_cell(RTLIL::IdString type) { - return type.isPublic(); + return type.isPublic() || type == ID($print); } bool is_cxxrtl_blackbox_cell(const RTLIL::Cell *cell) @@ -281,6 +282,7 @@ struct FlowGraph { CONNECT, CELL_SYNC, CELL_EVAL, + PRINT_SYNC, PROCESS_SYNC, PROCESS_CASE, MEM_RDPORT, @@ -290,6 +292,7 @@ struct FlowGraph { Type type; RTLIL::SigSig connect = {}; const RTLIL::Cell *cell = nullptr; + std::vector print_sync_cells; const RTLIL::Process *process = nullptr; const Mem *mem = nullptr; int portidx; @@ -477,6 +480,15 @@ struct FlowGraph { return node; } + Node *add_print_sync_node(std::vector cells) + { + Node *node = new Node; + node->type = Node::Type::PRINT_SYNC; + node->print_sync_cells = cells; + nodes.push_back(node); + return node; + } + // Processes void add_case_rule_defs_uses(Node *node, const RTLIL::CaseRule *case_) { @@ -681,6 +693,7 @@ struct CxxrtlWorker { bool split_intf = false; std::string intf_filename; std::string design_ns = "cxxrtl_design"; + std::string print_output = "std::cout"; std::ostream *impl_f = nullptr; std::ostream *intf_f = nullptr; @@ -1036,6 +1049,63 @@ struct CxxrtlWorker { f << ".val()"; } + void dump_print(const RTLIL::Cell *cell) + { + Fmt fmt = {}; + fmt.parse_rtlil(cell); + + f << indent << "if ("; + dump_sigspec_rhs(cell->getPort(ID::EN)); + f << " == value<1>{1u}) {\n"; + inc_indent(); + f << indent << print_output; + fmt.emit_cxxrtl(f, [this](const RTLIL::SigSpec &sig) { dump_sigspec_rhs(sig); }); + f << ";\n"; + dec_indent(); + f << indent << "}\n"; + } + + void dump_sync_print(std::vector &cells) + { + log_assert(!cells.empty()); + const auto &trg = cells[0]->getPort(ID::TRG); + const auto &trg_polarity = cells[0]->getParam(ID::TRG_POLARITY); + + f << indent << "if ("; + for (int i = 0; i < trg.size(); i++) { + RTLIL::SigBit trg_bit = trg[i]; + trg_bit = sigmaps[trg_bit.wire->module](trg_bit); + log_assert(trg_bit.wire); + + if (i != 0) + f << " || "; + + if (trg_polarity[i] == State::S1) + f << "posedge_"; + else + f << "negedge_"; + f << mangle(trg_bit); + } + f << ") {\n"; + inc_indent(); + std::sort(cells.begin(), cells.end(), [](const RTLIL::Cell *a, const RTLIL::Cell *b) { + return a->getParam(ID::PRIORITY).as_int() > b->getParam(ID::PRIORITY).as_int(); + }); + for (auto cell : cells) { + log_assert(cell->getParam(ID::TRG_ENABLE).as_bool()); + log_assert(cell->getPort(ID::TRG) == trg); + log_assert(cell->getParam(ID::TRG_POLARITY) == trg_polarity); + + std::vector inlined_cells; + collect_cell_eval(cell, /*for_debug=*/false, inlined_cells); + dump_inlined_cells(inlined_cells); + dump_print(cell); + } + dec_indent(); + + f << indent << "}\n"; + } + void dump_inlined_cells(const std::vector &cells) { if (cells.empty()) { @@ -1202,6 +1272,25 @@ struct CxxrtlWorker { f << " = "; dump_cell_expr(cell, for_debug); f << ";\n"; + // $print cell + } else if (cell->type == ID($print)) { + log_assert(!for_debug); + + // Sync $print cells are grouped into PRINT_SYNC nodes in the FlowGraph. + log_assert(!cell->getParam(ID::TRG_ENABLE).as_bool()); + + f << indent << "auto " << mangle(cell) << "_curr = "; + dump_sigspec_rhs(cell->getPort(ID::EN)); + f << ".concat("; + dump_sigspec_rhs(cell->getPort(ID::ARGS)); + f << ").val();\n"; + + f << indent << "if (" << mangle(cell) << " != " << mangle(cell) << "_curr) {\n"; + inc_indent(); + dump_print(cell); + f << indent << mangle(cell) << " = " << mangle(cell) << "_curr;\n"; + dec_indent(); + f << indent << "}\n"; // Flip-flops } else if (is_ff_cell(cell->type)) { log_assert(!for_debug); @@ -1946,6 +2035,9 @@ struct CxxrtlWorker { case FlowGraph::Node::Type::CELL_EVAL: dump_cell_eval(node.cell); break; + case FlowGraph::Node::Type::PRINT_SYNC: + dump_sync_print(node.print_sync_cells); + break; case FlowGraph::Node::Type::PROCESS_CASE: dump_process_case(node.process); break; @@ -2291,6 +2383,11 @@ struct CxxrtlWorker { f << "\n"; bool has_cells = false; for (auto cell : module->cells()) { + if (cell->type == ID($print) && !cell->getParam(ID::TRG_ENABLE).as_bool()) { + // comb $print cell -- store the last EN/ARGS values to know when they change. + dump_attrs(cell); + f << indent << "value<" << (1 + cell->getParam(ID::ARGS_WIDTH).as_int()) << "> " << mangle(cell) << ";\n"; + } if (is_internal_cell(cell->type)) continue; dump_attrs(cell); @@ -2377,6 +2474,7 @@ struct CxxrtlWorker { RTLIL::Module *top_module = nullptr; std::vector modules; TopoSort topo_design; + bool has_prints = false; for (auto module : design->modules()) { if (!design->selected_module(module)) continue; @@ -2389,6 +2487,8 @@ struct CxxrtlWorker { topo_design.node(module); for (auto cell : module->cells()) { + if (cell->type == ID($print)) + has_prints = true; if (is_internal_cell(cell->type) || is_cxxrtl_blackbox_cell(cell)) continue; RTLIL::Module *cell_module = design->module(cell->type); @@ -2447,6 +2547,8 @@ struct CxxrtlWorker { f << "#include \"" << intf_filename << "\"\n"; else f << "#include \n"; + if (has_prints) + f << "#include \n"; f << "\n"; f << "#if defined(CXXRTL_INCLUDE_CAPI_IMPL) || \\\n"; f << " defined(CXXRTL_INCLUDE_VCD_CAPI_IMPL)\n"; @@ -2601,6 +2703,16 @@ struct CxxrtlWorker { register_edge_signal(sigmap, cell->getPort(ID::CLK), cell->parameters[ID::CLK_POLARITY].as_bool() ? RTLIL::STp : RTLIL::STn); } + + // $print cells may be triggered on posedge/negedge events. + if (cell->type == ID($print) && cell->getParam(ID::TRG_ENABLE).as_bool()) { + for (size_t i = 0; i < (size_t)cell->getParam(ID::TRG_WIDTH).as_int(); i++) { + RTLIL::SigBit trg = cell->getPort(ID::TRG).extract(i, 1); + if (is_valid_clock(trg)) + register_edge_signal(sigmap, trg, + cell->parameters[ID::TRG_POLARITY][i] == RTLIL::S1 ? RTLIL::STp : RTLIL::STn); + } + } } for (auto &mem : memories) { @@ -2736,6 +2848,8 @@ struct CxxrtlWorker { for (auto node : flow.nodes) { if (node->type == FlowGraph::Node::Type::CELL_EVAL && is_effectful_cell(node->cell->type)) worklist.insert(node); // node has effects + else if (node->type == FlowGraph::Node::Type::PRINT_SYNC) + worklist.insert(node); // node is sync $print else if (node->type == FlowGraph::Node::Type::MEM_WRPORTS) worklist.insert(node); // node is memory write else if (node->type == FlowGraph::Node::Type::PROCESS_SYNC && is_memwr_process(node->process)) @@ -2792,9 +2906,22 @@ struct CxxrtlWorker { } // Emit reachable nodes in eval(). + // Accumulate sync $print cells per trigger condition. + dict, std::vector> sync_print_cells; for (auto node : node_order) - if (live_nodes[node]) - schedule[module].push_back(*node); + if (live_nodes[node]) { + if (node->type == FlowGraph::Node::Type::CELL_EVAL && + node->cell->type == ID($print) && + node->cell->getParam(ID::TRG_ENABLE).as_bool()) + sync_print_cells[make_pair(node->cell->getPort(ID::TRG), node->cell->getParam(ID::TRG_POLARITY))].push_back(node->cell); + else + schedule[module].push_back(*node); + } + + for (auto &it : sync_print_cells) { + auto node = flow.add_print_sync_node(it.second); + schedule[module].push_back(*node); + } // For maximum performance, the state of the simulation (which is the same as the set of its double buffered // wires, since using a singly buffered wire for any kind of state introduces a race condition) should contain @@ -3213,6 +3340,11 @@ struct CxxrtlBackend : public Backend { log(" place the generated code into namespace . if not specified,\n"); log(" \"cxxrtl_design\" is used.\n"); log("\n"); + log(" -print-output \n"); + log(" $print cells in the generated code direct their output to .\n"); + log(" must be one of \"std::cout\", \"std::cerr\". if not specified,\n"); + log(" \"std::cout\" is used.\n"); + log("\n"); log(" -nohierarchy\n"); log(" use design hierarchy as-is. in most designs, a top module should be\n"); log(" present as it is exposed through the C API and has unbuffered outputs\n"); @@ -3351,6 +3483,14 @@ struct CxxrtlBackend : public Backend { worker.design_ns = args[++argidx]; continue; } + if (args[argidx] == "-print-output" && argidx+1 < args.size()) { + worker.print_output = args[++argidx]; + if (!(worker.print_output == "std::cout" || worker.print_output == "std::cerr")) { + log_cmd_error("Invalid output stream \"%s\".\n", worker.print_output.c_str()); + worker.print_output = "std::cout"; + } + continue; + } break; } extra_args(f, filename, args, argidx); diff --git a/backends/smt2/smtio.py b/backends/smt2/smtio.py index 8094747bc14..0ec7f08f4dc 100644 --- a/backends/smt2/smtio.py +++ b/backends/smt2/smtio.py @@ -245,6 +245,7 @@ def setup(self): self.logic_uf = False self.unroll_idcnt = 0 self.unroll_buffer = "" + self.unroll_level = 0 self.unroll_sorts = set() self.unroll_objs = set() self.unroll_decls = dict() @@ -420,13 +421,15 @@ def write(self, stmt, unroll=True): self.p_close() if unroll and self.unroll: - stmt = self.unroll_buffer + stmt - self.unroll_buffer = "" - s = re.sub(r"\|[^|]*\|", "", stmt) - if s.count("(") != s.count(")"): - self.unroll_buffer = stmt + " " + self.unroll_level += s.count("(") - s.count(")") + if self.unroll_level > 0: + self.unroll_buffer += stmt + self.unroll_buffer += " " return + else: + stmt = self.unroll_buffer + stmt + self.unroll_buffer = "" s = self.parse(stmt) diff --git a/backends/smt2/witness.py b/backends/smt2/witness.py index 7d5a2469eb5..0977f4532d5 100644 --- a/backends/smt2/witness.py +++ b/backends/smt2/witness.py @@ -84,26 +84,65 @@ def stats(input): Transform a Yosys witness trace. Currently no transformations are implemented, so it is only useful for testing. +If two or more inputs are provided they will be concatenated together into the output. """) -@click.argument("input", type=click.File("r")) +@click.argument("inputs", type=click.File("r"), nargs=-1) @click.argument("output", type=click.File("w")) -def yw2yw(input, output): - click.echo(f"Copying yosys witness trace from {input.name!r} to {output.name!r}...") - inyw = ReadWitness(input) +@click.option("--append", "-p", type=int, multiple=True, + help="Number of steps (+ve or -ve) to append to end of input trace. " + +"Can be defined multiple times, following the same order as input traces. ") +def yw2yw(inputs, output, append): outyw = WriteWitness(output, "yosys-witness yw2yw") + join_inputs = len(inputs) > 1 + inyws = {} + + if not append: + # default to 0 + append = [0] * len(inputs) + if len(append) != len(inputs): + print(f"Mismatch in number of --append values ({len(append)}) and input traces ({len(inputs)}).") + sys.exit(1) + + for (input, p) in zip(inputs, append): + if (join_inputs): + click.echo(f"Loading signals from yosys witness trace {input.name!r}...") + inyw = ReadWitness(input) + if p: + click.echo(f" appending {p} steps") + if (p + len(inyw) <= 0): + click.echo(f" skipping {input.name!r} (only {len(inyw)} steps to skip)") + continue + inyw.append_steps(p) + inyws[input] = inyw + for clock in inyw.clocks: + if clock not in outyw.clocks: + outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) - for clock in inyw.clocks: - outyw.add_clock(clock["path"], clock["offset"], clock["edge"]) + for sig in inyw.signals: + if sig not in outyw.signals: + outyw.add_sig(sig.path, sig.offset, sig.width, sig.init_only) - for sig in inyw.signals: - outyw.add_sig(sig.path, sig.offset, sig.width, sig.init_only) + init_values = sum([inyw.init_step() for inyw in inyws.values()], start=WitnessValues()) - for t, values in inyw.steps(): - outyw.step(values) + first_witness = True + for (input, inyw) in inyws.items(): + click.echo(f"Copying yosys witness trace from {input.name!r} to {output.name!r}...") + + if first_witness: + outyw.step(init_values) + else: + outyw.step(inyw.first_step()) + + for t, values in inyw.steps(1): + outyw.step(values) + + click.echo(f" copied {t + 1} time steps.") + first_witness = False outyw.end_trace() - click.echo(f"Copied {outyw.t + 1} time steps.") + if join_inputs: + click.echo(f"Copied {outyw.t} total time steps.") class AigerMap: diff --git a/backends/smt2/ywio.py b/backends/smt2/ywio.py index 39cfac41e25..4e95f8c33d2 100644 --- a/backends/smt2/ywio.py +++ b/backends/smt2/ywio.py @@ -165,8 +165,8 @@ def pretty(self): else: return f"{pretty_path(self.path)}[{self.offset}]" - def __eq__(self): - return self.sort_key + def __eq__(self, other): + return self.sort_key == other.sort_key def __hash__(self): return hash(self.sort_key) @@ -294,6 +294,16 @@ def present_signals(self, sigmap): return sorted(signals), missing_signals + def __add__(self, other: "WitnessValues"): + new = WitnessValues() + new += self + new += other + return new + + def __iadd__(self, other: "WitnessValues"): + for key, value in other.values.items(): + self.values.setdefault(key, value) + return self class WriteWitness: def __init__(self, f, generator): @@ -380,14 +390,37 @@ def __init__(self, f): self.bits = [step["bits"] for step in data["steps"]] + def init_step(self): + return self.step(0) + + def non_init_bits(self): + if len(self) > 1: + return len(self.bits[1]) + else: + return sum([sig.width for sig in self.signals if not sig.init_only]) + + def first_step(self): + values = WitnessValues() + # may have issues when non_init_bits is 0 + values.unpack(WitnessSigMap([sig for sig in self.signals if not sig.init_only]), self.bits[0][-self.non_init_bits():]) + return values + def step(self, t): values = WitnessValues() values.unpack(self.sigmap, self.bits[t]) return values - def steps(self): - for i in range(len(self.bits)): + def steps(self, start=0): + for i in range(start, len(self.bits)): yield i, self.step(i) + def append_steps(self, t): + if not t: + pass + elif t < 0: + self.bits = self.bits[:t] + else: + self.bits.extend(["0"*self.non_init_bits()]*t) + def __len__(self): return len(self.bits) diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index 5ff191a9c16..7099c18c349 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -27,6 +27,7 @@ #include "kernel/sigtools.h" #include "kernel/ff.h" #include "kernel/mem.h" +#include "kernel/fmt.h" #include #include #include @@ -1005,6 +1006,41 @@ void dump_cell_expr_binop(std::ostream &f, std::string indent, RTLIL::Cell *cell f << stringf(";\n"); } +void dump_cell_expr_print(std::ostream &f, std::string indent, const RTLIL::Cell *cell) +{ + Fmt fmt = {}; + fmt.parse_rtlil(cell); + std::vector args = fmt.emit_verilog(); + + f << stringf("%s" "$write(", indent.c_str()); + bool first = true; + for (auto &arg : args) { + if (first) { + first = false; + } else { + f << ", "; + } + switch (arg.type) { + case VerilogFmtArg::STRING: + dump_const(f, RTLIL::Const(arg.str)); + break; + case VerilogFmtArg::INTEGER: + f << (arg.signed_ ? "$signed(" : "$unsigned("); + dump_sigspec(f, arg.sig); + f << ")"; + break; + case VerilogFmtArg::TIME: + if (arg.realtime) + f << "$realtime"; + else + f << "$time"; + break; + default: log_abort(); + } + } + f << stringf(");\n"); +} + bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) { if (cell->type == ID($_NOT_)) { @@ -1753,6 +1789,22 @@ bool dump_cell_expr(std::ostream &f, std::string indent, RTLIL::Cell *cell) return true; } + if (cell->type == ID($print)) + { + // Sync $print cells are accumulated and handled in dump_module. + if (cell->getParam(ID::TRG_ENABLE).as_bool()) + return true; + + f << stringf("%s" "always @*\n", indent.c_str()); + + f << stringf("%s" " if (", indent.c_str()); + dump_sigspec(f, cell->getPort(ID::EN)); + f << stringf(")\n"); + + dump_cell_expr_print(f, indent + " ", cell); + return true; + } + // FIXME: $fsm return false; @@ -1841,6 +1893,34 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } } +void dump_sync_print(std::ostream &f, std::string indent, const RTLIL::SigSpec &trg, const RTLIL::Const &polarity, std::vector &cells) +{ + f << stringf("%s" "always @(", indent.c_str()); + for (int i = 0; i < trg.size(); i++) { + if (i != 0) + f << " or "; + if (polarity[i]) + f << "posedge "; + else + f << "negedge "; + dump_sigspec(f, trg[i]); + } + f << ") begin\n"; + + std::sort(cells.begin(), cells.end(), [](const RTLIL::Cell *a, const RTLIL::Cell *b) { + return a->getParam(ID::PRIORITY).as_int() > b->getParam(ID::PRIORITY).as_int(); + }); + for (auto cell : cells) { + f << stringf("%s" " if (", indent.c_str()); + dump_sigspec(f, cell->getPort(ID::EN)); + f << stringf(")\n"); + + dump_cell_expr_print(f, indent + " ", cell); + } + + f << stringf("%s" "end\n", indent.c_str()); +} + void dump_conn(std::ostream &f, std::string indent, const RTLIL::SigSpec &left, const RTLIL::SigSpec &right) { if (simple_lhs) { @@ -2022,6 +2102,8 @@ void dump_process(std::ostream &f, std::string indent, RTLIL::Process *proc, boo void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) { + std::map, std::vector> sync_print_cells; + reg_wires.clear(); reset_auto_counter(module); active_module = module; @@ -2052,6 +2134,11 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) std::set> reg_bits; for (auto cell : module->cells()) { + if (cell->type == ID($print) && cell->getParam(ID::TRG_ENABLE).as_bool()) { + sync_print_cells[make_pair(cell->getPort(ID::TRG), cell->getParam(ID::TRG_POLARITY))].push_back(cell); + continue; + } + if (!RTLIL::builtin_ff_cell_types().count(cell->type) || !cell->hasPort(ID::Q) || cell->type.in(ID($ff), ID($_FF_))) continue; @@ -2107,6 +2194,9 @@ void dump_module(std::ostream &f, std::string indent, RTLIL::Module *module) for (auto cell : module->cells()) dump_cell(f, indent + " ", cell); + for (auto &it : sync_print_cells) + dump_sync_print(f, indent + " ", it.first.first, it.first.second, it.second); + for (auto it = module->processes.begin(); it != module->processes.end(); ++it) dump_process(f, indent + " ", it->second); diff --git a/docs/source/yosys_internals/formats/cell_library.rst b/docs/source/yosys_internals/formats/cell_library.rst index cb2f99bb2ba..11f55dabc64 100644 --- a/docs/source/yosys_internals/formats/cell_library.rst +++ b/docs/source/yosys_internals/formats/cell_library.rst @@ -630,6 +630,133 @@ Add information about ``$assert``, ``$assume``, ``$live``, ``$fair``, Add information about ``$ff`` and ``$_FF_`` cells. +Debugging cells +~~~~~~~~~~~~~~~ + +The ``$print`` cell is used to log the values of signals, akin to (and +translatable to) the ``$display`` and ``$write`` family of tasks in Verilog. It +has the following parameters: + +``\FORMAT`` + The internal format string. The syntax is described below. + +``\ARGS_WIDTH`` + The width (in bits) of the signal on the ``\ARGS`` port. + +``\TRG_ENABLE`` + True if triggered on specific signals defined in ``\TRG``; false if + triggered whenever ``\ARGS`` or ``\EN`` change and ``\EN`` is 1. + +If ``\TRG_ENABLE`` is true, the following parameters also apply: + +``\TRG_WIDTH`` + The number of bits in the ``\TRG`` port. + +``\TRG_POLARITY`` + For each bit in ``\TRG``, 1 if that signal is positive-edge triggered, 0 if + negative-edge triggered. + +``\PRIORITY`` + When multiple ``$print`` cells fire on the same trigger, they execute in + descending priority order. + +Ports: + +``\TRG`` + The signals that control when this ``$print`` cell is triggered. + +``\EN`` + Enable signal for the whole cell. + +``\ARGS`` + The values to be displayed, in format string order. + +Format string syntax +^^^^^^^^^^^^^^^^^^^^ + +The format string syntax resembles Python f-strings. Regular text is passed +through unchanged until a format specifier is reached, starting with a ``{``. + +Format specifiers have the following syntax. Unless noted, all items are +required: + +``{`` + Denotes the start of the format specifier. + +size + Signal size in bits; this many bits are consumed from the ``\ARGS`` port by + this specifier. + +``:`` + Separates the size from the remaining items. + +justify + ``>`` for right-justified, ``<`` for left-justified. + +padding + ``0`` for zero-padding, or a space for space-padding. + +width\ *?* + (optional) The number of characters wide to pad to. + +base + * ``b`` for base-2 integers (binary) + * ``o`` for base-8 integers (octal) + * ``d`` for base-10 integers (decimal) + * ``h`` for base-16 integers (hexadecimal) + * ``c`` for ASCII characters/strings + * ``t`` and ``r`` for simulation time (corresponding to :verilog:`$time` and :verilog:`$realtime`) + +For integers, this item may follow: + +``+``\ *?* + (optional, decimals only) Include a leading plus for non-negative numbers. + This can assist with symmetry with negatives in tabulated output. + +signedness + ``u`` for unsigned, ``s`` for signed. This distinction is only respected + when rendering decimals. + +ASCII characters/strings have no special options, but the signal size must be +divisible by 8. + +For simulation time, the signal size must be zero. + +Finally: + +``}`` + Denotes the end of the format specifier. + +Some example format specifiers: + ++ ``{8:>02hu}`` - 8-bit unsigned integer rendered as hexadecimal, + right-justified, zero-padded to 2 characters wide. ++ ``{32:< 15d+s}`` - 32-bit signed integer rendered as decimal, left-justified, + space-padded to 15 characters wide, positive values prefixed with ``+``. ++ ``{16:< 10hu}`` - 16-bit unsigned integer rendered as hexadecimal, + left-justified, space-padded to 10 characters wide. ++ ``{0:>010t}`` - simulation time, right-justified, zero-padded to 10 characters + wide. + +To include literal ``{`` and ``}`` characters in your format string, use ``{{`` +and ``}}`` respectively. + +It is an error for a format string to consume more or less bits from ``\ARGS`` +than the port width. + +Values are never truncated, regardless of the specified width. + +Note that further restrictions on allowable combinations of options may apply +depending on the backend used. + +For example, Verilog does not have a format specifier that allows zero-padding a +string (i.e. more than 1 ASCII character), though zero-padding a single +character is permitted. + +Thus, while the RTLIL format specifier ``{8:>02c}`` translates to ``%02c``, +``{16:>02c}`` cannot be represented in Verilog and will fail to emit. In this +case, ``{16:> 02c}`` must be used, which translates to ``%2s``. + .. _sec:celllib_gates: Gates diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 8893d5e010c..e357579add2 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -30,6 +30,7 @@ #define AST_H #include "kernel/rtlil.h" +#include "kernel/fmt.h" #include #include @@ -277,7 +278,9 @@ namespace AST bool replace_variables(std::map &variables, AstNode *fcall, bool must_succeed); AstNode *eval_const_function(AstNode *fcall, bool must_succeed); bool is_simple_const_expr(); - std::string process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint); + + // helper for parsing format strings + Fmt processFormat(int stage, bool sformat_like, int default_base = 10, size_t first_arg_at = 0); bool is_recursive_function() const; std::pair get_tern_choice(); diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 3aa19b70687..d62f06ae549 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -315,7 +315,10 @@ struct AST_INTERNAL::ProcessGenerator // Buffer for generating the init action RTLIL::SigSpec init_lvalue, init_rvalue; - ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg) + // The most recently assigned $print cell \PRIORITY. + int last_print_priority; + + ProcessGenerator(AstNode *always, RTLIL::SigSpec initSyncSignalsArg = RTLIL::SigSpec()) : always(always), initSyncSignals(initSyncSignalsArg), last_print_priority(0) { // rewrite lookahead references LookaheadRewriter la_rewriter(always); @@ -693,8 +696,86 @@ struct AST_INTERNAL::ProcessGenerator ast->input_error("Found parameter declaration in block without label!\n"); break; - case AST_NONE: case AST_TCALL: + if (ast->str == "$display" || ast->str == "$displayb" || ast->str == "$displayh" || ast->str == "$displayo" || + ast->str == "$write" || ast->str == "$writeb" || ast->str == "$writeh" || ast->str == "$writeo") { + std::stringstream sstr; + sstr << ast->str << "$" << ast->filename << ":" << ast->location.first_line << "$" << (autoidx++); + + RTLIL::Cell *cell = current_module->addCell(sstr.str(), ID($print)); + set_src_attr(cell, ast); + + RTLIL::SigSpec triggers; + RTLIL::Const polarity; + for (auto sync : proc->syncs) { + if (sync->type == RTLIL::STp) { + triggers.append(sync->signal); + polarity.bits.push_back(RTLIL::S1); + } else if (sync->type == RTLIL::STn) { + triggers.append(sync->signal); + polarity.bits.push_back(RTLIL::S0); + } + } + cell->parameters[ID::TRG_WIDTH] = triggers.size(); + cell->parameters[ID::TRG_ENABLE] = !triggers.empty(); + cell->parameters[ID::TRG_POLARITY] = polarity; + cell->parameters[ID::PRIORITY] = --last_print_priority; + cell->setPort(ID::TRG, triggers); + + Wire *wire = current_module->addWire(sstr.str() + "_EN", 1); + set_src_attr(wire, ast); + cell->setPort(ID::EN, wire); + + proc->root_case.actions.push_back(SigSig(wire, false)); + current_case->actions.push_back(SigSig(wire, true)); + + int default_base = 10; + if (ast->str.back() == 'b') + default_base = 2; + else if (ast->str.back() == 'o') + default_base = 8; + else if (ast->str.back() == 'h') + default_base = 16; + + std::vector args; + for (auto node : ast->children) { + int width; + bool is_signed; + node->detectSignWidth(width, is_signed, nullptr); + + VerilogFmtArg arg = {}; + arg.filename = node->filename; + arg.first_line = node->location.first_line; + if (node->type == AST_CONSTANT && node->is_string) { + arg.type = VerilogFmtArg::STRING; + arg.str = node->bitsAsConst().decode_string(); + // and in case this will be used as an argument... + arg.sig = node->bitsAsConst(); + arg.signed_ = false; + } else if (node->type == AST_IDENTIFIER && node->str == "$time") { + arg.type = VerilogFmtArg::TIME; + } else if (node->type == AST_IDENTIFIER && node->str == "$realtime") { + arg.type = VerilogFmtArg::TIME; + arg.realtime = true; + } else { + arg.type = VerilogFmtArg::INTEGER; + arg.sig = node->genWidthRTLIL(-1, false, &subst_rvalue_map.stdmap()); + arg.signed_ = is_signed; + } + args.push_back(arg); + } + + Fmt fmt = {}; + fmt.parse_verilog(args, /*sformat_like=*/false, default_base, /*task_name=*/ast->str, current_module->name); + if (ast->str.substr(0, 8) == "$display") + fmt.append_string("\n"); + fmt.emit_rtlil(cell); + } else if (!ast->str.empty()) { + log_file_error(ast->filename, ast->location.first_line, "Found unsupported invocation of system task `%s'!\n", ast->str.c_str()); + } + break; + + case AST_NONE: case AST_FOR: break; diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 64191cd7ebf..ee1be3781c8 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -43,141 +43,40 @@ using namespace AST_INTERNAL; // Process a format string and arguments for $display, $write, $sprintf, etc -std::string AstNode::process_format_str(const std::string &sformat, int next_arg, int stage, int width_hint, bool sign_hint) { - // Other arguments are placeholders. Process the string as we go through it - std::string sout; - for (size_t i = 0; i < sformat.length(); i++) - { - // format specifier - if (sformat[i] == '%') - { - // If there's no next character, that's a problem - if (i+1 >= sformat.length()) - input_error("System task `%s' called with `%%' at end of string.\n", str.c_str()); - - char cformat = sformat[++i]; - - // %% is special, does not need a matching argument - if (cformat == '%') - { - sout += '%'; - continue; - } - - bool got_len = false; - bool got_zlen = false; - int len_value = 0; - - while ('0' <= cformat && cformat <= '9') - { - if (!got_len && cformat == '0') - got_zlen = true; - - got_len = true; - len_value = 10*len_value + (cformat - '0'); - - cformat = sformat[++i]; - } - - // Simplify the argument - AstNode *node_arg = nullptr; - - // Everything from here on depends on the format specifier - switch (cformat) - { - case 's': - case 'S': - case 'd': - case 'D': - if (got_len && len_value != 0) - goto unsupported_format; - YS_FALLTHROUGH - case 'x': - case 'X': - if (next_arg >= GetSize(children)) - input_error("Missing argument for %%%c format specifier in system task `%s'.\n", - cformat, str.c_str()); - - node_arg = children[next_arg++]; - while (node_arg->simplify(true, false, stage, width_hint, sign_hint, false)) { } - if (node_arg->type != AST_CONSTANT) - input_error("Failed to evaluate system task `%s' with non-constant argument.\n", str.c_str()); - break; - - case 'm': - case 'M': - if (got_len) - goto unsupported_format; - break; - - case 'l': - case 'L': - if (got_len) - goto unsupported_format; - break; - - default: - unsupported_format: - input_error("System task `%s' called with invalid/unsupported format specifier.\n", str.c_str()); - break; - } - - switch (cformat) - { - case 's': - case 'S': - sout += node_arg->bitsAsConst().decode_string(); - break; - - case 'd': - case 'D': - sout += stringf("%d", node_arg->bitsAsConst().as_int()); - break; - - case 'x': - case 'X': - { - Const val = node_arg->bitsAsConst(); - - while (GetSize(val) % 4 != 0) - val.bits.push_back(State::S0); - - int len = GetSize(val) / 4; - for (int i = len; i < len_value; i++) - sout += got_zlen ? '0' : ' '; - - for (int i = len-1; i >= 0; i--) { - Const digit = val.extract(4*i, 4); - if (digit.is_fully_def()) - sout += stringf(cformat == 'x' ? "%x" : "%X", digit.as_int()); - else - sout += cformat == 'x' ? "x" : "X"; - } - } - break; - - case 'm': - case 'M': - sout += log_id(current_module->name); - break; - - case 'l': - case 'L': - sout += log_id(current_module->name); - break; - - default: - log_abort(); - } +Fmt AstNode::processFormat(int stage, bool sformat_like, int default_base, size_t first_arg_at) { + std::vector args; + for (size_t index = first_arg_at; index < children.size(); index++) { + AstNode *node_arg = children[index]; + while (node_arg->simplify(true, false, stage, -1, false, false)) { } + + VerilogFmtArg arg = {}; + arg.filename = filename; + arg.first_line = location.first_line; + if (node_arg->type == AST_CONSTANT && node_arg->is_string) { + arg.type = VerilogFmtArg::STRING; + arg.str = node_arg->bitsAsConst().decode_string(); + // and in case this will be used as an argument... + arg.sig = node_arg->bitsAsConst(); + arg.signed_ = false; + } else if (node_arg->type == AST_IDENTIFIER && node_arg->str == "$time") { + arg.type = VerilogFmtArg::TIME; + } else if (node_arg->type == AST_IDENTIFIER && node_arg->str == "$realtime") { + arg.type = VerilogFmtArg::TIME; + arg.realtime = true; + } else if (node_arg->type == AST_CONSTANT) { + arg.type = VerilogFmtArg::INTEGER; + arg.sig = node_arg->bitsAsConst(); + arg.signed_ = node_arg->is_signed; + } else { + log_file_error(filename, location.first_line, "Failed to evaluate system task `%s' with non-constant argument at position %zu.\n", str.c_str(), index + 1); } - - // not a format specifier - else - sout += sformat[i]; + args.push_back(arg); } - return sout; -} + Fmt fmt = {}; + fmt.parse_verilog(args, sformat_like, default_base, /*task_name=*/str, current_module->name); + return fmt; +} void AstNode::annotateTypedEnums(AstNode *template_node) { @@ -1057,33 +956,34 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin str = std::string(); } - if ((type == AST_TCALL) && (str == "$display" || str == "$write") && (!current_always || current_always->type != AST_INITIAL)) { - log_file_warning(filename, location.first_line, "System task `%s' outside initial block is unsupported.\n", str.c_str()); - delete_children(); - str = std::string(); - } - - // print messages if this a call to $display() or $write() - // This code implements only a small subset of Verilog-2005 $display() format specifiers, - // but should be good enough for most uses - if ((type == AST_TCALL) && ((str == "$display") || (str == "$write"))) + if ((type == AST_TCALL) && + (str == "$display" || str == "$displayb" || str == "$displayh" || str == "$displayo" || + str == "$write" || str == "$writeb" || str == "$writeh" || str == "$writeo")) { - int nargs = GetSize(children); - if (nargs < 1) - input_error("System task `%s' got %d arguments, expected >= 1.\n", - str.c_str(), int(children.size())); - - // First argument is the format string - AstNode *node_string = children[0]; - while (node_string->simplify(true, false, stage, width_hint, sign_hint, false)) { } - if (node_string->type != AST_CONSTANT) - input_error("Failed to evaluate system task `%s' with non-constant 1st argument.\n", str.c_str()); - std::string sformat = node_string->bitsAsConst().decode_string(); - std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); - // Finally, print the message (only include a \n for $display, not for $write) - log("%s", sout.c_str()); - if (str == "$display") - log("\n"); + if (!current_always) { + log_file_warning(filename, location.first_line, "System task `%s' outside initial or always block is unsupported.\n", str.c_str()); + } else if (current_always->type == AST_INITIAL) { + int default_base = 10; + if (str.back() == 'b') + default_base = 2; + else if (str.back() == 'o') + default_base = 8; + else if (str.back() == 'h') + default_base = 16; + + // when $display()/$write() functions are used in an initial block, print them during synthesis + Fmt fmt = processFormat(stage, /*sformat_like=*/false, default_base); + if (str.substr(0, 8) == "$display") + fmt.append_string("\n"); + log("%s", fmt.render().c_str()); + } else { + // when $display()/$write() functions are used in an always block, simplify the expressions and + // convert them to a special cell later in genrtlil + for (auto node : children) + while (node->simplify(true, false, stage, -1, false, false)) {} + return false; + } + delete_children(); str = std::string(); } @@ -3735,13 +3635,8 @@ skip_dynamic_range_lvalue_expansion:; } if (str == "\\$sformatf") { - AstNode *node_string = children[0]; - while (node_string->simplify(true, false, stage, width_hint, sign_hint, false)) { } - if (node_string->type != AST_CONSTANT) - input_error("Failed to evaluate system function `%s' with non-constant 1st argument.\n", str.c_str()); - std::string sformat = node_string->bitsAsConst().decode_string(); - std::string sout = process_format_str(sformat, 1, stage, width_hint, sign_hint); - newNode = AstNode::mkconst_str(sout); + Fmt fmt = processFormat(stage, /*sformat_like=*/true); + newNode = AstNode::mkconst_str(fmt.render()); goto apply_newNode; } diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index b0d789d8fa3..a67244d7ab3 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -74,7 +74,7 @@ USING_YOSYS_NAMESPACE # error "Only YosysHQ flavored Verific is supported. Please contact office@yosyshq.com for commercial support for Yosys+Verific." #endif -#if YOSYSHQ_VERIFIC_API_VERSION < 20210801 +#if YOSYSHQ_VERIFIC_API_VERSION < 20230901 # error "Please update your version of YosysHQ flavored Verific." #endif @@ -251,6 +251,14 @@ static const RTLIL::Const verific_const(const char *value, bool allow_string = t return c; } +static const std::string verific_unescape(const char *value) +{ + std::string val = std::string(value); + if (val.size()>1 && val[0]=='\"' && val.back()=='\"') + return val.substr(1,val.size()-2); + return value; +} + void VerificImporter::import_attributes(dict &attributes, DesignObj *obj, Netlist *nl) { MapIter mi; @@ -1103,6 +1111,43 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == OPER_YOSYSHQ_SET_TAG) + { + RTLIL::SigSpec sig_expr = operatorInport(inst, "expr"); + RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); + RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); + RTLIL::SigSpec sig_o = operatorOutput(inst); + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; + module->connect(sig_o, module->SetTag(new_verific_id(inst), tag, sig_expr, sig_set_mask, sig_clr_mask)); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_GET_TAG) + { + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; + module->connect(operatorOutput(inst),module->GetTag(new_verific_id(inst), tag, operatorInput(inst))); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_OVERWRITE_TAG) + { + RTLIL::SigSpec sig_signal = operatorInport(inst, "signal"); + RTLIL::SigSpec sig_set_mask = operatorInport(inst, "set_mask"); + RTLIL::SigSpec sig_clr_mask = operatorInport(inst, "clr_mask"); + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; + module->addOverwriteTag(new_verific_id(inst), tag, sig_signal, sig_set_mask, sig_clr_mask); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_ORIGINAL_TAG) + { + std::string tag = inst->GetAtt("tag") ? verific_unescape(inst->GetAttValue("tag")) : ""; + module->connect(operatorOutput(inst),module->OriginalTag(new_verific_id(inst), tag, operatorInput(inst))); + return true; + } + if (inst->Type() == OPER_YOSYSHQ_FUTURE_FF) + { + module->connect(operatorOutput(inst),module->FutureFF(new_verific_id(inst), operatorInput(inst))); + return true; + } + #undef IN #undef IN1 #undef IN2 @@ -2951,6 +2996,9 @@ struct VerificPass : public Pass { RuntimeFlags::SetVar("db_infer_wide_operators", 1); RuntimeFlags::SetVar("db_infer_set_reset_registers", 0); + // Properly respect order of read and write for rams + RuntimeFlags::SetVar("db_change_inplace_ram_blocking_write_before_read", 1); + RuntimeFlags::SetVar("veri_extract_dualport_rams", 0); RuntimeFlags::SetVar("veri_extract_multiport_rams", 1); RuntimeFlags::SetVar("veri_allow_any_ram_in_loop", 1); diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 24998666828..8a37343022f 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -386,7 +386,7 @@ and|nand|or|nor|xor|xnor|not|buf|bufif0|bufif1|notif0|notif1 { supply0 { return TOK_SUPPLY0; } supply1 { return TOK_SUPPLY1; } -"$"(display|write|strobe|monitor|time|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { +"$"(display[bho]?|write[bho]?|strobe|monitor|time|realtime|stop|finish|dumpfile|dumpvars|dumpon|dumpoff|dumpall) { yylval->string = new std::string(yytext); return TOK_ID; } diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 98bdbf9e5c5..1e82940bbbd 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -1830,7 +1830,7 @@ struct_member_type: { astbuf1 = new AstNode(AST_STRUCT_ITEM); } member_type_toke ; member_type_token: - member_type + member_type | hierarchical_type_id { addWiretypeNode($1, astbuf1); } @@ -2721,6 +2721,7 @@ behavioral_stmt: ast_stack.push_back(node); append_attr(node, $1); } opt_arg_list ';'{ + SET_AST_NODE_LOC(ast_stack.back(), @2, @5); ast_stack.pop_back(); } | attr TOK_MSG_TASKS { @@ -2731,6 +2732,7 @@ behavioral_stmt: ast_stack.push_back(node); append_attr(node, $1); } opt_arg_list ';'{ + SET_AST_NODE_LOC(ast_stack.back(), @2, @5); ast_stack.pop_back(); } | attr TOK_BEGIN { diff --git a/kernel/cellaigs.cc b/kernel/cellaigs.cc index 332f821b76c..5dda4503fdd 100644 --- a/kernel/cellaigs.cc +++ b/kernel/cellaigs.cc @@ -385,17 +385,17 @@ Aig::Aig(Cell *cell) goto optimize; } - if (cell->type.in({ID($lt), ID($gt), ID($le), ID($ge)})) + if (cell->type.in(ID($lt), ID($gt), ID($le), ID($ge))) { int width = std::max(GetSize(cell->getPort(ID::A)), GetSize(cell->getPort(ID::B))) + 1; vector A = mk.inport_vec(ID::A, width); vector B = mk.inport_vec(ID::B, width); - if (cell->type.in({ID($gt), ID($ge)})) + if (cell->type.in(ID($gt), ID($ge))) std::swap(A, B); - int carry = mk.bool_node(!cell->type.in({ID($le), ID($ge)})); + int carry = mk.bool_node(!cell->type.in(ID($le), ID($ge))); for (auto &n : B) n = mk.not_gate(n); vector Y = mk.adder(A, B, carry); diff --git a/kernel/celltypes.h b/kernel/celltypes.h index 63e7408c142..cad505d9afd 100644 --- a/kernel/celltypes.h +++ b/kernel/celltypes.h @@ -101,6 +101,12 @@ struct CellTypes setup_type(ID($specify2), {ID::EN, ID::SRC, ID::DST}, pool(), true); setup_type(ID($specify3), {ID::EN, ID::SRC, ID::DST, ID::DAT}, pool(), true); setup_type(ID($specrule), {ID::EN_SRC, ID::EN_DST, ID::SRC, ID::DST}, pool(), true); + setup_type(ID($print), {ID::EN, ID::ARGS, ID::TRG}, pool()); + setup_type(ID($set_tag), {ID::A, ID::SET, ID::CLR}, {ID::Y}); + setup_type(ID($get_tag), {ID::A}, {ID::Y}); + setup_type(ID($overwrite_tag), {ID::A, ID::SET, ID::CLR}, pool()); + setup_type(ID($original_tag), {ID::A}, {ID::Y}); + setup_type(ID($future_ff), {ID::A}, {ID::Y}); } void setup_internals_eval() diff --git a/kernel/constids.inc b/kernel/constids.inc index 39211d0c753..93101282a0b 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -22,6 +22,8 @@ X(always_ff) X(always_latch) X(anyconst) X(anyseq) +X(ARGS) +X(ARGS_WIDTH) X(ARST) X(ARST_POLARITY) X(ARST_VALUE) @@ -86,6 +88,7 @@ X(equiv_merged) X(equiv_region) X(extract_order) X(F) +X(FORMAT) X(force_downto) X(force_upto) X(fsm_encoding) @@ -205,6 +208,7 @@ X(syn_romstyle) X(S_WIDTH) X(T) X(TABLE) +X(TAG) X(techmap_autopurge) X(_TECHMAP_BITS_CONNMAP_) X(_TECHMAP_CELLNAME_) @@ -233,6 +237,10 @@ X(TRANS_NUM) X(TRANSPARENCY_MASK) X(TRANSPARENT) X(TRANS_TABLE) +X(TRG) +X(TRG_ENABLE) +X(TRG_POLARITY) +X(TRG_WIDTH) X(T_RISE_MAX) X(T_RISE_MIN) X(T_RISE_TYP) diff --git a/kernel/fmt.cc b/kernel/fmt.cc new file mode 100644 index 00000000000..965e58ebce4 --- /dev/null +++ b/kernel/fmt.cc @@ -0,0 +1,758 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 whitequark + * + * 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 "libs/bigint/BigUnsigned.hh" +#include "kernel/fmt.h" + +USING_YOSYS_NAMESPACE + +void Fmt::append_string(const std::string &str) { + FmtPart part = {}; + part.type = FmtPart::STRING; + part.str = str; + parts.push_back(part); +} + +void Fmt::parse_rtlil(const RTLIL::Cell *cell) { + std::string fmt = cell->getParam(ID(FORMAT)).decode_string(); + RTLIL::SigSpec args = cell->getPort(ID(ARGS)); + parts.clear(); + + FmtPart part; + for (size_t i = 0; i < fmt.size(); i++) { + if (fmt.substr(i, 2) == "}}") { + part.str += '}'; + ++i; + } else if (fmt.substr(i, 2) == "{{") { + part.str += '{'; + ++i; + } else if (fmt[i] == '}') + log_assert(false && "Unexpected '}' in format string"); + else if (fmt[i] == '{') { + if (!part.str.empty()) { + part.type = FmtPart::STRING; + parts.push_back(part); + part = {}; + } + + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + + size_t arg_size = 0; + for (; i < fmt.size(); i++) { + if (fmt[i] >= '0' && fmt[i] <= '9') { + arg_size *= 10; + arg_size += fmt[i] - '0'; + } else if (fmt[i] == ':') { + ++i; + break; + } else { + log_assert(false && "Unexpected character in format substitution"); + } + } + if (i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + + if ((size_t)args.size() < arg_size) + log_assert(false && "Format part overruns arguments"); + part.sig = args.extract(0, arg_size); + args.remove(0, arg_size); + + if (fmt[i] == '>') + part.justify = FmtPart::RIGHT; + else if (fmt[i] == '<') + part.justify = FmtPart::LEFT; + else + log_assert(false && "Unexpected justification in format substitution"); + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + + if (fmt[i] == '0' || fmt[i] == ' ') + part.padding = fmt[i]; + else + log_assert(false && "Unexpected padding in format substitution"); + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + + for (; i < fmt.size(); i++) { + if (fmt[i] >= '0' && fmt[i] <= '9') { + part.width *= 10; + part.width += fmt[i] - '0'; + continue; + } else if (fmt[i] == 'b') { + part.type = FmtPart::INTEGER; + part.base = 2; + } else if (fmt[i] == 'o') { + part.type = FmtPart::INTEGER; + part.base = 8; + } else if (fmt[i] == 'd') { + part.type = FmtPart::INTEGER; + part.base = 10; + } else if (fmt[i] == 'h') { + part.type = FmtPart::INTEGER; + part.base = 16; + } else if (fmt[i] == 'c') { + part.type = FmtPart::CHARACTER; + } else if (fmt[i] == 't') { + part.type = FmtPart::TIME; + } else if (fmt[i] == 'r') { + part.type = FmtPart::TIME; + part.realtime = true; + } else { + log_assert(false && "Unexpected character in format substitution"); + } + ++i; + break; + } + if (i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + + if (part.type == FmtPart::INTEGER) { + if (fmt[i] == '+') { + part.plus = true; + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + } + + if (fmt[i] == 'u') + part.signed_ = false; + else if (fmt[i] == 's') + part.signed_ = true; + else + log_assert(false && "Unexpected character in format substitution"); + if (++i == fmt.size()) + log_assert(false && "Unexpected end in format substitution"); + } + + if (fmt[i] != '}') + log_assert(false && "Expected '}' after format substitution"); + + parts.push_back(part); + part = {}; + } else { + part.str += fmt[i]; + } + } + if (!part.str.empty()) { + part.type = FmtPart::STRING; + parts.push_back(part); + } +} + +void Fmt::emit_rtlil(RTLIL::Cell *cell) const { + std::string fmt; + RTLIL::SigSpec args; + + for (auto &part : parts) { + switch (part.type) { + case FmtPart::STRING: + for (char c : part.str) { + if (c == '{') + fmt += "{{"; + else if (c == '}') + fmt += "}}"; + else + fmt += c; + } + break; + + case FmtPart::TIME: + log_assert(part.sig.size() == 0); + YS_FALLTHROUGH + case FmtPart::CHARACTER: + log_assert(part.sig.size() % 8 == 0); + YS_FALLTHROUGH + case FmtPart::INTEGER: + args.append(part.sig); + fmt += '{'; + fmt += std::to_string(part.sig.size()); + fmt += ':'; + if (part.justify == FmtPart::RIGHT) + fmt += '>'; + else if (part.justify == FmtPart::LEFT) + fmt += '<'; + else log_abort(); + log_assert(part.width == 0 || part.padding != '\0'); + fmt += part.padding != '\0' ? part.padding : ' '; + if (part.width > 0) + fmt += std::to_string(part.width); + if (part.type == FmtPart::INTEGER) { + switch (part.base) { + case 2: fmt += 'b'; break; + case 8: fmt += 'o'; break; + case 10: fmt += 'd'; break; + case 16: fmt += 'h'; break; + default: log_abort(); + } + if (part.plus) + fmt += '+'; + fmt += part.signed_ ? 's' : 'u'; + } else if (part.type == FmtPart::CHARACTER) { + fmt += 'c'; + } else if (part.type == FmtPart::TIME) { + if (part.realtime) + fmt += 'r'; + else + fmt += 't'; + } else log_abort(); + fmt += '}'; + break; + + default: log_abort(); + } + } + + cell->setParam(ID(FORMAT), fmt); + cell->setParam(ID(ARGS_WIDTH), args.size()); + cell->setPort(ID(ARGS), args); +} + +static size_t compute_required_decimal_places(size_t size, bool signed_) +{ + BigUnsigned max; + if (!signed_) + max.setBit(size, true); + else + max.setBit(size - 1, true); + size_t places = 0; + while (!max.isZero()) { + places++; + max /= 10; + } + if (signed_) + places++; + return places; +} + +static size_t compute_required_nondecimal_places(size_t size, unsigned base) +{ + log_assert(base != 10); + BigUnsigned max; + max.setBit(size - 1, true); + size_t places = 0; + while (!max.isZero()) { + places++; + max /= base; + } + return places; +} + +// Only called for integers, either when: +// +// (a) passed without a format string (e.g. "$display(a);"), or +// +// (b) the corresponding format specifier has no leading zero, e.g. "%b", +// "%20h", "%-10d". +// +// In these cases, for binary/octal/hex, we always zero-pad to the size of the +// signal; i.e. whether "%h" or "%10h" or "%-20h" is used, if the corresponding +// signal is 32'h1234, "00001234" will always be a substring of the output. +// +// For case (a), we have no specified width, so there is nothing more to do. +// +// For case (b), because we are only called with no leading zero on the +// specifier, any specified width beyond the signal size is therefore space +// padding, whatever the justification. +// +// For decimal, we do no zero-padding, instead space-padding to the size +// required for the signal's largest value. This is per other Verilog +// implementations, and intuitively makes sense as decimal representations lack +// a discrete mapping of digits to bit groups. Decimals may also show sign and +// must accommodate this, whereas other representations do not. +void Fmt::apply_verilog_automatic_sizing_and_add(FmtPart &part) +{ + if (part.base == 10) { + size_t places = compute_required_decimal_places(part.sig.size(), part.signed_); + part.padding = ' '; + part.width = std::max(part.width, places); + parts.push_back(part); + return; + } + + part.padding = '0'; + + size_t places = compute_required_nondecimal_places(part.sig.size(), part.base); + if (part.width < places) { + part.justify = FmtPart::RIGHT; + part.width = places; + parts.push_back(part); + } else if (part.width == places) { + parts.push_back(part); + } else if (part.width > places) { + auto gap = std::string(part.width - places, ' '); + part.width = places; + + if (part.justify == FmtPart::RIGHT) { + append_string(gap); + parts.push_back(part); + } else { + part.justify = FmtPart::RIGHT; + parts.push_back(part); + append_string(gap); + } + } +} + +void Fmt::parse_verilog(const std::vector &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name) +{ + parts.clear(); + + auto arg = args.begin(); + for (; arg != args.end(); ++arg) { + switch (arg->type) { + case VerilogFmtArg::INTEGER: { + FmtPart part = {}; + part.type = FmtPart::INTEGER; + part.sig = arg->sig; + part.base = default_base; + part.signed_ = arg->signed_; + apply_verilog_automatic_sizing_and_add(part); + break; + } + + case VerilogFmtArg::STRING: { + if (arg == args.begin() || !sformat_like) { + const auto fmtarg = arg; + const std::string &fmt = fmtarg->str; + FmtPart part = {}; + for (size_t i = 0; i < fmt.size(); i++) { + if (fmt[i] != '%') { + part.str += fmt[i]; + } else if (fmt.substr(i, 2) == "%%") { + i++; + part.str += '%'; + } else if (fmt.substr(i, 2) == "%l" || fmt.substr(i, 2) == "%L") { + i++; + part.str += module_name.str(); + } else if (fmt.substr(i, 2) == "%m" || fmt.substr(i, 2) == "%M") { + i++; + part.str += module_name.str(); + } else { + if (!part.str.empty()) { + part.type = FmtPart::STRING; + parts.push_back(part); + part = {}; + } + if (++i == fmt.size()) { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); + } + + if (++arg == args.end()) { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with fewer arguments than the format specifiers in argument %zu require.\n", task_name.c_str(), fmtarg - args.begin() + 1); + } + part.sig = arg->sig; + part.signed_ = arg->signed_; + + for (; i < fmt.size(); i++) { + if (fmt[i] == '-') { + // left justify; not in IEEE 1800-2017 or verilator but iverilog has it + part.justify = FmtPart::LEFT; + } else if (fmt[i] == '+') { + // always show sign; not in IEEE 1800-2017 or verilator but iverilog has it + part.plus = true; + } else break; + } + if (i == fmt.size()) { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); + } + + bool has_leading_zero = false, has_width = false; + for (; i < fmt.size(); i++) { + if (fmt[i] >= '0' && fmt[i] <= '9') { + if (fmt[i] == '0' && !has_width) { + has_leading_zero = true; + } else { + has_width = true; + part.width *= 10; + part.width += fmt[i] - '0'; + } + continue; + } else if (fmt[i] == 'b' || fmt[i] == 'B') { + part.type = FmtPart::INTEGER; + part.base = 2; + } else if (fmt[i] == 'o' || fmt[i] == 'O') { + part.type = FmtPart::INTEGER; + part.base = 8; + } else if (fmt[i] == 'd' || fmt[i] == 'D') { + part.type = FmtPart::INTEGER; + part.base = 10; + } else if (fmt[i] == 'h' || fmt[i] == 'H' || + fmt[i] == 'x' || fmt[i] == 'X') { + // hex digits always printed in lowercase for %h%x as well as %H%X + part.type = FmtPart::INTEGER; + part.base = 16; + } else if (fmt[i] == 'c' || fmt[i] == 'C') { + part.type = FmtPart::CHARACTER; + part.sig.extend_u0(8); + // %10c and %010c not fully defined in IEEE 1800-2017 and do different things in iverilog + } else if (fmt[i] == 's' || fmt[i] == 'S') { + part.type = FmtPart::CHARACTER; + if ((part.sig.size() % 8) != 0) + part.sig.extend_u0((part.sig.size() + 7) / 8 * 8); + // %10s and %010s not fully defined in IEEE 1800-2017 and do the same thing in iverilog + part.padding = ' '; + } else if (fmt[i] == 't' || fmt[i] == 'T') { + if (arg->type == VerilogFmtArg::TIME) { + part.type = FmtPart::TIME; + part.realtime = arg->realtime; + if (!has_width && !has_leading_zero) + part.width = 20; + } else { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with format character `%c' in argument %zu, but the argument is not $time or $realtime.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1); + } + } else { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with unrecognized format character `%c' in argument %zu.\n", task_name.c_str(), fmt[i], fmtarg - args.begin() + 1); + } + break; + } + if (i == fmt.size()) { + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with incomplete format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); + } + + if (part.padding == '\0') + part.padding = (has_leading_zero && part.justify == FmtPart::RIGHT) ? '0' : ' '; + + if (part.type == FmtPart::INTEGER && part.base != 10 && part.plus) + log_file_error(fmtarg->filename, fmtarg->first_line, "System task `%s' called with invalid format specifier in argument %zu.\n", task_name.c_str(), fmtarg - args.begin() + 1); + + if (part.type == FmtPart::INTEGER && !has_leading_zero) + apply_verilog_automatic_sizing_and_add(part); + else + parts.push_back(part); + part = {}; + } + } + if (!part.str.empty()) { + part.type = FmtPart::STRING; + parts.push_back(part); + } + } else { + FmtPart part = {}; + part.type = FmtPart::STRING; + part.str = arg->str; + parts.push_back(part); + } + break; + } + + default: log_abort(); + } + } +} + +std::vector Fmt::emit_verilog() const +{ + std::vector args; + VerilogFmtArg fmt = {}; + fmt.type = VerilogFmtArg::STRING; + + for (auto &part : parts) { + switch (part.type) { + case FmtPart::STRING: + for (char c : part.str) { + if (c == '%') + fmt.str += "%%"; + else + fmt.str += c; + } + break; + + case FmtPart::INTEGER: { + VerilogFmtArg arg = {}; + arg.type = VerilogFmtArg::INTEGER; + arg.sig = part.sig; + arg.signed_ = part.signed_; + args.push_back(arg); + + fmt.str += '%'; + if (part.plus) + fmt.str += '+'; + if (part.justify == FmtPart::LEFT) + fmt.str += '-'; + if (part.width == 0) { + fmt.str += '0'; + } else if (part.width > 0) { + log_assert(part.padding == ' ' || part.padding == '0'); + if (part.base != 10 || part.padding == '0') + fmt.str += '0'; + fmt.str += std::to_string(part.width); + } + switch (part.base) { + case 2: fmt.str += 'b'; break; + case 8: fmt.str += 'o'; break; + case 10: fmt.str += 'd'; break; + case 16: fmt.str += 'h'; break; + default: log_abort(); + } + break; + } + + case FmtPart::CHARACTER: { + VerilogFmtArg arg; + arg.type = VerilogFmtArg::INTEGER; + arg.sig = part.sig; + args.push_back(arg); + + fmt.str += '%'; + if (part.justify == FmtPart::LEFT) + fmt.str += '-'; + if (part.sig.size() == 8) { + if (part.width > 0) { + log_assert(part.padding == '0' || part.padding == ' '); + if (part.padding == '0') + fmt.str += part.padding; + fmt.str += std::to_string(part.width); + } + fmt.str += 'c'; + } else { + log_assert(part.sig.size() % 8 == 0); + if (part.width > 0) { + log_assert(part.padding == ' '); // no zero padding + fmt.str += std::to_string(part.width); + } + fmt.str += 's'; + } + break; + } + + case FmtPart::TIME: { + VerilogFmtArg arg; + arg.type = VerilogFmtArg::TIME; + if (part.realtime) + arg.realtime = true; + args.push_back(arg); + + fmt.str += '%'; + if (part.plus) + fmt.str += '+'; + if (part.justify == FmtPart::LEFT) + fmt.str += '-'; + log_assert(part.padding == ' ' || part.padding == '0'); + if (part.padding == '0' && part.width > 0) + fmt.str += '0'; + fmt.str += std::to_string(part.width); + fmt.str += 't'; + break; + } + + default: log_abort(); + } + } + + args.insert(args.begin(), fmt); + return args; +} + +void Fmt::emit_cxxrtl(std::ostream &f, std::function emit_sig) const +{ + for (auto &part : parts) { + switch (part.type) { + case FmtPart::STRING: + f << " << \""; + for (char c : part.str) { + switch (c) { + case '\\': + YS_FALLTHROUGH + case '"': + f << '\\' << c; + break; + case '\a': + f << "\\a"; + break; + case '\b': + f << "\\b"; + break; + case '\f': + f << "\\f"; + break; + case '\n': + f << "\\n"; + break; + case '\r': + f << "\\r"; + break; + case '\t': + f << "\\t"; + break; + case '\v': + f << "\\v"; + break; + default: + f << c; + break; + } + } + f << '"'; + break; + + case FmtPart::INTEGER: + case FmtPart::CHARACTER: { + f << " << value_formatted<" << part.sig.size() << ">("; + emit_sig(part.sig); + f << ", " << (part.type == FmtPart::CHARACTER); + f << ", " << (part.justify == FmtPart::LEFT); + f << ", (char)" << (int)part.padding; + f << ", " << part.width; + f << ", " << part.base; + f << ", " << part.signed_; + f << ", " << part.plus; + f << ')'; + break; + } + + case FmtPart::TIME: { + // CXXRTL only records steps taken, so there's no difference between + // the values taken by $time and $realtime. + f << " << value_formatted<64>("; + f << "value<64>{steps}"; + f << ", " << (part.type == FmtPart::CHARACTER); + f << ", " << (part.justify == FmtPart::LEFT); + f << ", (char)" << (int)part.padding; + f << ", " << part.width; + f << ", " << part.base; + f << ", " << part.signed_; + f << ", " << part.plus; + f << ')'; + break; + } + + default: log_abort(); + } + } +} + +std::string Fmt::render() const +{ + std::string str; + + for (auto &part : parts) { + switch (part.type) { + case FmtPart::STRING: + str += part.str; + break; + + case FmtPart::INTEGER: + case FmtPart::TIME: + case FmtPart::CHARACTER: { + std::string buf; + if (part.type == FmtPart::INTEGER) { + RTLIL::Const value = part.sig.as_const(); + + if (part.base != 10) { + size_t minimum_size = 0; + for (size_t index = 0; index < (size_t)value.size(); index++) + if (value[index] != State::S0) + minimum_size = index + 1; + value = value.extract(0, minimum_size); + } + + if (part.base == 2) { + buf = value.as_string(); + } else if (part.base == 8 || part.base == 16) { + size_t step = (part.base == 16) ? 4 : 3; + for (size_t index = 0; index < (size_t)value.size(); index += step) { + RTLIL::Const subvalue = value.extract(index, min(step, value.size() - index)); + bool has_x = false, all_x = true, has_z = false, all_z = true; + for (State bit : subvalue) { + if (bit == State::Sx) + has_x = true; + else + all_x = false; + if (bit == State::Sz) + has_z = true; + else + all_z = false; + } + if (all_x) + buf += 'x'; + else if (all_z) + buf += 'z'; + else if (has_x) + buf += 'X'; + else if (has_z) + buf += 'Z'; + else + buf += "0123456789abcdef"[subvalue.as_int()]; + } + std::reverse(buf.begin(), buf.end()); + } else if (part.base == 10) { + bool has_x = false, all_x = true, has_z = false, all_z = true; + for (State bit : value) { + if (bit == State::Sx) + has_x = true; + else + all_x = false; + if (bit == State::Sz) + has_z = true; + else + all_z = false; + } + if (all_x) + buf += 'x'; + else if (all_z) + buf += 'z'; + else if (has_x) + buf += 'X'; + else if (has_z) + buf += 'Z'; + else { + bool negative = part.signed_ && value[value.size() - 1]; + RTLIL::Const absvalue; + if (negative) + absvalue = RTLIL::const_neg(value, {}, part.signed_, {}, value.size() + 1); + else + absvalue = value; + log_assert(absvalue.is_fully_def()); + if (absvalue.is_fully_zero()) + buf += '0'; + while (!absvalue.is_fully_zero()) { + buf += '0' + RTLIL::const_mod(absvalue, 10, false, false, 4).as_int(); + absvalue = RTLIL::const_div(absvalue, 10, false, false, absvalue.size()); + } + if (negative || part.plus) + buf += negative ? '-' : '+'; + std::reverse(buf.begin(), buf.end()); + } + } else log_abort(); + } else if (part.type == FmtPart::CHARACTER) { + buf = part.sig.as_const().decode_string(); + } else if (part.type == FmtPart::TIME) { + // We only render() during initial, so time is always zero. + buf = "0"; + } + + log_assert(part.width == 0 || part.padding != '\0'); + if (part.justify == FmtPart::RIGHT && buf.size() < part.width) { + size_t pad_width = part.width - buf.size(); + if (part.padding == '0' && (!buf.empty() && (buf.front() == '+' || buf.front() == '-'))) { + str += buf.front(); + buf.erase(0, 1); + } + str += std::string(pad_width, part.padding); + } + str += buf; + if (part.justify == FmtPart::LEFT && buf.size() < part.width) + str += std::string(part.width - buf.size(), part.padding); + break; + } + } + } + + return str; +} diff --git a/kernel/fmt.h b/kernel/fmt.h new file mode 100644 index 00000000000..39a278c562e --- /dev/null +++ b/kernel/fmt.h @@ -0,0 +1,106 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2020 whitequark + * + * 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 FMT_H +#define FMT_H + +#include "kernel/yosys.h" + +YOSYS_NAMESPACE_BEGIN + +// Verilog format argument, such as the arguments in: +// $display("foo %d bar %01x", 4'b0, $signed(2'b11)) +struct VerilogFmtArg { + enum { + STRING = 0, + INTEGER = 1, + TIME = 2, + } type; + + // All types + std::string filename; + unsigned first_line; + + // STRING type + std::string str; + + // INTEGER type + RTLIL::SigSpec sig; + bool signed_ = false; + + // TIME type + bool realtime = false; +}; + +// RTLIL format part, such as the substitutions in: +// "foo {4:> 4du} bar {2:<01hs}" +struct FmtPart { + enum { + STRING = 0, + INTEGER = 1, + CHARACTER = 2, + TIME = 3, + } type; + + // STRING type + std::string str; + + // INTEGER/CHARACTER types + RTLIL::SigSpec sig; + + // INTEGER/CHARACTER/TIME types + enum { + RIGHT = 0, + LEFT = 1, + } justify = RIGHT; + char padding = '\0'; + size_t width = 0; + + // INTEGER type + unsigned base = 10; + bool signed_ = false; + bool plus = false; + + // TIME type + bool realtime = false; +}; + +struct Fmt { +public: + std::vector parts; + + void append_string(const std::string &str); + + void parse_rtlil(const RTLIL::Cell *cell); + void emit_rtlil(RTLIL::Cell *cell) const; + + void parse_verilog(const std::vector &args, bool sformat_like, int default_base, RTLIL::IdString task_name, RTLIL::IdString module_name); + std::vector emit_verilog() const; + + void emit_cxxrtl(std::ostream &f, std::function emit_sig) const; + + std::string render() const; + +private: + void apply_verilog_automatic_sizing_and_add(FmtPart &part); +}; + +YOSYS_NAMESPACE_END + +#endif diff --git a/kernel/mem.cc b/kernel/mem.cc index 628f6210499..269a476a125 100644 --- a/kernel/mem.cc +++ b/kernel/mem.cc @@ -1252,12 +1252,12 @@ void Mem::prepare_wr_merge(int idx1, int idx2, FfInitVals *initvals) { // If transparent with only one, emulate it, and remove the collision-X // flag that emulate_transparency will set (to align with the other port). if (rport.transparency_mask[idx1]) { - emulate_transparency(i, idx1, initvals); + emulate_transparency(idx1, i, initvals); rport.collision_x_mask[idx1] = false; continue; } if (rport.transparency_mask[idx2]) { - emulate_transparency(i, idx2, initvals); + emulate_transparency(idx2, i, initvals); rport.collision_x_mask[idx2] = false; continue; } diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index 7011429ff5a..51d02091308 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -1720,6 +1720,18 @@ namespace { return; } + if (cell->type == ID($print)) { + param(ID(FORMAT)); + param_bool(ID::TRG_ENABLE); + param(ID::TRG_POLARITY); + param(ID::PRIORITY); + port(ID::EN, 1); + port(ID::TRG, param(ID::TRG_WIDTH)); + port(ID::ARGS, param(ID::ARGS_WIDTH)); + check_expected(); + return; + } + if (cell->type == ID($_BUF_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; } if (cell->type == ID($_NOT_)) { port(ID::A,1); port(ID::Y,1); check_expected(); return; } if (cell->type == ID($_AND_)) { port(ID::A,1); port(ID::B,1); port(ID::Y,1); check_expected(); return; } @@ -1816,6 +1828,40 @@ namespace { ID($_DLATCHSR_PNN_), ID($_DLATCHSR_PNP_), ID($_DLATCHSR_PPN_), ID($_DLATCHSR_PPP_))) { port(ID::E,1); port(ID::S,1); port(ID::R,1); port(ID::D,1); port(ID::Q,1); check_expected(); return; } + if (cell->type.in(ID($set_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::SET, param(ID::WIDTH)); + port(ID::CLR, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($get_tag),ID($original_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($overwrite_tag))) { + param(ID::WIDTH); + param(ID::TAG); + port(ID::A, param(ID::WIDTH)); + port(ID::SET, param(ID::WIDTH)); + port(ID::CLR, param(ID::WIDTH)); + check_expected(); + return; + } + if (cell->type.in(ID($future_ff))) { + param(ID::WIDTH); + port(ID::A, param(ID::WIDTH)); + port(ID::Y, param(ID::WIDTH)); + check_expected(); + return; + } error(__LINE__); } }; @@ -3234,6 +3280,80 @@ RTLIL::SigSpec RTLIL::Module::Initstate(RTLIL::IdString name, const std::string return sig; } +RTLIL::SigSpec RTLIL::Module::SetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); + Cell *cell = addCell(name, ID($set_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + +RTLIL::Cell* RTLIL::Module::addSetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src) +{ + Cell *cell = addCell(name, ID($set_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->setPort(ID::Y, sig_y); + cell->set_src_attribute(src); + return cell; +} + +RTLIL::SigSpec RTLIL::Module::GetTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); + Cell *cell = addCell(name, ID($get_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + +RTLIL::Cell* RTLIL::Module::addOverwriteTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src) +{ + RTLIL::Cell *cell = addCell(name, ID($overwrite_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::SET, sig_s); + cell->setPort(ID::CLR, sig_c); + cell->set_src_attribute(src); + return cell; +} + +RTLIL::SigSpec RTLIL::Module::OriginalTag(RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_a.size()); + Cell *cell = addCell(name, ID($original_tag)); + cell->parameters[ID::WIDTH] = sig_a.size(); + cell->parameters[ID::TAG] = tag; + cell->setPort(ID::A, sig_a); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + +RTLIL::SigSpec RTLIL::Module::FutureFF(RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src) +{ + RTLIL::SigSpec sig = addWire(NEW_ID, sig_e.size()); + Cell *cell = addCell(name, ID($future_ff)); + cell->parameters[ID::WIDTH] = sig_e.size(); + cell->setPort(ID::A, sig_e); + cell->setPort(ID::Y, sig); + cell->set_src_attribute(src); + return sig; +} + RTLIL::Wire::Wire() { static unsigned int hashidx_count = 123456789; diff --git a/kernel/rtlil.h b/kernel/rtlil.h index a69ce480baf..c50d75e9087 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -1465,6 +1465,13 @@ struct RTLIL::Module : public RTLIL::AttrObject RTLIL::SigSpec Allseq (RTLIL::IdString name, int width = 1, const std::string &src = ""); RTLIL::SigSpec Initstate (RTLIL::IdString name, const std::string &src = ""); + RTLIL::SigSpec SetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::Cell* addSetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const RTLIL::SigSpec &sig_y, const std::string &src = ""); + RTLIL::SigSpec GetTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); + RTLIL::Cell* addOverwriteTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const RTLIL::SigSpec &sig_s, const RTLIL::SigSpec &sig_c, const std::string &src = ""); + RTLIL::SigSpec OriginalTag (RTLIL::IdString name, const std::string &tag, const RTLIL::SigSpec &sig_a, const std::string &src = ""); + RTLIL::SigSpec FutureFF (RTLIL::IdString name, const RTLIL::SigSpec &sig_e, const std::string &src = ""); + #ifdef WITH_PYTHON static std::map *get_all_modules(void); #endif diff --git a/libs/fst/fstapi.cc b/libs/fst/fstapi.cc index da0d959a0de..592b5cae6a7 100644 --- a/libs/fst/fstapi.cc +++ b/libs/fst/fstapi.cc @@ -348,17 +348,17 @@ static void *fstMmap2(size_t __len, int __fd, fst_off_t __off) #ifdef FST_DO_MISALIGNED_OPS #define fstGetUint32(x) (*(uint32_t *)(x)) #else -static uint32_t fstGetUint32(unsigned char *mem) +static inline uint32_t fstGetUint32(unsigned char *mem) { - uint32_t u32; - unsigned char *buf = (unsigned char *)(&u32); + union { + uint8_t u8[sizeof(uint32_t)]; + uint32_t u32; + } u; - buf[0] = mem[0]; - buf[1] = mem[1]; - buf[2] = mem[2]; - buf[3] = mem[3]; + for (size_t i=0; i < sizeof(u.u8); i++) + u.u8[i] = mem[i]; - return (*(uint32_t *)buf); + return u.u32; } #endif @@ -4334,7 +4334,7 @@ int fstReaderInit(struct fstReaderContext *xc) hdr_incomplete = (xc->start_time == 0) && (xc->end_time == 0); fstFread(&dcheck, 8, 1, xc->f); - xc->double_endian_match = (dcheck == FST_DOUBLE_ENDTEST); + xc->double_endian_match = (dcheck == (double)FST_DOUBLE_ENDTEST); if (!xc->double_endian_match) { union { diff --git a/passes/cmds/Makefile.inc b/passes/cmds/Makefile.inc index 29b3a1132ad..d7e572462b0 100644 --- a/passes/cmds/Makefile.inc +++ b/passes/cmds/Makefile.inc @@ -46,3 +46,5 @@ OBJS += passes/cmds/printattrs.o OBJS += passes/cmds/sta.o OBJS += passes/cmds/clean_zerowidth.o OBJS += passes/cmds/xprop.o +OBJS += passes/cmds/dft_tag.o +OBJS += passes/cmds/future.o diff --git a/passes/cmds/dft_tag.cc b/passes/cmds/dft_tag.cc new file mode 100644 index 00000000000..9fd356ef65d --- /dev/null +++ b/passes/cmds/dft_tag.cc @@ -0,0 +1,1015 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2022 Jannis Harder + * + * 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/celltypes.h" +#include "kernel/ff.h" +#include "kernel/modtools.h" +#include "kernel/sigtools.h" +#include "kernel/yosys.h" +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct DftTagOptions { + bool tag_public = false; + bool overwrite_only = false; +}; + +struct DftTagWorker { + Module *module; + DftTagOptions options; + ModWalker modwalker; + SigMap &sigmap; + FfInitVals initvals; + + struct tag_set { + int index = 0; + + tag_set(int index = 0) : index(index) {} + + bool operator<(const tag_set &other) const { return index < other.index; } + bool operator==(const tag_set &other) const { return index == other.index; } + + unsigned int hash() const { return hash_ops::hash(index); } + + bool empty() const { return index == 0; } + }; + + idict> tag_sets; + + pool tmp_tag_set; + dict, tag_set> tag_set_union_cache; + + dict tagged_signals; + + dict> tag_groups; + dict group_of_tag; + pool all_tags; + + pool pending_cells; + std::deque pending_cell_queue; + + dict, SigBit> tag_signals; + + // Uses SigSpec instead of SigBit so we can use coarse grained cells to combine the individual tags + dict, SigSpec> tag_group_signals; + + pool warned_cells; + + DftTagWorker(Module *module, DftTagOptions options) : + module(module), options(options), modwalker(module->design), sigmap(modwalker.sigmap) + { + modwalker.setup(module); + initvals.set(&modwalker.sigmap, module); + tag_sets(tmp_tag_set); + } + + void resolve_overwrites() + { + std::vector overwrite_cells; + std::vector original_cells; + + bool design_changed = false; + + for (auto cell : module->cells()) { + if (cell->type == ID($overwrite_tag)) + overwrite_cells.push_back(cell); + + if (cell->type == ID($original_tag)) + original_cells.push_back(cell); + } + + for (auto cell : overwrite_cells) { + log_debug("Applying $overwrite_tag %s for signal %s\n", log_id(cell->name), log_signal(cell->getPort(ID::A))); + SigSpec orig_signal = cell->getPort(ID::A); + SigSpec interposed_signal = divert_users(orig_signal); + auto *set_tag_cell = module->addSetTag(NEW_ID, cell->getParam(ID::TAG).decode_string(), orig_signal, cell->getPort(ID::SET), cell->getPort(ID::CLR), interposed_signal); + modwalker.add_cell(set_tag_cell); // Make sure the next $overwrite_tag sees the new connections + design_changed = true; + } + + for (auto cell : overwrite_cells) { + module->remove(cell); + } + for (auto cell : original_cells) { + cell->type = ID($get_tag); + } + + if (design_changed) + modwalker.setup(module); + } + + SigSpec divert_users(SigSpec signal) + { + SigSpec signal_mapped = sigmap(signal); + signal_mapped.sort_and_unify(); + if (GetSize(signal_mapped) < GetSize(signal)) + log_warning("Detected $overwrite_tag on signal %s which contains repeated bits, this can result in unexpected behavior.\n", log_signal(signal)); + SigSpec new_wire = module->addWire(NEW_ID, GetSize(signal)); + for (int i = 0; i < GetSize(new_wire); ++i) + divert_users(signal[i], new_wire[i]); + return new_wire; + } + + void divert_users(SigBit driver_bit, SigBit interposed_bit) + { + dict, SigSpec> updated_ports; + // TODO also check module outputs + auto found = modwalker.signal_consumers.find(driver_bit); + if (found == modwalker.signal_consumers.end()) + return; + for (auto &consumer : found->second) { + if (consumer.cell->type.in(ID($original_tag))) + continue; + if (sigmap(consumer.cell->getPort(consumer.port)[consumer.offset]) != driver_bit) + continue; + std::pair key = {consumer.cell, consumer.port}; + auto found_port = updated_ports.find(key); + if (found_port == updated_ports.end()) { + updated_ports.emplace(key, consumer.cell->getPort(consumer.port)); + } + updated_ports[key][consumer.offset] = interposed_bit; + } + for (auto &update : updated_ports) { + update.first.first->setPort(update.first.second, update.second); + modwalker.add_cell(update.first.first); // Make sure the next $overwrite_tag sees the new connections + } + } + + const pool &tag_pool(tag_set set) { return tag_sets[set.index]; } + + tag_set singleton(IdString tag) + { + tmp_tag_set.clear(); + tmp_tag_set.emplace(tag); + return tag_sets(tmp_tag_set); + } + + tag_set merge(tag_set a, tag_set b) + { + if (b < a) + std::swap(a, b); + if (a.empty() || a == b) + return b; + auto found = tag_set_union_cache.find(std::make_pair(a, b)); + if (found == tag_set_union_cache.end()) { + tmp_tag_set.clear(); + auto &a_tags = tag_pool(a); + auto &b_tags = tag_pool(b); + tmp_tag_set.insert(a_tags.begin(), a_tags.end()); + tmp_tag_set.insert(b_tags.begin(), b_tags.end()); + tag_set result = tag_sets(tmp_tag_set); + tag_set_union_cache.emplace(std::make_pair(a, b), result); + return result; + } + return found->second; + } + + tag_set tags(SigBit bit) + { + sigmap.apply(bit); + auto found = tagged_signals.find(bit); + if (found != tagged_signals.end()) + return found->second; + return tag_set(); + } + + tag_set tags(SigSpec sig) + { + tag_set result; + for (auto bit : sig) + result = merge(result, tags(bit)); + return result; + } + + tag_set tags(Cell *cell) + { + tag_set result; + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) + result = merge(result, tags(conn.second)); + } + return result; + } + + void add_tags(SigBit bit, tag_set new_tags) + { + sigmap.apply(bit); + auto &tags = tagged_signals[bit]; + tag_set merged_tags = merge(tags, new_tags); + if (merged_tags == tags) + return; + tags = merged_tags; + auto it = modwalker.signal_consumers.find(bit); + if (it == modwalker.signal_consumers.end()) + return; + for (auto &consumer : it->second) + if (pending_cells.insert(consumer.cell).second) + pending_cell_queue.push_back(consumer.cell); + } + + void add_tags(SigSpec sig, tag_set new_tags) + { + for (auto bit : sigmap(sig)) + add_tags(bit, new_tags); + } + + void add_tags(Cell *cell, tag_set new_tags) + { + for (auto &conn : cell->connections()) + if (cell->output(conn.first)) + add_tags(conn.second, new_tags); + } + + void forward_tags(SigSpec dst, SigSpec src) + { + log_assert(GetSize(dst) == GetSize(src)); + for (int i = 0; i < GetSize(dst); i++) + add_tags(dst[i], tags(src[i])); + } + + void propagate_tags() + { + for (auto cell : module->cells()) { + if (cell->type == ID($set_tag)) { + pending_cells.insert(cell); + pending_cell_queue.push_back(cell); + } + } + + while (!pending_cell_queue.empty()) { + Cell *cell = pending_cell_queue.front(); + pending_cell_queue.pop_front(); + pending_cells.erase(cell); + + propagate_tags(cell); + } + } + + SigBit tag_signal(IdString tag, SigBit bit) + { + sigmap.apply(bit); + if (!bit.is_wire()) + return State::S0; // Constant value - no tags + + auto found = tag_signals.find(std::make_pair(tag, bit)); + if (found != tag_signals.end()) + return found->second; + + if (!tag_pool(tags(bit)).count(tag)) + return State::S0; // Statically known to not have this tag + + // TODO handle module inputs + auto drivers = modwalker.signal_drivers.find(bit); + if (drivers == modwalker.signal_drivers.end() || drivers->second.empty()) + return State::S0; // No driver - no tags + + log_assert(drivers->second.size() == 1); + auto driver = *drivers->second.begin(); + + emit_tag_signals(tag, driver.cell); + + found = tag_signals.find(std::make_pair(tag, bit)); + log_assert(found != tag_signals.end()); + return found->second; + } + + SigSpec tag_signal(IdString tag, SigSpec sig) + { + SigSpec result; + for (auto bit : sig) + result.append(tag_signal(tag, bit)); + return result; + } + + SigSpec tag_group_signal(IdString tag_group, SigSpec sig) + { + sigmap.apply(sig); + if (sig.is_fully_const() || tag_groups.count(tag_group) == 0) + return Const(0, GetSize(sig)); + + auto found = tag_group_signals.find(std::make_pair(tag_group, sig)); + if (found != tag_group_signals.end()) + return found->second; + + SigSpec combined; + + for (auto &tag : tag_groups[tag_group]) { + auto tag_sig = tag_signal(tag, sig); + + if (!GetSize(combined)) + combined = tag_sig; + else + combined = autoOr(NEW_ID, combined, tag_sig); + } + + if (!GetSize(combined)) + combined = Const(0, GetSize(sig)); + + tag_group_signals.emplace(std::make_pair(tag_group, sig), combined); + return combined; + } + + void emit_tag_signal(IdString tag, SigBit bit, SigBit tag_bit) + { + sigmap.apply(bit); + sigmap.apply(tag_bit); + + if (!tag_pool(tags(bit)).count(tag)) + return; + + auto key = std::make_pair(tag, bit); + auto found = tag_signals.find(key); + if (found != tag_signals.end()) { + module->connect(found->second, tag_bit); + return; + } + tag_signals.emplace(key, tag_bit); + } + + void emit_tag_signal(IdString tag, SigSpec sig, SigSpec tag_sig) + { + log_assert(GetSize(sig) == GetSize(tag_sig)); + for (int i = 0; i < GetSize(sig); i++) + emit_tag_signal(tag, sig[i], tag_sig[i]); + } + + void emit_tag_signals(IdString tag, Cell *cell) + { + if (!pending_cells.insert(cell).second) { + // We have a cycle, emit placeholder wires which will be connected + // when the outer call for this tag/cell returns + for (auto &conn : cell->connections()) + if (cell->output(conn.first)) + emit_tag_signal(tag, conn.second, module->addWire(NEW_ID, GetSize(conn.second))); + + return; + } + + process_cell(tag, cell); + + pending_cells.erase(cell); + } + + void propagate_tags(Cell *cell) + { + if (cell->type == ID($set_tag)) { + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + if (all_tags.insert(tag).second) { + auto group_sep = tag.str().find(':'); + IdString tag_group = group_sep != std::string::npos ? tag.str().substr(0, group_sep) : tag; + tag_groups[tag_group].insert(tag); + group_of_tag[tag] = tag_group; + } + + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + // TODO handle constant set/clr masks + add_tags(sig_y, singleton(tag)); + forward_tags(sig_y, sig_a); + return; + } + + if (cell->type == ID($get_tag)) { + return; + } + + if (cell->type.in(ID($not), ID($pos))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + if (cell->type.in(ID($not), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + } + forward_tags(sig_y, sig_a); + return; + } + + if (cell->type.in(ID($and), ID($or), ID($xor), ID($xnor), ID($bweqx))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($and), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + forward_tags(sig_y, sig_a); + forward_tags(sig_y, sig_b); + return; + } + + if (cell->type.in(ID($mux), ID($bwmux))) { + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + auto &sig_b = cell->getPort(ID::B); + auto sig_s = cell->getPort(ID::S); + + if (cell->type == ID($mux)) + sig_s = SigSpec(sig_s[0], GetSize(sig_y)); + + forward_tags(sig_y, sig_a); + forward_tags(sig_y, sig_b); + forward_tags(sig_y, sig_s); + return; + } + + if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) { + FfData ff(&initvals, cell); + + if (ff.has_clk || ff.has_gclk) + forward_tags(ff.sig_q, ff.sig_d); + return; + } + + // Single output but, sensitive to all inputs + if (cell->type.in( + ID($le), ID($lt), ID($ge), ID($gt), + ID($reduce_and), ID($reduce_or), ID($reduce_xor), ID($reduce_xnor), + ID($reduce_bool), ID($logic_not), ID($logic_or), ID($logic_and), + ID($eq), ID($ne) + )) { + auto &sig_y = cell->getPort(ID::Y); + + add_tags(sig_y[0], tags(cell)); + return; + } + + + // Fallback, propagate tags from all inputs to all outputs + add_tags(cell, tags(cell)); + + if (cell->type.in( + ID($_AND_), ID($_OR_), ID($_NAND_), ID($_NOR_), ID($_ANDNOT_), ID($_ORNOT_), + ID($_XOR_), ID($_XNOR_), ID($_NOT_), ID($_BUF_), ID($_MUX_), + + ID($assert), ID($assume) + )) { + return; + } + + // This isn't a correctness concern (unless cell is a module generating + // tags), but we may end up generating a lot of extra logic when + // reaching this + if (!warned_cells.insert(cell).second) + return; + if (cell->type.isPublic()) + log_warning("Unhandled cell %s (%s) during tag propagation\n", log_id(cell), log_id(cell->type)); + else + log_debug("Unhandled cell %s (%s) during tag propagation\n", log_id(cell), log_id(cell->type)); + } + + void process_cell(IdString tag, Cell *cell) + { + if (cell->type == ID($set_tag)) { + IdString cell_tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + auto tag_sig_a = tag_signal(tag, cell->getPort(ID::A)); + auto &sig_y = cell->getPort(ID::Y); + + if (cell_tag == tag) { + auto &sig_set = cell->getPort(ID::SET); + auto &sig_clr = cell->getPort(ID::CLR); + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, autoNot(NEW_ID, sig_clr)); + tag_sig_a = autoOr(NEW_ID, tag_sig_a, sig_set); + } + + emit_tag_signal(tag, sig_y, tag_sig_a); + return; + } + + if (cell->type == ID($get_tag)) { + log_assert(false); + } + + if (cell->type.in(ID($not), ID($pos), ID($_NOT_), ID($_BUF_))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + if (cell->type.in(ID($not), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + } + emit_tag_signal(tag, sig_y, tag_signal(tag, sig_a)); + return; + } + + if (cell->type.in( + ID($and), ID($or), + ID($_AND_), ID($_OR_), ID($_NAND_), ID($_NOR_), ID($_ANDNOT_), ID($_ORNOT_) + )) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($and), ID($or))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + + bool inv_a = false; + bool inv_b = false; + + if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_), ID($_ORNOT_))) + inv_a ^= true, inv_b ^= true; + if (cell->type.in(ID($_ANDNOT_), ID($_ORNOT_))) + inv_b ^= true; + + if (inv_a) + sig_a = autoNot(NEW_ID, sig_a); + if (inv_b) + sig_b = autoNot(NEW_ID, sig_b); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + + // Does this input allow propagating (doesn't fix output or same tag group) + sig_a = autoOr(NEW_ID, sig_a, group_sig_a); + sig_b = autoOr(NEW_ID, sig_b, group_sig_b); + + // Mask input tags by whether the other side allows propagation + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, sig_b); + tag_sig_b = autoAnd(NEW_ID, tag_sig_b, sig_a); + + + auto tag_sig = autoOr(NEW_ID, tag_sig_a, tag_sig_b); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($xor), ID($xnor), ID($bweqx), ID($_XOR_), ID($_XNOR_))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + if (cell->type.in(ID($xor), ID($xnor))) { + sig_a.extend_u0(GetSize(sig_y), cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(GetSize(sig_y), cell->getParam(ID::B_SIGNED).as_bool()); + } + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto tag_sig = autoOr(NEW_ID, tag_sig_a, tag_sig_b); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + + if (cell->type.in(ID($_MUX_), ID($mux), ID($bwmux))) { + auto &sig_y = cell->getPort(ID::Y); + auto &sig_a = cell->getPort(ID::A); + auto &sig_b = cell->getPort(ID::B); + auto sig_s = cell->getPort(ID::S); + + if (cell->type == ID($mux)) + sig_s = SigSpec(sig_s[0], GetSize(sig_y)); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + auto group_sig_s = tag_group_signal(tag, sig_s); + + auto prop_s = autoOr(NEW_ID, + autoXor(NEW_ID, sig_a, sig_b), + autoOr(NEW_ID, group_sig_a, group_sig_b)); + + auto prop_a = autoOr(NEW_ID, autoNot(NEW_ID, sig_s), group_sig_s); + auto prop_b = autoOr(NEW_ID, sig_s, group_sig_s); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + auto tag_sig_s = tag_signal(tag, sig_s); + + tag_sig_a = autoAnd(NEW_ID, tag_sig_a, prop_a); + tag_sig_b = autoAnd(NEW_ID, tag_sig_b, prop_b); + tag_sig_s = autoAnd(NEW_ID, tag_sig_s, prop_s); + + auto tag_sig = autoOr(NEW_ID, tag_sig_s, + autoOr(NEW_ID, tag_sig_a, tag_sig_b)); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($eq), ID($ne), ID($eqx), ID($nex))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + int width = std::max(GetSize(sig_a), GetSize(sig_b)); + sig_a.extend_u0(width, cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(width, cell->getParam(ID::B_SIGNED).as_bool()); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto group_sig = autoOr(NEW_ID, group_sig_a, group_sig_b); + // The output can only be affected by the tagged inputs if all group-untagged bits are equal + + auto masked_a = autoOr(NEW_ID, sig_a, group_sig); + auto masked_b = autoOr(NEW_ID, sig_b, group_sig); + + auto prop = autoEq(NEW_ID, masked_a, masked_b); + + auto tag_sig = autoAnd(NEW_ID, prop, autoReduceOr(NEW_ID, {tag_sig_a, tag_sig_b})); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + + if (cell->type.in(ID($lt), ID($gt), ID($le), ID($ge))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + auto sig_b = cell->getPort(ID::B); + int width = std::max(GetSize(sig_a), GetSize(sig_b)); + sig_a.extend_u0(width, cell->getParam(ID::A_SIGNED).as_bool()); + sig_b.extend_u0(width, cell->getParam(ID::B_SIGNED).as_bool()); + + if (cell->type.in(ID($gt), ID($le))) + std::swap(sig_a, sig_b); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto group_sig_b = tag_group_signal(tag, sig_b); + + auto tag_sig_a = tag_signal(tag, sig_a); + auto tag_sig_b = tag_signal(tag, sig_b); + + auto group_sig = autoOr(NEW_ID, group_sig_a, group_sig_b); + // The output can only be affected by the tagged inputs if the greatest possible sig_a is + // greater or equal to the least possible sig_b + auto masked_a = autoOr(NEW_ID, sig_a, group_sig); + auto masked_b = autoAnd(NEW_ID, sig_b, autoNot(NEW_ID, group_sig)); + + auto prop = autoGe(NEW_ID, masked_a, masked_b); + + auto tag_sig = autoAnd(NEW_ID, prop, autoReduceOr(NEW_ID, {tag_sig_a, tag_sig_b})); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (cell->type.in(ID($reduce_and), ID($reduce_or), ID($reduce_bool), ID($logic_not))) { + auto &sig_y = cell->getPort(ID::Y); + auto sig_a = cell->getPort(ID::A); + + if (cell->type.in(ID($reduce_or), ID($reduce_bool), ID($logic_not))) + sig_a = autoNot(NEW_ID, sig_a); + + auto group_sig_a = tag_group_signal(tag, sig_a); + auto tag_sig_a = tag_signal(tag, sig_a); + + auto filled = autoOr(NEW_ID, sig_a, group_sig_a); + + auto prop = autoReduceAnd(NEW_ID, filled); + auto tagged = autoReduceOr(NEW_ID, tag_sig_a); + auto tag_sig = autoAnd(NEW_ID, prop, tagged); + tag_sig.extend_u0(GetSize(sig_y), false); + emit_tag_signal(tag, sig_y, tag_sig); + return; + } + + if (RTLIL::builtin_ff_cell_types().count(cell->type) || cell->type == ID($anyinit)) { + FfData ff(&initvals, cell); + // TODO handle some more variants + if ((ff.has_clk || ff.has_gclk) && !ff.has_ce && !ff.has_aload && !ff.has_srst && !ff.has_arst && !ff.has_sr) { + if (ff.has_clk && !tags(ff.sig_clk).empty()) + log_warning("Tags on CLK input ignored for %s (%s)\n", log_id(cell), log_id(cell->type)); + + int width = ff.width; + + auto sig_q = ff.sig_q; + auto sig_d = ff.sig_d; + + ff.name = NEW_ID; + ff.cell = nullptr; + ff.sig_d = tag_signal(tag, ff.sig_d); + ff.sig_q = module->addWire(NEW_ID, width); + ff.is_anyinit = false; + ff.val_init = Const(0, width); + ff.emit(); + + emit_tag_signal(tag, sig_q, ff.sig_q); + return; + } else { + log_warning("Unhandled FF-cell %s (%s), consider running clk2fflogic, async2sync and/or dffunmap\n", log_id(cell), log_id(cell->type)); + + // For unhandled FFs, the default propagation would cause combinational loops + emit_tag_signal(tag, ff.sig_q, Const(0, ff.width)); + return; + } + } + + // Fallback + SigSpec tag_input; + + for (auto &conn : cell->connections()) { + if (cell->input(conn.first)) { + auto tag_sig = tag_signal(tag, conn.second); + tag_input.append(tag_sig); + } + } + + SigBit any_tagged = autoReduceOr(NEW_ID, tag_input); + + for (auto &conn : cell->connections()) { + if (cell->output(conn.first)) { + emit_tag_signal(tag, conn.second, SigSpec(any_tagged, GetSize(conn.second))); + } + } + + // As fallback we propagate all tags from all inputs to all outputs, + // which is an over-approximation (unless the cell is a module that + // generates tags itself in which case it could be arbitrary). + if (warned_cells.insert(cell).second) + log_warning("Unhandled cell %s (%s) while emitting tag signals\n", log_id(cell), log_id(cell->type)); + } + + void emit_tags() + { + warned_cells.clear(); + std::vector get_tag_cells; + for (auto cell : module->selected_cells()) + if (cell->type == ID($get_tag)) + get_tag_cells.push_back(cell); + + for (auto cell : get_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + tag_signal(tag, sig_a); + } + + if (options.tag_public) + { + std::vector public_wires; + + for (auto wire : module->selected_wires()) + if (wire->name.isPublic()) + public_wires.push_back(wire); + + for (auto wire : public_wires) { + for (auto tag : tag_pool(tags(SigSpec(wire)))) { + auto tag_sig = tag_signal(tag, SigSpec(wire)); + if (tag_sig.is_fully_zero()) + continue; + + int index = 0; + auto name = module->uniquify(stringf("%s:%s", wire->name.c_str(), tag.c_str() + 1), index); + auto hdlname = wire->get_hdlname_attribute(); + + if (!hdlname.empty()) + hdlname.back() += index ? + stringf(":%s_%d", tag.c_str() + 1, index) : + stringf(":%s", tag.c_str() + 1); + + auto tag_wire = module->addWire(name, wire->width); + + tag_wire->set_bool_attribute(ID::keep); + tag_wire->set_bool_attribute(ID(dft_tag)); + if (!hdlname.empty()) + tag_wire->set_hdlname_attribute(hdlname); + + module->connect(tag_wire, tag_sig); + } + } + } + } + + void replace_dft_cells() + { + std::vector get_tag_cells; + std::vector set_tag_cells; + for (auto cell : module->cells()) { + if (cell->type == ID($get_tag)) + get_tag_cells.push_back(cell); + + if (cell->type == ID($set_tag)) + set_tag_cells.push_back(cell); + + log_assert(!cell->type.in(ID($overwrite_tag), ID($original_tag))); + } + + for (auto cell : set_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + auto &sig_y = cell->getPort(ID::Y); + module->connect(sig_y, sig_a); + module->remove(cell); + } + + for (auto cell : get_tag_cells) { + auto &sig_a = cell->getPort(ID::A); + auto &sig_y = cell->getPort(ID::Y); + IdString tag = stringf("\\%s", cell->getParam(ID::TAG).decode_string().c_str()); + + auto tag_sig = tag_signal(tag, sig_a); + module->connect(sig_y, tag_sig); + module->remove(cell); + } + } + + + SigSpec autoAnd(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a.is_fully_zero() || sig_b.is_fully_ones() || sig_a == sig_b) + return sig_a; + if (sig_a.is_fully_ones() || sig_b.is_fully_zero()) + return sig_b; + + return module->And(name, sig_a, sig_b); + } + + SigSpec autoOr(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a.is_fully_ones() || sig_b.is_fully_zero() || sig_a == sig_b) + return sig_a; + if (sig_a.is_fully_zero() || sig_b.is_fully_ones()) + return sig_b; + + return module->Or(name, sig_a, sig_b); + } + + SigSpec autoXor(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return Const(State::S0, GetSize(sig_a)); + if (sig_a.is_fully_zero()) + return sig_b; + if (sig_b.is_fully_zero()) + return sig_a; + if (sig_a.is_fully_ones()) + return autoNot(name, sig_b); + if (sig_b.is_fully_ones()) + return autoNot(name, sig_a); + return module->Xor(name, sig_a, sig_b); + } + + SigSpec autoXnor(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return Const(State::S1, GetSize(sig_a)); + if (sig_a.is_fully_ones()) + return sig_b; + if (sig_b.is_fully_ones()) + return sig_a; + if (sig_a.is_fully_zero()) + return autoNot(name, sig_b); + if (sig_b.is_fully_zero()) + return autoNot(name, sig_a); + return module->Xnor(name, sig_a, sig_b); + } + + SigSpec autoNot(IdString name, const SigSpec &sig_a) + { + if (sig_a.is_fully_const()) { + auto const_val = sig_a.as_const(); + for (auto &bit : const_val.bits) + bit = bit == State::S0 ? State::S1 : bit == State::S1 ? State::S0 : bit; + return const_val; + } + return module->Not(name, sig_a); + } + + SigSpec autoEq(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b) + return State::S1; + for (int i = 0; i < GetSize(sig_a); i++) { + auto bit_a = sig_a[i]; + auto bit_b = sig_b[i]; + if (bit_a.is_wire() || bit_b.is_wire()) + continue; + if ((bit_a.data == State::S0 && bit_b.data == State::S1) || + (bit_a.data == State::S1 && bit_b.data == State::S0)) + return State::S0; + } + + return module->Eq(name, sig_a, sig_b); + } + + SigSpec autoGe(IdString name, const SigSpec &sig_a, const SigSpec &sig_b) + { + log_assert(GetSize(sig_a) == GetSize(sig_b)); + if (sig_a == sig_b || sig_a.is_fully_ones()) + return State::S1; + if (sig_b.is_fully_zero()) + return State::S1; + + return module->Ge(name, sig_a, sig_b); + } + + SigSpec autoReduceAnd(IdString name, const SigSpec &sig_a) + { + if (GetSize(sig_a) == 0) + return State::S1; + + if (GetSize(sig_a) == 1 || sig_a == SigSpec(sig_a[0], GetSize(sig_a))) + return sig_a[0]; + for (auto bit : sig_a) + if (!bit.is_wire() && bit.data == State::S0) + return State::S0; + if (sig_a.is_fully_ones()) + return State::S1; + return module->ReduceAnd(name, sig_a); + } + + SigSpec autoReduceOr(IdString name, const SigSpec &sig_a) + { + if (GetSize(sig_a) == 0) + return State::S0; + + if (GetSize(sig_a) == 1 || sig_a == SigSpec(sig_a[0], GetSize(sig_a))) + return sig_a[0]; + for (auto bit : sig_a) + if (!bit.is_wire() && bit.data == State::S1) + return State::S1; + if (sig_a.is_fully_zero()) + return State::S0; + return module->ReduceOr(name, sig_a); + } +}; + +struct DftTagPass : public Pass { + DftTagPass() : Pass("dft_tag", "create tagging logic for data flow tracking") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" dft_tag [options] [selection]\n"); + log("\n"); + log("This pass... TODO\n"); + log("\n"); + log(" -overwrite-only\n"); + log(" Only process $overwrite_tag and $original_tag cells.\n"); + log(" -tag-public\n"); + log(" For each public wire that may carry tagged data, create a new public\n"); + log(" wire (named :) that carries the tag bits. Note\n"); + log(" that without this, tagging logic will only be emitted as required\n"); + log(" for uses of $get_tag.\n"); + log("\n"); + } + + void execute(std::vector args, RTLIL::Design *design) override + { + DftTagOptions options; + + log_header(design, "Executing DFT_TAG pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-tag-public") { + options.tag_public = true; + continue; + } + if (args[argidx] == "-overwrite-only") { + options.overwrite_only = true; + continue; + } + break; + } + + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + DftTagWorker worker(module, options); + + log_debug("Resolve overwrite_tag and original_tag.\n"); + worker.resolve_overwrites(); + + if (options.overwrite_only) + continue; + + log_debug("Propagate tagged signals.\n"); + worker.propagate_tags(); + + log_debug("Emit tag signals and logic.\n"); + worker.emit_tags(); + + log_debug("Replace dft cells.\n"); + worker.replace_dft_cells(); + } + } +} DftTagPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/future.cc b/passes/cmds/future.cc new file mode 100644 index 00000000000..b03613c9bd2 --- /dev/null +++ b/passes/cmds/future.cc @@ -0,0 +1,140 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2023 Jannis Harder + * + * 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/celltypes.h" +#include "kernel/ff.h" +#include "kernel/ffinit.h" +#include "kernel/modtools.h" +#include "kernel/sigtools.h" +#include "kernel/utils.h" +#include "kernel/yosys.h" +#include + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct FutureOptions { +}; + +struct FutureWorker { + Module *module; + FutureOptions options; + ModWalker modwalker; + SigMap &sigmap; + FfInitVals initvals; + + dict future_ff_signals; + + FutureWorker(Module *module, FutureOptions options) : + module(module), options(options), modwalker(module->design), sigmap(modwalker.sigmap) + { + modwalker.setup(module); + initvals.set(&modwalker.sigmap, module); + + std::vector replaced_cells; + for (auto cell : module->selected_cells()) { + if (cell->type != ID($future_ff)) + continue; + + module->connect(cell->getPort(ID::Y), future_ff(cell->getPort(ID::A))); + replaced_cells.push_back(cell); + } + + for (auto cell : replaced_cells) { + module->remove(cell); + } + } + + SigSpec future_ff(SigSpec sig) + { + for (auto &bit : sig) { + bit = future_ff(bit); + } + return sig; + } + + SigBit future_ff(SigBit bit) + { + if (!bit.is_wire()) + return bit; + + auto found = future_ff_signals.find(bit); + if (found != future_ff_signals.end()) + return found->second; + + auto found_driver = modwalker.signal_drivers.find(bit); + if (found_driver == modwalker.signal_drivers.end() || found_driver->second.size() < 1) + log_error("No driver for future_ff target signal %s found\n", log_signal(bit)); + if (found_driver->second.size() > 1) + log_error("Found multiple drivers for future_ff target signal %s\n", log_signal(bit)); + auto driver = *found_driver->second.begin(); + if (!RTLIL::builtin_ff_cell_types().count(driver.cell->type) && driver.cell->type != ID($anyinit)) + log_error("Driver for future_ff target signal %s has non-FF cell type %s\n", log_signal(bit), log_id(driver.cell->type)); + + FfData ff(&initvals, driver.cell); + + if (!ff.has_clk && !ff.has_gclk) + log_error("Driver for future_ff target signal %s has cell type %s, which is not clocked\n", log_signal(bit), + log_id(driver.cell->type)); + + ff.unmap_ce_srst(); + + // We insert all bits into the mapping, because unmap_ce_srst might + // have removed the cell which is still present in the modwalker data. + // By inserting all bits driven by th FF we ensure that we'll never use + // that stale modwalker data again. + + for (int i = 0; i < ff.width; ++i) { + future_ff_signals.emplace(ff.sig_q[i], ff.sig_d[i]); + } + + return future_ff_signals.at(bit); + } +}; + +struct FuturePass : public Pass { + FuturePass() : Pass("future", "resolve future sampled value functions") {} + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" future [options] [selection]\n"); + log("\n"); + } + void execute(std::vector args, RTLIL::Design *design) override + { + FutureOptions options; + + log_header(design, "Executing FUTURE pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + + break; + } + + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) { + FutureWorker worker(module, options); + } + } +} FuturePass; + +PRIVATE_NAMESPACE_END diff --git a/passes/cmds/xprop.cc b/passes/cmds/xprop.cc index 5e78ff9fce4..310d6d773d5 100644 --- a/passes/cmds/xprop.cc +++ b/passes/cmds/xprop.cc @@ -493,8 +493,9 @@ struct XpropWorker auto sig_b = cell->getPort(ID::B); auto name = cell->name; + auto type = cell->type; module->remove(cell); - if (cell->type == ID($eqx)) + if (type == ID($eqx)) module->addEq(name, sig_a, sig_b, sig_y); else module->addNe(name, sig_a, sig_b, sig_y); @@ -534,7 +535,7 @@ struct XpropWorker auto enc_b = encoded(sig_b); auto enc_y = encoded(sig_y, true); - if (cell->type.in(ID($or), ID($_OR_))) + if (cell->type.in(ID($or), ID($_OR_), ID($_NOR_), ID($_ORNOT_))) enc_a.invert(), enc_b.invert(), enc_y.invert(); if (cell->type.in(ID($_NAND_), ID($_NOR_))) enc_y.invert(); @@ -1027,12 +1028,25 @@ struct XpropWorker for (auto wire : module->selected_wires()) { if (wire->port_input || wire->port_output || !wire->name.isPublic()) continue; - auto name_d = module->uniquify(stringf("%s_d", wire->name.c_str())); - auto name_x = module->uniquify(stringf("%s_x", wire->name.c_str())); + int index_d = 0; + int index_x = 0; + auto name_d = module->uniquify(stringf("%s_d", wire->name.c_str()), index_d); + auto name_x = module->uniquify(stringf("%s_x", wire->name.c_str()), index_x); + + auto hdlname = wire->get_hdlname_attribute(); auto wire_d = module->addWire(name_d, GetSize(wire)); auto wire_x = module->addWire(name_x, GetSize(wire)); + if (!hdlname.empty()) { + auto hdlname_d = hdlname; + auto hdlname_x = hdlname; + hdlname_d.back() += index_d ? stringf("_d_%d", index_d) : "_d"; + hdlname_x.back() += index_x ? stringf("_x_%d", index_x) : "_x"; + wire_d->set_hdlname_attribute(hdlname_d); + wire_x->set_hdlname_attribute(hdlname_x); + } + auto enc = encoded(wire); module->connect(wire_d, enc.is_1); module->connect(wire_x, enc.is_x); diff --git a/passes/memory/memlib.md b/passes/memory/memlib.md index fdc2d4bed27..855aa1345fb 100644 --- a/passes/memory/memlib.md +++ b/passes/memory/memlib.md @@ -267,7 +267,7 @@ The address is always `abits` wide. If a non-narrowest width is used, the appro bits will be tied to 0. -### Port `width` prooperty +### Port `width` property 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: diff --git a/passes/memory/memory_libmap.cc b/passes/memory/memory_libmap.cc index 6e5a806fd0e..f8b0eec1d8d 100644 --- a/passes/memory/memory_libmap.cc +++ b/passes/memory/memory_libmap.cc @@ -667,7 +667,7 @@ void MemMapping::assign_wr_ports() { if (used >= GetSize(pg.names)) { log_reject(*cfg.def, pg, "not enough unassigned ports remaining"); continue; - } + } for (int pvi = 0; pvi < GetSize(pg.variants); pvi++) { auto &def = pg.variants[pvi]; // Make sure the target is a write port. @@ -2114,7 +2114,7 @@ struct MemoryLibMapPass : public Pass { log(" memory_libmap -lib [-D ] [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("all selected memories to one of them, or leaves them to be mapped to FFs.\n"); log("\n"); log(" -lib \n"); log(" Selects a library file containing RAM cell definitions. This option\n"); diff --git a/passes/opt/opt_clean.cc b/passes/opt/opt_clean.cc index cb2490dc72e..a219e470813 100644 --- a/passes/opt/opt_clean.cc +++ b/passes/opt/opt_clean.cc @@ -76,9 +76,15 @@ struct keep_cache_t if (cell->type.in(ID($assert), ID($assume), ID($live), ID($fair), ID($cover))) return true; + if (cell->type.in(ID($overwrite_tag))) + return true; + if (!ignore_specify && cell->type.in(ID($specify2), ID($specify3), ID($specrule))) return true; + if (cell->type == ID($print)) + return true; + if (cell->has_keep_attr()) return true; diff --git a/passes/opt/opt_lut_ins.cc b/passes/opt/opt_lut_ins.cc index 2f7c392b29a..652fce1e2d5 100644 --- a/passes/opt/opt_lut_ins.cc +++ b/passes/opt/opt_lut_ins.cc @@ -39,7 +39,7 @@ struct OptLutInsPass : public Pass { log("\n"); log(" -tech \n"); log(" Instead of generic $lut cells, operate on LUT cells specific\n"); - log(" to the given technology. Valid values are: xilinx, ecp5, gowin.\n"); + log(" to the given technology. Valid values are: xilinx, lattice, gowin.\n"); log("\n"); } void execute(std::vector args, RTLIL::Design *design) override @@ -58,7 +58,7 @@ struct OptLutInsPass : public Pass { } extra_args(args, argidx, design); - if (techname != "" && techname != "xilinx" && techname != "ecp5" && techname != "gowin") + if (techname != "" && techname != "xilinx" && techname != "lattice" && techname != "ecp5" && techname != "gowin") log_cmd_error("Unsupported technology: '%s'\n", techname.c_str()); for (auto module : design->selected_modules()) @@ -130,7 +130,7 @@ struct OptLutInsPass : public Pass { output = cell->getPort(ID::O); else output = cell->getPort(ID::F); - } else if (techname == "ecp5") { + } else if (techname == "lattice" || techname == "ecp5") { if (cell->type == ID(LUT4)) { inputs = { cell->getPort(ID::A), @@ -181,7 +181,7 @@ struct OptLutInsPass : public Pass { if (!doit) continue; log(" Optimizing lut %s (%d -> %d)\n", log_id(cell), GetSize(inputs), GetSize(new_inputs)); - if (techname == "ecp5") { + if (techname == "lattice" || techname == "ecp5") { // Pad the LUT to 4 inputs, adding consts from the front. int extra = 4 - GetSize(new_inputs); log_assert(extra >= 0); @@ -215,9 +215,9 @@ struct OptLutInsPass : public Pass { } new_lut[i] = lut[lidx]; } - // For ecp5, and gowin do not replace with a const driver — the nextpnr + // For lattice, and gowin do not replace with a const driver — the nextpnr // packer requires a complete set of LUTs for wide LUT muxes. - if (new_inputs.empty() && techname != "ecp5" && techname != "gowin") { + if (new_inputs.empty() && techname != "lattice" && techname != "ecp5" && techname != "gowin") { // const driver. remove_cells.push_back(cell); module->connect(output, new_lut[0]); @@ -226,7 +226,7 @@ struct OptLutInsPass : public Pass { cell->setParam(ID::LUT, new_lut); cell->setParam(ID::WIDTH, GetSize(new_inputs)); cell->setPort(ID::A, new_inputs); - } else if (techname == "ecp5") { + } else if (techname == "lattice" || techname == "ecp5") { log_assert(GetSize(new_inputs) == 4); cell->setParam(ID::INIT, new_lut); cell->setPort(ID::A, new_inputs[0]); diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 8fd4c788c92..87a5cb56d86 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -364,10 +364,16 @@ struct WreduceWorker if (cell->type == ID($mul)) max_y_size = a_size + b_size; - while (GetSize(sig) > 1 && GetSize(sig) > max_y_size) { - module->connect(sig[GetSize(sig)-1], is_signed ? sig[GetSize(sig)-2] : State::S0); - sig.remove(GetSize(sig)-1); - bits_removed++; + max_y_size = std::max(max_y_size, 1); + + if (GetSize(sig) > max_y_size) { + SigSpec extra_bits = sig.extract(max_y_size, GetSize(sig) - max_y_size); + + bits_removed += GetSize(extra_bits); + sig.remove(max_y_size, GetSize(extra_bits)); + + SigBit padbit = is_signed ? sig[GetSize(sig)-1] : State::S0; + module->connect(extra_bits, SigSpec(padbit, GetSize(extra_bits))); } } diff --git a/passes/proc/proc_clean.cc b/passes/proc/proc_clean.cc index 45872907bd8..95cb0e88ca9 100644 --- a/passes/proc/proc_clean.cc +++ b/passes/proc/proc_clean.cc @@ -31,7 +31,7 @@ PRIVATE_NAMESPACE_BEGIN void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did_something, int &count, int max_depth) { - if (sw->signal.size() > 0 && sw->signal.is_fully_const()) + if (sw->signal.size() > 0 && sw->signal.is_fully_def()) { int found_matching_case_idx = -1; for (int i = 0; i < int(sw->cases.size()) && found_matching_case_idx < 0; i++) @@ -41,7 +41,7 @@ void proc_clean_switch(RTLIL::SwitchRule *sw, RTLIL::CaseRule *parent, bool &did break; for (int j = 0; j < int(cs->compare.size()); j++) { RTLIL::SigSpec &val = cs->compare[j]; - if (!val.is_fully_const()) + if (!val.is_fully_def()) continue; if (val == sw->signal) { cs->compare.clear(); diff --git a/passes/sat/sim.cc b/passes/sat/sim.cc index 325e123201c..1e6645303b5 100644 --- a/passes/sat/sim.cc +++ b/passes/sat/sim.cc @@ -25,6 +25,7 @@ #include "kernel/ff.h" #include "kernel/yw.h" #include "kernel/json.h" +#include "kernel/fmt.h" #include @@ -109,6 +110,7 @@ struct SimShared int next_output_id = 0; int step = 0; std::vector triggered_assertions; + bool serious_asserts = false; }; void zinit(State &v) @@ -168,11 +170,38 @@ struct SimInstance Const data; }; + struct print_state_t + { + Const past_trg; + Const past_en; + Const past_args; + + Cell *cell; + Fmt fmt; + + std::tuple _sort_label() const + { + return std::make_tuple( + cell->getParam(ID::TRG_ENABLE).as_bool(), // Group by trigger + cell->getPort(ID::TRG), + cell->getParam(ID::TRG_POLARITY), + -cell->getParam(ID::PRIORITY).as_int(), // Then sort by descending PRIORITY + cell + ); + } + + bool operator<(const print_state_t &other) const + { + return _sort_label() < other._sort_label(); + } + }; + dict ff_database; dict mem_database; pool formal_database; pool initstate_database; dict mem_cells; + std::vector print_database; std::vector memories; @@ -289,13 +318,26 @@ struct SimInstance if (shared->fst) fst_memories[name] = shared->fst->getMemoryHandles(scope + "." + RTLIL::unescape_id(name)); } - if (cell->type.in(ID($assert), ID($cover), ID($assume))) { + + if (cell->type.in(ID($assert), ID($cover), ID($assume))) formal_database.insert(cell); - } + if (cell->type == ID($initstate)) initstate_database.insert(cell); + + if (cell->type == ID($print)) { + print_database.emplace_back(); + auto &print = print_database.back(); + print.cell = cell; + print.fmt.parse_rtlil(cell); + print.past_trg = Const(State::Sx, cell->getPort(ID::TRG).size()); + print.past_args = Const(State::Sx, cell->getPort(ID::ARGS).size()); + print.past_en = State::Sx; + } } + std::sort(print_database.begin(), print_database.end()); + if (shared->zinit) { for (auto &it : ff_database) @@ -519,6 +561,9 @@ struct SimInstance return; } + if (cell->type == ID($print)) + return; + log_error("Unsupported cell type: %s (%s.%s)\n", log_id(cell->type), log_id(module), log_id(cell)); } @@ -760,6 +805,50 @@ struct SimInstance } } + // Do prints *before* assertions + for (auto &print : print_database) { + Cell *cell = print.cell; + bool triggered = false; + + Const trg = get_state(cell->getPort(ID::TRG)); + Const en = get_state(cell->getPort(ID::EN)); + Const args = get_state(cell->getPort(ID::ARGS)); + + if (!en.as_bool()) + goto update_print; + + if (cell->getParam(ID::TRG_ENABLE).as_bool()) { + Const trg_pol = cell->getParam(ID::TRG_POLARITY); + for (int i = 0; i < trg.size(); i++) { + bool pol = trg_pol[i] == State::S1; + State curr = trg[i], past = print.past_trg[i]; + if (pol && curr == State::S1 && past == State::S0) + triggered = true; + if (!pol && curr == State::S0 && past == State::S1) + triggered = true; + } + } else { + if (args != print.past_args || en != print.past_en) + triggered = true; + } + + if (triggered) { + int pos = 0; + for (auto &part : print.fmt.parts) { + part.sig = args.extract(pos, part.sig.size()); + pos += part.sig.size(); + } + + std::string rendered = print.fmt.render(); + log("%s", rendered.c_str()); + } + + update_print: + print.past_trg = trg; + print.past_en = en; + print.past_args = args; + } + if (check_assertions) { for (auto cell : formal_database) @@ -781,8 +870,12 @@ struct SimInstance if (cell->type == ID($assume) && en == State::S1 && a != State::S1) log("Assumption %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); - if (cell->type == ID($assert) && en == State::S1 && a != State::S1) - log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + if (cell->type == ID($assert) && en == State::S1 && a != State::S1) { + if (shared->serious_asserts) + log_error("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + else + log_warning("Assert %s.%s (%s) failed.\n", hiername().c_str(), log_id(cell), label.c_str()); + } } } @@ -2497,6 +2590,10 @@ struct SimPass : public Pass { log(" -sim-gate\n"); log(" co-simulation, x in FST can match any value in simulation\n"); log("\n"); + log(" -assert\n"); + log(" fail the simulation command if, in the course of simulating,\n"); + log(" any of the asserts in the design fail\n"); + log("\n"); log(" -q\n"); log(" disable per-cycle/sample log message\n"); log("\n"); @@ -2651,6 +2748,10 @@ struct SimPass : public Pass { worker.sim_mode = SimulationMode::gate; continue; } + if (args[argidx] == "-assert") { + worker.serious_asserts = true; + continue; + } if (args[argidx] == "-x") { worker.ignore_x = true; continue; diff --git a/passes/techmap/Makefile.inc b/passes/techmap/Makefile.inc index 1b834fabc3b..97d8b76f3b8 100644 --- a/passes/techmap/Makefile.inc +++ b/passes/techmap/Makefile.inc @@ -4,6 +4,7 @@ OBJS += passes/techmap/techmap.o OBJS += passes/techmap/simplemap.o OBJS += passes/techmap/dfflibmap.o OBJS += passes/techmap/maccmap.o +OBJS += passes/techmap/booth.o OBJS += passes/techmap/libparse.o ifeq ($(ENABLE_ABC),1) diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc index 364a8e54458..42287966288 100644 --- a/passes/techmap/abc.cc +++ b/passes/techmap/abc.cc @@ -127,10 +127,15 @@ bool clk_polarity, en_polarity, arst_polarity, srst_polarity; RTLIL::SigSpec clk_sig, en_sig, arst_sig, srst_sig; dict pi_map, po_map; +int undef_bits_lost; + int map_signal(RTLIL::SigBit bit, gate_type_t gate_type = G(NONE), int in1 = -1, int in2 = -1, int in3 = -1, int in4 = -1) { assign_map.apply(bit); + if (bit == State::Sx) + undef_bits_lost++; + if (signal_map.count(bit) == 0) { gate_t gate; gate.id = signal_list.size(); @@ -702,7 +707,7 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin std::vector &liberty_files, std::vector &genlib_files, std::string constr_file, bool cleanup, vector lut_costs, bool dff_mode, std::string clk_str, bool keepff, std::string delay_target, std::string sop_inputs, std::string sop_products, std::string lutin_shared, bool fast_mode, - const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress) + const std::vector &cells, bool show_tempdir, bool sop_mode, bool abc_dress, std::vector &dont_use_cells) { module = current_module; map_autoidx = autoidx++; @@ -795,8 +800,13 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin std::string abc_script = stringf("read_blif \"%s/input.blif\"; ", tempdir_name.c_str()); if (!liberty_files.empty() || !genlib_files.empty()) { - for (std::string liberty_file : liberty_files) - abc_script += stringf("read_lib -w \"%s\"; ", liberty_file.c_str()); + std::string dont_use_args; + for (std::string dont_use_cell : dont_use_cells) { + dont_use_args += stringf("-X \"%s\" ", dont_use_cell.c_str()); + } + for (std::string liberty_file : liberty_files) { + abc_script += stringf("read_lib %s -w \"%s\" ; ", dont_use_args.c_str(), liberty_file.c_str()); + } for (std::string liberty_file : genlib_files) abc_script += stringf("read_library \"%s\"; ", liberty_file.c_str()); if (!constr_file.empty()) @@ -880,10 +890,15 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin } } + undef_bits_lost = 0; + had_init = false; for (auto c : cells) extract_cell(c, keepff); + if (undef_bits_lost) + log("Replacing %d occurrences of constant undef bits with constant zero bits\n", undef_bits_lost); + for (auto wire : module->wires()) { if (wire->port_id > 0 || wire->get_bool_attribute(ID::keep)) mark_port(wire); @@ -1503,6 +1518,10 @@ struct AbcPass : public Pass { log(" generate netlists for the specified cell library (using the liberty\n"); log(" file format).\n"); log("\n"); + log(" -dont_use \n"); + log(" generate netlists for the specified cell library (using the liberty\n"); + log(" file format).\n"); + log("\n"); log(" -genlib \n"); log(" generate netlists for the specified cell library (using the SIS Genlib\n"); log(" file format).\n"); @@ -1639,7 +1658,7 @@ struct AbcPass : public Pass { std::string exe_file = yosys_abc_executable; std::string script_file, default_liberty_file, constr_file, clk_str; - std::vector liberty_files, genlib_files; + std::vector liberty_files, genlib_files, dont_use_cells; std::string delay_target, sop_inputs, sop_products, lutin_shared = "-S 1"; bool fast_mode = false, dff_mode = false, keepff = false, cleanup = true; bool show_tempdir = false, sop_mode = false; @@ -1722,6 +1741,10 @@ struct AbcPass : public Pass { liberty_files.push_back(args[++argidx]); continue; } + if (arg == "-dont_use" && argidx+1 < args.size()) { + dont_use_cells.push_back(args[++argidx]); + continue; + } if (arg == "-genlib" && argidx+1 < args.size()) { genlib_files.push_back(args[++argidx]); continue; @@ -2028,7 +2051,7 @@ struct AbcPass : public Pass { if (!dff_mode || !clk_str.empty()) { abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, dff_mode, clk_str, keepff, - delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress); + delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, mod->selected_cells(), show_tempdir, sop_mode, abc_dress, dont_use_cells); continue; } @@ -2190,7 +2213,7 @@ struct AbcPass : public Pass { srst_polarity = std::get<6>(it.first); srst_sig = assign_map(std::get<7>(it.first)); abc_module(design, mod, script_file, exe_file, liberty_files, genlib_files, constr_file, cleanup, lut_costs, !clk_sig.empty(), "$", - keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress); + keepff, delay_target, sop_inputs, sop_products, lutin_shared, fast_mode, it.second, show_tempdir, sop_mode, abc_dress, dont_use_cells); assign_map.set(mod); } } diff --git a/passes/techmap/booth.cc b/passes/techmap/booth.cc new file mode 100644 index 00000000000..e749168522d --- /dev/null +++ b/passes/techmap/booth.cc @@ -0,0 +1,1524 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2023 Andy Fox https://www.linkedin.com/in/awfox/ + * + * 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. + * + */ + +/* + Booth Pass + ---------- + + Replace $mul with booth encoded multipliers. Two different + architectures used for signed/unsigned. + + References: + Signed architecture: A Low Power Radix-4 Booth Multipliers with Pre-Encoded Mechanism, IEEE Access + https://ieeexplore.ieee.org/document/9121226 + + Unsigned architecture: Gary Bewick, Fast Multiplication algorithms and implementation. Stanford PhD: + http://i.stanford.edu/pub/cstr/reports/csl/tr/94/617/CSL-TR-94-617.pdf + + How to use: + Add booth pass to your yosys script eg: + + read_verilog smultiply5_rtl.v + opt + wreduce + opt + booth + alumacc + maccmap + opt + techmap -map ./techmap.v + dfflibmap -liberty NangateOpenCellLibrary_typical.lib + abc -liberty NangateOpenCellLibrary_typical.lib + stat -liberty NangateOpenCellLibrary_typical.lib + write_verilog -norename booth_final.v + +or in generic synthesis call with -booth argument: +synth -top my_design -booth +*/ + +#include "kernel/sigtools.h" +#include "kernel/yosys.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct BoothPassWorker { + + RTLIL::Module *module; + SigMap sigmap; + int booth_counter; + + BoothPassWorker(RTLIL::Module *module) : module(module), sigmap(module) { booth_counter = 0; } + + // Helper routines for building architecture subcomponents + + RTLIL::Wire *mk_wireFromSigSpec(const SigSpec &v) + { + + auto g = module->addCell(NEW_ID, ID($pos)); + Wire *ret = module->addWire(NEW_ID, 1); + g->setPort(ID::A, v); + g->setPort(ID::Y, ret); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + g->setParam(ID::A_SIGNED, false); + return ret; + } + + // fuse wires. + void join_wires_with_buffer(RTLIL::Wire *ip, RTLIL::Wire *op) + { + std::string wire_name = "join_"; + auto g = module->addCell(new_id(wire_name, __LINE__, ""), ID($pos)); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + g->setParam(ID::A_SIGNED, false); + g->setPort(ID::A, ip); + g->setPort(ID::Y, op); + } + + // Unary gate + RTLIL::Wire *mk_ugate1(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, std::string &op_name) + { + std::string op_wire_name; + if (op_name.empty()) + op_wire_name = name + "_o"; + else + op_wire_name = op_name; + RTLIL::Wire *ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); + auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); + g->setPort(ID::A, ip1); + g->setPort(ID::Y, ret); + g->setParam(ID::A_SIGNED, false); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + return ret; + } + + // Binary gate + RTLIL::Wire *mk_ugate2(const RTLIL::IdString &red_typ, std::string &name, RTLIL::Wire *ip1, RTLIL::Wire *ip2, std::string &op_name) + { + auto g = module->addCell(new_id(name, __LINE__, ""), red_typ); + std::string op_wire_name; + if (op_name.empty()) + op_wire_name = name + "_o"; + else + op_wire_name = op_name; + + auto ret = module->addWire(new_id(op_wire_name, __LINE__, ""), 1); + + g->setPort(ID::A, ip1); + g->setPort(ID::B, ip2); + g->setPort(ID::Y, ret); + g->setParam(ID::A_SIGNED, false); + g->setParam(ID::B_SIGNED, false); + g->setParam(ID::A_WIDTH, 1); + g->setParam(ID::B_WIDTH, 1); + g->setParam(ID::Y_WIDTH, 1); + return ret; + } + + // Booth unsigned decoder lsb + void BuildBur4d_lsb(std::string &name, RTLIL::Wire *lsb_i, RTLIL::Wire *one_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o, + std::string op_wire_name) + { + std::string empty; + auto and_op = mk_ugate2(ID($and), name, lsb_i, one_i, empty); + ppij_o = mk_ugate2(ID($xor), name, and_op, s_i, op_wire_name); + } + + // Booth unsigned radix4 decoder + void BuildBur4d_n(std::string &name, RTLIL::Wire *yn_i, RTLIL::Wire *ynm1_i, RTLIL::Wire *one_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, + RTLIL::Wire *&ppij_o) + { + // ppij = ((yn & one) | (ynm1 & two)) ^ s; + std::string empty; + auto an1 = mk_ugate2(ID($and), name, yn_i, one_i, empty); + auto an2 = mk_ugate2(ID($and), name, ynm1_i, two_i, empty); + auto or1 = mk_ugate2(ID($or), name, an1, an2, empty); + ppij_o = mk_ugate2(ID($xor), name, s_i, or1, empty); + } + + // Booth unsigned radix4 decoder + void BuildBur4d_msb(std::string &name, RTLIL::Wire *msb_i, RTLIL::Wire *two_i, RTLIL::Wire *s_i, RTLIL::Wire *&ppij_o) + { + // ppij = (msb & two) ^ s; + std::string empty; + auto an1 = mk_ugate2(ID($and), name, msb_i, two_i, empty); + ppij_o = mk_ugate2(ID($xor), name, s_i, an1, empty); + } + + // half adder, used in CPA + void BuildHa(std::string &name, RTLIL::Wire *a_i, RTLIL::Wire *b_i, RTLIL::Wire *&s_o, RTLIL::Wire *&c_o) + { + std::string empty; + s_o = mk_ugate2(ID($xor), name, a_i, b_i, empty); + c_o = mk_ugate2(ID($and), name, a_i, b_i, empty); + } + + // Booth unsigned radix 4 encoder + void BuildBur4e(std::string &name, RTLIL::Wire *y0_i, RTLIL::Wire *y1_i, RTLIL::Wire *y2_i, + + RTLIL::Wire *&one_o, RTLIL::Wire *&two_o, RTLIL::Wire *&s_o, RTLIL::Wire *&sb_o) + { + + std::string empty; + one_o = mk_ugate2(ID($xor), name, y0_i, y1_i, empty); + s_o = y2_i; + sb_o = mk_ugate1(ID($not), name, y2_i, empty); + auto inv_y1_xor_y2 = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y1_i, y2_i, empty), empty); + two_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, inv_y1_xor_y2, one_o, empty), empty); + } + + void BuildBr4e(std::string &name, RTLIL::Wire *y2_m1_i, + RTLIL::Wire *y2_i, // y2i + RTLIL::Wire *y2_p1_i, + + RTLIL::Wire *&negi_o, RTLIL::Wire *&twoi_n_o, RTLIL::Wire *&onei_n_o, RTLIL::Wire *&cori_o) + { + + std::string empty; + auto y2_p1_n = mk_ugate1(ID($not), name, y2_p1_i, empty); + auto y2_n = mk_ugate1(ID($not), name, y2_i, empty); + auto y2_m1_n = mk_ugate1(ID($not), name, y2_m1_i, empty); + + // negi_o = y2_p1_i + negi_o = mk_ugate1(ID($pos), name, y2_p1_i, empty); + // twoi_n = ~( + // (y2_p1_n & y2_i & y2_m1_i) | + // (y2_p1 & y2_n & y2_m1_n) + // ) + auto and3_1 = mk_ugate2(ID($and), name, y2_p1_n, mk_ugate2(ID($and), name, y2_i, y2_m1_i, empty), empty); + auto and3_2 = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($and), name, y2_n, y2_m1_n, empty), empty); + + twoi_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, and3_1, and3_2, empty), empty); + // onei_n = ~(y2_m1_i ^ y2_i); + onei_n_o = mk_ugate1(ID($not), name, mk_ugate2(ID($xor), name, y2_m1_i, y2_i, empty), empty); + // cori = (y2_m1_n | y2_n) & y2_p1_i; + cori_o = mk_ugate2(ID($and), name, y2_p1_i, mk_ugate2(ID($or), name, y2_m1_n, y2_n, empty), empty); + } + + // + // signed booth radix 4 decoder + // + void BuildBr4d(std::string &name, RTLIL::Wire *nxj_m1_i, RTLIL::Wire *twoi_n_i, RTLIL::Wire *xj_i, RTLIL::Wire *negi_i, RTLIL::Wire *onei_n_i, + + RTLIL::Wire *&ppij_o, RTLIL::Wire *&nxj_o) + { + + std::string empty; + // nxj_in = xnor(xj,negi) + // nxj_o = xnj_in, + // ppij = ~( (nxj_m1_i | twoi_n_i) & (nxj_int | onei_n_i)); + nxj_o = mk_ugate2(ID($xnor), name, xj_i, negi_i, empty); + RTLIL::Wire *or1 = mk_ugate2(ID($or), name, nxj_m1_i, twoi_n_i, empty); + RTLIL::Wire *or2 = mk_ugate2(ID($or), name, nxj_o, onei_n_i, empty); + ppij_o = mk_ugate1(ID($not), name, mk_ugate2(ID($and), name, or1, or2, empty), empty); + } + + /* + In signed case 1st two bits best realised + using non-booth encoded logic. We can save a booth + encoder for the first couple of bits. + */ + void BuildBoothQ1(std::string &name, RTLIL::Wire *negi_i, RTLIL::Wire *cori_i, RTLIL::Wire *x0_i, RTLIL::Wire *x1_i, RTLIL::Wire *y0_i, + RTLIL::Wire *y1_i, + + RTLIL::Wire *&nxj_o, RTLIL::Wire *&cor_o, RTLIL::Wire *&pp0_o, RTLIL::Wire *&pp1_o + + ) + { + /* + assign NXJO = ~(X1 ^ NEGI); + assign PP0 = (X0 & Y0); + //and terms for multiply + wire pp1_1_int = X1 & Y0; + wire pp1_2_int = X0 & Y1; + //sum generation for pp[1] + assign PP1 = pp1_1_int ^ pp1_2_int; + //correction propagation + assign CORO = (~PP1 & ~PP0)? CORI : 1'b0; + */ + std::string empty; + nxj_o = mk_ugate2(ID($xnor), name, x1_i, negi_i, empty); + pp0_o = mk_ugate2(ID($and), name, x0_i, y0_i, empty); + RTLIL::Wire *pp1_1_int = mk_ugate2(ID($and), name, x1_i, y0_i, empty); + RTLIL::Wire *pp1_2_int = mk_ugate2(ID($and), name, x0_i, y1_i, empty); + pp1_o = mk_ugate2(ID($xor), name, pp1_1_int, pp1_2_int, empty); + + RTLIL::Wire *pp1_nor_pp0 = mk_ugate1(ID($not), name, mk_ugate2(ID($or), name, pp1_o, pp0_o, empty), empty); + cor_o = mk_ugate2(ID($and), name, pp1_nor_pp0, cori_i, empty); + } + + void run() + { + for (auto cell : module->selected_cells()) { + if (cell->type.in(ID($mul))) { + RTLIL::SigSpec A = sigmap(cell->getPort(ID::A)); + RTLIL::SigSpec B = sigmap(cell->getPort(ID::B)); + RTLIL::SigSpec Y = sigmap(cell->getPort(ID::Y)); + if (GetSize(A) >= 4 && GetSize(B) >= 4 && GetSize(Y) >= 8 && + ((cell->getParam(ID::A_SIGNED).as_bool() && cell->getParam(ID::B_SIGNED).as_bool()) || + (!cell->getParam(ID::A_SIGNED).as_bool() && !cell->getParam(ID::B_SIGNED).as_bool()))) { + bool is_signed = false; + if (cell->getParam(ID::A_SIGNED).as_bool()) { + log(" By passing macc inferencing for signed multiplier -- generating booth\n"); + is_signed = true; + } else + log(" By passing macc inferencing for unsigned multiplier -- generating booth\n"); + + int x_sz = GetSize(A); + int y_sz = GetSize(B); + int z_sz = GetSize(Y); + + // To simplify the generator size the arguments + // to be the same. Then allow logic synthesis to + // clean things up. Size to biggest + + int x_sz_revised = x_sz; + int y_sz_revised = y_sz; + + if (x_sz != y_sz) { + if (x_sz < y_sz) { + if (y_sz % 2 != 0) { + x_sz_revised = y_sz + 1; + y_sz_revised = y_sz + 1; + } else + x_sz_revised = y_sz; + + } else { + if (x_sz % 2 != 0) { + y_sz_revised = x_sz + 1; + x_sz_revised = x_sz + 1; + } else + y_sz_revised = x_sz; + } + } else { + if (x_sz % 2 != 0) { + y_sz_revised = y_sz + 1; + x_sz_revised = x_sz + 1; + } + } + + log_assert((x_sz_revised == y_sz_revised) && (x_sz_revised % 2 == 0) && (y_sz_revised % 2 == 0)); + + Wire *expanded_A = module->addWire(NEW_ID, x_sz_revised); + Wire *expanded_B = module->addWire(NEW_ID, y_sz_revised); + + std::string buf_name = "expand_a_buf_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setParam(ID::A_WIDTH, x_sz); + buf->setParam(ID::Y_WIDTH, x_sz_revised); + buf->setPort(ID::A, SigSpec(A)); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_A)); + + buf_name = "expand_b_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, SigSpec(B)); + buf->setParam(ID::A_WIDTH, y_sz); + buf->setParam(ID::Y_WIDTH, y_sz_revised); + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + buf->setPort(ID::Y, SigSpec(expanded_B)); + + // Make sure output domain is big enough to take + // all combinations. + // Later logic synthesis will kill unused + // portions of the output domain. + + unsigned required_op_size = x_sz_revised + y_sz_revised; + Wire *expanded_Y = module->addWire(NEW_ID, required_op_size); + // now connect the expanded_Y with a tap to fill out sig Spec Y + buf_name = "reducer_buf_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, expanded_Y); + buf->setParam(ID::A_WIDTH, required_op_size); + buf->setParam(ID::Y_WIDTH, z_sz); // The real user width + buf->setParam(ID::A_SIGNED, is_signed ? true : false); + // wire in output Y + buf->setPort(ID::Y, SigSpec(Y)); + + if (is_signed == false) /* unsigned multiplier */ + CreateBoothUMult(module, x_sz_revised, y_sz_revised, required_op_size, + expanded_A, // multiplicand + expanded_B, // multiplier(scanned) + expanded_Y // result + ); + else /*signed multiplier */ + CreateBoothSMult(module, x_sz_revised, y_sz_revised, required_op_size, + expanded_A, // multiplicand + expanded_B, // multiplier(scanned) + expanded_Y // result (sized) + ); + module->remove(cell); + booth_counter++; + continue; + } + } + } + } + + /* + Build Unsigned Multiplier. + ------------------------- + Create a booth unsigned multiplier. + Uses a generic booth multiplier with + extra row of decoders and extended multiplier + */ + + void CreateBoothUMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, + RTLIL::Wire *X, // multiplicand + RTLIL::Wire *Y, // multiplier + RTLIL::Wire *Z) + { // result + + std::vector one_int; + std::vector two_int; + std::vector s_int; + std::vector sb_int; + int encoder_count = 0; + + BuildBoothUMultEncoders(Y, y_sz, one_int, two_int, s_int, sb_int, module, encoder_count); + + // Build the decoder rows + // format of each Partial product to be passed to CSA + // tree builder: + // + // Bits to be added + // Shift + // Sign bit to be added + // + std::vector, int, RTLIL::Wire *>> ppij_int; + + static int constant_ix; + constant_ix++; + std::string buf_name = "constant_buf_" + std::to_string(constant_ix); + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + RTLIL::Wire *constant_one = module->addWire(new_id(buf_name, __LINE__, ""), 1); + buf->setPort(ID::A, State::S1); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, constant_one); + + constant_ix++; + buf_name = "constant_buf_" + std::to_string(constant_ix); + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + RTLIL::Wire *constant_zero = module->addWire(new_id(buf_name, __LINE__, ""), 1); + buf->setPort(ID::A, State::S0); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, constant_zero); + + // Row 0: special case 1. Format S/.S.S.C.Data + std::vector ppij_row_0; + BuildBoothUMultDecoderRow0(module, X, s_int, sb_int, one_int, two_int, ppij_row_0); + + // data, shift, sign + ppij_int.push_back(std::make_tuple(ppij_row_0, 0, s_int[0])); + + for (int i = 1; i < encoder_count - 2; i++) { + // format 1,S.Data.shift = encoder_ix*2,sign = sb_int[i] + std::vector ppij_row_n; + + BuildBoothUMultDecoderRowN(module, + X, // multiplicand + one_int[i], two_int[i], s_int[i], sb_int[i], ppij_row_n, constant_one, i, + false, // include sign + false // include constant + ); + // data, shift, sign + ppij_int.push_back(std::make_tuple(ppij_row_n, i * 2, s_int[i])); + } + + // Build second to last row + // format S/,Data + sign bit + std::vector ppij_row_em1; + BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 2], two_int[encoder_count - 2], s_int[encoder_count - 2], + sb_int[encoder_count - 2], ppij_row_em1, constant_one, encoder_count - 2, + false, // include sign + true // no constant + ); + ppij_int.push_back(std::make_tuple(ppij_row_em1, (encoder_count - 2) * 2, s_int[encoder_count - 2])); + // Build last row + // format Data + sign bit + std::vector ppij_row_e; + BuildBoothUMultDecoderRowN(module, X, one_int[encoder_count - 1], two_int[encoder_count - 1], s_int[encoder_count - 1], + sb_int[encoder_count - 1], ppij_row_e, constant_one, encoder_count - 1, + true, // no sign + true // no constant + ); + ppij_int.push_back(std::make_tuple(ppij_row_e, (encoder_count - 1) * 2, s_int[encoder_count - 1])); + + // Debug dump out partial products + // DebugDumpPP(ppij_int); + + // Summation of Partial Products (Wallace Tree) + std::vector> aligned_pp; + aligned_pp.resize(encoder_count + 1); // make an entirely redundant row + // just for sign bit in lsb. (We then filter this out). + + // resize all to be same size as z + for (int i = 0; i < encoder_count + 1; i++) + aligned_pp[i].resize(z_sz); + + AlignPP(x_sz, z_sz, ppij_int, aligned_pp); + + // Debug: dump out aligned partial products. + // Later on yosys will clean up unused constants + // DebugDumpAlignPP(aligned_pp); + + std::vector s_vec; + std::vector c_vec; + std::vector> debug_csa_trees; + + debug_csa_trees.resize(z_sz); + + BuildCSATree(module, aligned_pp, s_vec, c_vec, debug_csa_trees); + + // Debug code: Dump out the csa trees + // DumpCSATrees(debug_csa_trees); + // Build the CPA to do the final accumulation. + BuildCPA(module, s_vec, c_vec, Z); + } + + /* + Build Row 0 of decoders + */ + + void BuildBoothUMultDecoderRow0(RTLIL::Module *module, + RTLIL::Wire *X, // multiplicand + std::vector &s_int, std::vector &sb_int, std::vector &one_int, + std::vector &two_int, std::vector &ppij_vec) + { + (void)module; + int x_sz = GetSize(X); + + // lsb + std::string dec_name = "row0_lsb_dec"; + + RTLIL::Wire *ppij; + std::string ppij_name = "ppij_0_0"; + BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int[0], s_int[0], ppij, ppij_name); + ppij_vec.push_back(ppij); + + // 1..xsize -1 + for (int i = 1; i < x_sz; i++) { + dec_name = "row0_dec_" + std::to_string(i); + RTLIL::Wire *ppij; + BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int[0], two_int[0], + s_int[0], ppij); + ppij_vec.push_back(ppij); + } + + // The redundant bit. Duplicate decoding of last bit. + dec_name = "row0_dec_msb"; + BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int[0], s_int[0], ppij); + ppij_vec.push_back(ppij); + + // append the sign bits + ppij_vec.push_back(s_int[0]); + ppij_vec.push_back(s_int[0]); + ppij_vec.push_back(sb_int[0]); + } + + // Build a generic row of decoders. + + void BuildBoothUMultDecoderRowN(RTLIL::Module *module, + RTLIL::Wire *X, // multiplicand + RTLIL::Wire *one_int, RTLIL::Wire *two_int, RTLIL::Wire *s_int, RTLIL::Wire *sb_int, + std::vector &ppij_vec, RTLIL::Wire *constant_one, int row_ix, bool no_sign, bool no_constant) + { + (void)module; + int x_sz = GetSize(X); + + // lsb + std::string ppij_name = "ppij_" + std::to_string(row_ix) + "_0"; + RTLIL::Wire *ppij = nullptr; + std::string empty; + std::string dec_name = "row" + std::to_string(row_ix) + "_lsb_dec"; + BuildBur4d_lsb(dec_name, mk_wireFromSigSpec(SigSpec(X, 0, 1)), one_int, s_int, ppij, empty); + + ppij_vec.push_back(ppij); + + // core bits + for (int i = 1; i < x_sz; i++) { + + dec_name = "row_" + std::to_string(row_ix) + "_dec_" + std::to_string(i); + RTLIL::Wire *ppij = nullptr; + BuildBur4d_n(dec_name, mk_wireFromSigSpec(SigSpec(X, i, 1)), mk_wireFromSigSpec(SigSpec(X, i - 1, 1)), one_int, two_int, + s_int, ppij); + ppij_vec.push_back(ppij); + } + + // redundant bit + + dec_name = "row_dec_red"; + BuildBur4d_msb(dec_name, mk_wireFromSigSpec(SigSpec(X, x_sz - 1, 1)), two_int, s_int, ppij); + ppij_vec.push_back(ppij); + + // sign bit + if (no_sign == false) // if no sign is false then make a sign bit + ppij_vec.push_back(sb_int); + + // constant bit + if (no_constant == false) { // if non constant is false make a constant bit + ppij_vec.push_back(constant_one); + } + } + + void DebugDumpAlignPP(std::vector> &aligned_pp) + { + printf("Aligned & Padded Partial products\n"); + int pp_ix = 0; + for (auto pp_row : aligned_pp) { + printf("PP_%d \t", pp_ix); + for (unsigned i = 0; i < pp_row.size(); i++) + printf("[%d] %s ", i, pp_row[i] == nullptr ? " 0 " : pp_row[i]->name.c_str()); + printf("\n"); + pp_ix++; + } + } + + // Debug routines to inspect intermediate results + void DebugDumpPP(std::vector, int, RTLIL::Wire *>> &ppij_int) + { + printf("Debug dump of partial products\n"); + int pp_ix = 0; + + for (auto pp : ppij_int) { + int shift = get<1>(pp); + RTLIL::Wire *sign_bit = get<2>(pp); + + printf("PP %d\n", pp_ix); + printf("\tShift %d\n", shift); + printf("\tData (0 lsb)\n\t"); + int ix = 0; + + for (auto pp_wire : get<0>(pp)) { + RTLIL::IdString wire_name = pp_wire->name; + + printf(" [%d]:%s ", ix, wire_name.c_str()); + ix++; + } + printf("\n"); + printf("\tSign bit to add in: %s\n", sign_bit->name.c_str()); + + pp_ix++; + } + } + + void DumpCSATrees(std::vector> &debug_csa_trees) + { + int i = 0; + for (auto csa_tree : debug_csa_trees) { + printf("CSA Tree column %d\n", i); + int ix = 0; + for (auto csa_elem : csa_tree) { + printf("\tCell %d %s type %s\n", ix, csa_elem->name.c_str(), csa_elem->type.c_str()); + if (csa_elem->getPort(ID::A) == State::S0) + printf("\tA set to constant 0\n"); + else if (csa_elem->getPort(ID::A) == State::S1) + printf("\tA set to constant 1\n"); + else + printf("\tA driven by %s\n", csa_elem->getPort(ID::A).as_wire()->name.c_str()); + + if (csa_elem->getPort(ID::B) == State::S0) + printf("\tB set to constant 0\n"); + else if (csa_elem->getPort(ID::B) == State::S1) + printf("\tB set to constant 1\n"); + else + printf("\tB driven by %s\n", csa_elem->getPort(ID::B).as_wire()->name.c_str()); + + if (csa_elem->getPort(ID::C) == State::S0) + printf("\tC set to constant 0\n"); + else if (csa_elem->getPort(ID::C) == State::S1) + printf("\tC set to constant 1\n"); + else + printf("\tC driven by %s\n", csa_elem->getPort(ID::C).as_wire()->name.c_str()); + + printf("Carry out: %s\n", csa_elem->getPort(ID::X).as_wire()->name.c_str()); + printf("Sum out: %s\n", csa_elem->getPort(ID::Y).as_wire()->name.c_str()); + + ix++; + } + i++; + } + } + + void BuildCSATree(RTLIL::Module *module, std::vector> &bits_to_reduce, std::vector &s_vec, + std::vector &c_vec, std::vector> &debug_csa_trees) + { + + if (!(bits_to_reduce.size() > 0)) + return; + + int column_size = bits_to_reduce[0].size(); + int row_size = bits_to_reduce.size(); + std::vector carry_bits_to_add_to_next_column; + + for (int column_ix = 0; column_ix < column_size; column_ix++) { + + // get the bits in this column. + std::vector column_bits; + for (int row_ix = 0; row_ix < row_size; row_ix++) { + if (bits_to_reduce[row_ix].at(column_ix)) + column_bits.push_back(bits_to_reduce[row_ix].at(column_ix)); + } + for (auto c : carry_bits_to_add_to_next_column) { +#ifdef DEBUG_CSA + printf("\t Propagating column bit %s to column %d from column %d\n", c->name.c_str(), column_ix, column_ix - 1); +#endif + column_bits.push_back(c); + } + + carry_bits_to_add_to_next_column.resize(0); + +#ifdef DEBUG_CSA + printf("Column %d Reducing %d bits\n", column_ix, column_bits.size()); + for (auto b : column_bits) { + printf("\t %s\n", b->name.c_str()); + } + printf("\n"); +#endif + + RTLIL::Wire *s = nullptr; + RTLIL::Wire *c = nullptr; +#ifdef DEBUG_CSA + int csa_count_before = debug_csa_trees[column_ix].size(); +#endif + + ReduceBits(module, column_ix, column_bits, s, c, carry_bits_to_add_to_next_column, debug_csa_trees); + + s_vec.push_back(s); + c_vec.push_back(c); + +#ifdef DEBUG_CSA + int csa_count_after = debug_csa_trees[column_ix].size(); + + printf("Column %d Created %d csa tree elements\n", column_ix, csa_count_after - csa_count_before); +#endif + } + } + + /* + Alignment: + --------- + + Concept traverse from last row. + Pad row by shift + Add sign bit from prior row to 2 bits right of end of data. + + Example + + SCDDDDDDD- +S + DDDDDDDD_ + + ==> + SCDDDDDDD- + DDDDDDDD_S <-- prior rows sign bit added 2 columns to right on next row. + + Pad out rows with zeros and left the opt pass clean them up. + + */ + void AlignPP(int x_sz, int z_sz, std::vector, int, RTLIL::Wire *>> &ppij_int, + std::vector> &aligned_pp) + { + unsigned aligned_pp_ix = aligned_pp.size() - 1; + + // default is zero for everything (so don't have to think to hard + // about padding). + + for (unsigned i = 0; i < aligned_pp.size(); i++) { + for (int j = 0; j < z_sz; j++) { + aligned_pp[i][j] = nullptr; + } + } + + // for very last row we just have the sign bit + // Note that the aligned_pp is one row bigger + // than the ppij_int. We put the sign bit + // in first column of the last partial product + // which is at index corresponding to size of multiplicand + { + RTLIL::Wire *prior_row_sign = nullptr; + prior_row_sign = get<2>(ppij_int[aligned_pp_ix - 1]); + if (prior_row_sign) { + log_assert(aligned_pp_ix < aligned_pp.size()); + log_assert(x_sz - 1 < (int)(aligned_pp[aligned_pp_ix].size())); + aligned_pp[aligned_pp_ix][x_sz - 1] = prior_row_sign; + } + } + + for (int row_ix = aligned_pp_ix - 1; row_ix >= 0; row_ix--) { + int shift_amount = get<1>(ppij_int[row_ix]); + RTLIL::Wire *prior_row_sign = nullptr; + + // copy in data + unsigned copy_ix = shift_amount; + for (auto w : get<0>(ppij_int[row_ix])) { + if (copy_ix < aligned_pp[row_ix].size()) { + aligned_pp[row_ix][copy_ix] = w; + } + copy_ix++; + } + + // copy in the sign bit from the prior row + if (row_ix > 0) { + // if sign bit on prior row, copy in + // the destination of the sign bit is the (row_ix -1)*2 + // eg destination for sign bit for row 0 is 0. + // eg destination for sign bit for row 1 is 1 + prior_row_sign = get<2>(ppij_int[row_ix - 1]); + copy_ix = (row_ix - 1) * 2; + aligned_pp[row_ix][copy_ix] = prior_row_sign; + } + } + } + + /* + Build a Carry Propagate Adder + ----------------------------- + First build the sum and carry vectors to be added. + Axioms: + c_vec.size() == s_vec.size() + result.size() == s_vec.size() + 2; (assume result is reserved to hold correct size) + */ + void BuildCPA(RTLIL::Module *module, std::vector &s_vec, std::vector &c_vec, RTLIL::Wire *result) + { + + static int cpa_id; + cpa_id++; + + RTLIL::Wire *carry = nullptr; + + log_assert(s_vec.size() == c_vec.size()); + + for (unsigned n = 0; n < s_vec.size(); n++) { + std::string carry_name; + + // Base Case: Bit 0 is sum 0 + if (n == 0) { + std::string buf_name = "base_buf_" + std::to_string(cpa_id) + "_" + std::to_string(n); + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, s_vec[0]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, false); + buf->setPort(ID::Y, SigSpec(result, 0, 1)); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IP 0 %s \n", n, buf->name.c_str(), s_vec[0]->name.c_str()); +#endif + } + + // + // Base Case + // c,s = ha(s_vec[1],c_vec[0]) + // + else if (n == 1) { + std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); + RTLIL::Wire *ha_op; + BuildHa(ha_name, s_vec[n], c_vec[n - 1], ha_op, carry); + + module->connect(ha_op, SigSpec(result, n, 1)); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] \n", n, ha_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str()); +#endif + + } + // End Case + else if (n == (unsigned)((s_vec.size() - 1))) { + // Make the carry results.. Two extra bits after fa. + std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); + fa_cell->setParam(ID::WIDTH, 1); + carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); + fa_cell->setPort(ID::A, s_vec[n]); + fa_cell->setPort(ID::B, c_vec[n - 1]); + fa_cell->setPort(ID::C, carry); + // wire in result and carry out + fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + + // make a new carry bit for carry out... + carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); + fa_cell->setPort(ID::X, carry); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str(), carry->name.c_str()); +#endif + if (n + 1 < (unsigned)(GetSize(result))) { + // Now make a half adder: c_vec[n] = carry + std::string ha_name = "cpa_" + std::to_string(cpa_id) + "_ha_" + std::to_string(n); + RTLIL::Wire *ha_sum; + RTLIL::Wire *ha_carry; + BuildHa(ha_name, c_vec[n], carry, ha_sum, ha_carry); + if (n + 1 < (unsigned)GetSize(result)) + module->connect(ha_sum, SigSpec(result, n + 1, 1)); + if (n + 2 < (unsigned)GetSize(result)) + module->connect(ha_carry, SigSpec(result, n + 2, 1)); + } + } + // Step case + else { + std::string fa_name = "cpa_" + std::to_string(cpa_id) + "_fa_" + std::to_string(n); + auto fa_cell = module->addCell(new_id(fa_name, __LINE__, ""), ID($fa)); + fa_cell->setParam(ID::WIDTH, 1); + + carry_name = "cpa_" + std::to_string(cpa_id) + "carry_" + std::to_string(n); + fa_cell->setPort(ID::A, s_vec[n]); + fa_cell->setPort(ID::B, c_vec[n - 1]); + fa_cell->setPort(ID::C, carry); + // wire in result and carry out + fa_cell->setPort(ID::Y, SigSpec(result, n, 1)); + // make a new carry bit for carry out... + carry = module->addWire(new_id(carry_name, __LINE__, ""), 1); + fa_cell->setPort(ID::X, carry); + +#ifdef DEBUG_CPA + printf("CPA bit [%d] Cell %s IPs [%s] [%s] [%s]\n", n, fa_cell->name.c_str(), s_vec[n]->name.c_str(), + c_vec[n - 1]->name.c_str(), carry->name.c_str()); +#endif + } + } + } + + // Sum the bits in the current column + // Pass the carry bits from each csa to the next + // column for summation. + + void ReduceBits(RTLIL::Module *module, int column_ix, std::vector &column_bits, RTLIL::Wire *&s_result, RTLIL::Wire *&c_result, + std::vector &carry_bits_to_sum, std::vector> &debug_csa_trees) + { + + int csa_ix = 0; + int column_size = column_bits.size(); + static int unique_id = 0; + + unique_id++; + + if (column_size > 0) { + unsigned var_ix = 0; + std::vector first_csa_ips; + // get the first 3 inputs, if possible + for (var_ix = 0; var_ix < column_bits.size() && first_csa_ips.size() != 3; var_ix++) { + if (column_bits[var_ix]) + first_csa_ips.push_back(column_bits[var_ix]); + } + + if (first_csa_ips.size() > 0) { + // build the first csa + std::string csa_name = + "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_" + std::to_string(unique_id) + "_"; + auto csa = module->addCell(NEW_ID, + // new_id(csa_name, + // __LINE__, + // ""), + ID($fa)); + csa->setParam(ID::WIDTH, 1); + debug_csa_trees[column_ix].push_back(csa); + csa_ix++; + + csa->setPort(ID::A, first_csa_ips[0]); + + if (first_csa_ips.size() > 1) + csa->setPort(ID::B, first_csa_ips[1]); + else + csa->setPort(ID::B, State::S0); + + if (first_csa_ips.size() > 2) + csa->setPort(ID::C, first_csa_ips[2]); + else + csa->setPort(ID::C, State::S0); + + std::string sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; + auto s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); + csa->setPort(ID::Y, s_wire); + s_result = s_wire; + std::string carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; + auto c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); + csa->setPort(ID::X, c_wire); + c_result = c_wire; + + if (var_ix <= column_bits.size() - 1) + carry_bits_to_sum.push_back(c_wire); + + // Now build the rest of the tree if we can + while (var_ix <= column_bits.size() - 1) { + std::vector csa_ips; + // get the next two variables to sum + for (; var_ix <= column_bits.size() - 1 && csa_ips.size() < 2;) { + // skip any empty bits + if (column_bits[var_ix] != nullptr) + csa_ips.push_back(column_bits[var_ix]); + var_ix++; + } + + if (csa_ips.size() > 0) { + csa_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix); + auto csa = module->addCell(new_id(csa_name, __LINE__, ""), ID($fa)); + csa->setParam(ID::WIDTH, 1); + debug_csa_trees[column_ix].push_back(csa); + + csa_ix++; + // prior level + csa->setPort(ID::A, s_wire); + csa->setPort(ID::B, csa_ips[0]); + if (csa_ips.size() > 1) + csa->setPort(ID::C, csa_ips[1]); + else + csa->setPort(ID::C, State::S0); + + carry_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_c"; + c_wire = module->addWire(new_id(carry_wire_name, __LINE__, ""), 1); + + if (var_ix <= column_bits.size() - 1) + carry_bits_to_sum.push_back(c_wire); + + sum_wire_name = "csa_" + std::to_string(column_ix) + "_" + std::to_string(csa_ix) + "_s"; + s_wire = module->addWire(new_id(sum_wire_name, __LINE__, ""), 1); + + csa->setPort(ID::X, c_wire); + csa->setPort(ID::Y, s_wire); + + s_result = s_wire; + c_result = c_wire; + } + } + } + } + } + + void BuildBoothUMultEncoders(RTLIL::Wire *Y, int y_sz, std::vector &one_int, std::vector &two_int, + std::vector &s_int, std::vector &sb_int, RTLIL::Module *module, int &encoder_ix) + { + for (int y_ix = 0; y_ix < y_sz;) { + std::string enc_name = "bur_enc_" + std::to_string(encoder_ix) + "_"; + + std::string two_name = "two_int" + std::to_string(encoder_ix); + two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string one_name = "one_int" + std::to_string(encoder_ix); + one_int.push_back(module->addWire(new_id(one_name, __LINE__, ""), 1)); + + std::string s_name = "s_int" + std::to_string(encoder_ix); + s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + + std::string sb_name = "sb_int" + std::to_string(encoder_ix); + sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + + if (y_ix == 0) { + + BuildBur4e(enc_name, mk_wireFromSigSpec(State::S0), mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), + mk_wireFromSigSpec(SigSpec(Y, y_ix + 1, 1)), one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + sb_int[encoder_ix]); + + y_ix = y_ix + 1; + encoder_ix++; + } else { + // + // step case. If multiplier ends on a boundary + // then add an extra booth encoder bounded by + // zeroes to ensure unsigned works. + // + RTLIL::Wire *y0_wire; + RTLIL::Wire *y1_wire; + RTLIL::Wire *y2_wire; + + bool need_padded_cell = false; + + if (y_ix > y_sz - 1) { + y0_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + need_padded_cell = false; + } else { + y0_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y_ix++; + } + + if (y_ix > y_sz - 1) { + need_padded_cell = false; + y1_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + } else { + y1_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + y_ix++; + } + + if (y_ix > y_sz - 1) { + need_padded_cell = false; + y2_wire = mk_wireFromSigSpec(SigSpec(Y, State::S0)); + } else { + if (y_ix == y_sz - 1) + need_padded_cell = true; + else + need_padded_cell = false; + y2_wire = mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)); + + BuildBur4e(enc_name, y0_wire, y1_wire, y2_wire, one_int[encoder_ix], two_int[encoder_ix], s_int[encoder_ix], + sb_int[encoder_ix]); + } + + encoder_ix++; + + if (need_padded_cell == true) { + + // make extra encoder cell + // y_ix at y0, rest 0 + + std::string enc_name = "br_enc_pad" + std::to_string(encoder_ix) + "_"; + + std::string two_name = "two_int" + std::to_string(encoder_ix); + two_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string one_name = "one_int" + std::to_string(encoder_ix); + one_int.push_back(module->addWire(new_id(two_name, __LINE__, ""), 1)); + + std::string s_name = "s_int" + std::to_string(encoder_ix); + s_int.push_back(module->addWire(new_id(s_name, __LINE__, ""), 1)); + + std::string sb_name = "sb_int" + std::to_string(encoder_ix); + sb_int.push_back(module->addWire(new_id(sb_name, __LINE__, ""), 1)); + + RTLIL::Wire *one_o_int, *two_o_int, *s_o_int, *sb_o_int; + BuildBur4e(enc_name, mk_wireFromSigSpec(SigSpec(Y, y_ix, 1)), mk_wireFromSigSpec(State::S0), + mk_wireFromSigSpec(State::S0), one_o_int, two_o_int, s_o_int, sb_o_int); + + join_wires_with_buffer(one_o_int, one_int[encoder_ix]); + join_wires_with_buffer(two_o_int, two_int[encoder_ix]); + join_wires_with_buffer(s_o_int, s_int[encoder_ix]); + join_wires_with_buffer(sb_o_int, sb_int[encoder_ix]); + y_ix++; + encoder_ix++; + } + } + } + } + + /* + Signed Multiplier + */ + void CreateBoothSMult(RTLIL::Module *module, int x_sz, int y_sz, int z_sz, RTLIL::Wire *X, RTLIL::Wire *Y, RTLIL::Wire *Z) + { // product + unsigned enc_count = (y_sz / 2) + (((y_sz % 2) != 0) ? 1 : 0); + int dec_count = x_sz + 1; + + int fa_count = x_sz + 4; + int fa_row_count = enc_count - 1; + + log("Signed multiplier generator using low Power Negative First Booth Algorithm. Multiplicand of size %d Multiplier of size %d. " + "Result of size %d. %d encoders %d decoders\n", + x_sz, y_sz, z_sz, enc_count, dec_count); + + RTLIL::Wire **negi_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **twoi_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **onei_n_int = new RTLIL::Wire *[enc_count]; + RTLIL::Wire **cori_n_int = new RTLIL::Wire *[enc_count]; + + for (unsigned encoder_ix = 1; encoder_ix <= enc_count; encoder_ix++) { + std::string enc_name = "enc_" + std::to_string(encoder_ix) + "_"; + std::string negi_name = "negi_n_int" + std::to_string(encoder_ix) + "_"; + negi_n_int[encoder_ix - 1] = module->addWire(new_id(negi_name, __LINE__, ""), 1); + std::string twoi_name = "twoi_n_int_" + std::to_string(encoder_ix) + "_"; + twoi_n_int[encoder_ix - 1] = module->addWire(new_id(twoi_name, __LINE__, ""), 1); + std::string onei_name = "onei_n_int_" + std::to_string(encoder_ix) + "_"; + onei_n_int[encoder_ix - 1] = module->addWire(new_id(onei_name, __LINE__, ""), 1); + std::string cori_name = "cori_n_int_" + std::to_string(encoder_ix) + "_"; + cori_n_int[encoder_ix - 1] = module->addWire(new_id(cori_name, __LINE__, ""), 1); + + if (encoder_ix == 1) { + + BuildBr4e(enc_name, mk_wireFromSigSpec(SigSpec(State::S0)), mk_wireFromSigSpec(SigSpec(Y, 0, 1)), + mk_wireFromSigSpec(SigSpec(Y, 1, 1)), + + negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + cori_n_int[encoder_ix - 1]); + + } else { + RTLIL::Wire *y1_wire; + RTLIL::Wire *y2_wire; + RTLIL::Wire *y3_wire; + + y1_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 - 1), 1)); //-1 + if ((encoder_ix - 1) * 2 >= (unsigned)y_sz) + y2_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + else + y2_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2), 1)); // 0 + + if (((encoder_ix - 1) * 2 + 1) >= (unsigned)y_sz) + y3_wire = mk_wireFromSigSpec(SigSpec(State::S0)); // constant 0 + else + y3_wire = mk_wireFromSigSpec(SigSpec(Y, ((encoder_ix - 1) * 2 + 1), 1)); //+1 + + BuildBr4e(enc_name, y1_wire, y2_wire, y3_wire, + + negi_n_int[encoder_ix - 1], twoi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + cori_n_int[encoder_ix - 1]); + } + } + + // Decoders and PP generation + RTLIL::Wire **PPij = new RTLIL::Wire *[enc_count * dec_count]; + RTLIL::Wire **nxj = new RTLIL::Wire *[enc_count * dec_count]; + + for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { + for (int decoder_ix = 1; decoder_ix <= dec_count; decoder_ix++) { + std::string ppij_name = "ppij_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(ppij_name, __LINE__, ""), 1); + std::string nxj_name; + if (decoder_ix == 1) + nxj_name = "nxj_pre_dec" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + else + nxj_name = "nxj_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + + nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1] = module->addWire(new_id(nxj_name, __LINE__, ""), 1); + } + } + + // + // build decoder array + // + + for (int encoder_ix = 1; encoder_ix <= (int)enc_count; encoder_ix++) { + // pre-decoder + std::string pre_dec_name = "pre_dec_" + std::to_string(encoder_ix) + "_"; + + if (encoder_ix == 1) { + // quadrant 1 optimization + } else { + auto cell = module->addCell(new_id(pre_dec_name, __LINE__, ""), ID($_NOT_)); + cell->add_strpool_attribute(ID::src, cell->get_strpool_attribute(ID::src)); + cell->setPort(ID::A, negi_n_int[encoder_ix - 1]); + cell->setPort(ID::Y, nxj[(encoder_ix - 1) * dec_count]); + } + + for (int decoder_ix = 1; decoder_ix < dec_count; decoder_ix++) { + // range 1..8 + + // quadrant 1 optimization. + if ((decoder_ix == 1 || decoder_ix == 2) && encoder_ix == 1) + continue; + + std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(decoder_ix) + "_"; + + BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + decoder_ix - 1], twoi_n_int[encoder_ix - 1], + mk_wireFromSigSpec(SigSpec(X, decoder_ix - 1, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + PPij[((encoder_ix - 1) * dec_count) + decoder_ix - 1], nxj[((encoder_ix - 1) * dec_count) + decoder_ix]); + } + + // duplicate end for sign fix + // applies to 9th decoder (xsz+1 decoder). + std::string dec_name = "dec_" + std::to_string(encoder_ix) + "_" + std::to_string(x_sz + 1) + "_"; + RTLIL::Wire *unused_op = nullptr; + BuildBr4d(dec_name, nxj[((encoder_ix - 1) * dec_count) + dec_count - 1], twoi_n_int[encoder_ix - 1], + mk_wireFromSigSpec(SigSpec(X, dec_count - 2, 1)), negi_n_int[encoder_ix - 1], onei_n_int[encoder_ix - 1], + PPij[((encoder_ix - 1) * dec_count) + dec_count - 1], unused_op); + } + + // + // sum up the partial products + // + int fa_el_ix = 0; + int fa_row_ix = 0; + // use 1 d arrays (2d cannot have variable sized indices) + RTLIL::Wire **fa_sum_n = new RTLIL::Wire *[fa_row_count * fa_count]; + RTLIL::Wire **fa_carry_n = new RTLIL::Wire *[fa_row_count * fa_count]; + + for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { + for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { + + std::string fa_sum_name = "fa_sum_n_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; + fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_sum_name, __LINE__, ""), 1); + std::string fa_carry_name = "fa_carry_n" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_"; + fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix] = module->addWire(new_id(fa_carry_name, __LINE__, ""), 1); + } + } + + // full adder creation + std::string bfa_name; + std::string exc_inv_name; + for (fa_row_ix = 0; fa_row_ix < fa_row_count; fa_row_ix++) { + for (fa_el_ix = 0; fa_el_ix < fa_count; fa_el_ix++) { + // base case: 1st row. Inputs from decoders + // Note in rest of tree inputs from prior addition and a decoder + if (fa_row_ix == 0) { + // beginning + // base case: + // first two cells: have B input hooked to 0. + if (fa_el_ix == 0) { + // quadrant 1: we hard code these using non-booth + fa_el_ix++; + + } + // step case + else if (fa_el_ix >= 2 && fa_el_ix <= x_sz) { + // middle (2...x_sz cells) + bfa_name = "bfa_0_step_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell->setParam(ID::WIDTH, 1); + cell->setPort(ID::A, PPij[(0 * dec_count) + fa_el_ix]); + cell->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + } + // end 3 cells: x_sz+1.2.3 + // + else { + // fa_el_ix = x_sz+1 + bfa_name = "bfa_0_se_0" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, PPij[(0 * dec_count) + x_sz]); + cell1->setPort(ID::B, PPij[(1 * dec_count) + fa_el_ix - 2]); + cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + // exception:invert ppi + fa_el_ix++; + exc_inv_name = "bfa_0_exc_inv1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cellinv1 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv1->add_strpool_attribute(ID::src, cellinv1->get_strpool_attribute(ID::src)); + + RTLIL::Wire *d08_inv = module->addWire(NEW_ID, 1); + + cellinv1->setPort(ID::A, PPij[(0 * dec_count) + dec_count - 1]); + cellinv1->setPort(ID::Y, d08_inv); + + exc_inv_name = "bfa_0_exc_inv2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + + auto cellinv2 = module->addCell(new_id(exc_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv2->add_strpool_attribute(ID::src, cellinv2->get_strpool_attribute(ID::src)); + RTLIL::Wire *d18_inv = module->addWire(NEW_ID, 1); + cellinv2->setPort(ID::A, PPij[(1 * dec_count) + dec_count - 1]); + cellinv2->setPort(ID::Y, d18_inv); + + bfa_name = "bfa_0_se_1_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, d08_inv); + cell2->setPort(ID::B, d18_inv); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + + // sign extension + fa_el_ix++; + bfa_name = "bfa_0_se_2_" + std::to_string(fa_row_ix) + "_" + std::to_string(fa_el_ix) + "_L"; + auto cell3 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell3->setParam(ID::WIDTH, 1); + cell3->setPort(ID::A, State::S0); + cell3->setPort(ID::B, State::S1); + cell3->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell3->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell3->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + } + } + + // step case: 2nd and rest of rows. (fa_row_ix == 1...n) + // special because these are driven by a decoder and prior fa. + else { + // beginning + if (fa_el_ix == 0) { + // first two cells: have B input hooked to 0. + // column is offset by row_ix*2 + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + 2]); // from prior full adder row + cell1->setPort(ID::B, State::S0); + cell1->setPort(ID::C, cori_n_int[fa_row_ix]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + fa_el_ix++; + + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_base_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, + fa_sum_n[(fa_row_ix - 1) * fa_count + 3]); // from prior full adder row + cell2->setPort(ID::B, State::S0); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + } + + else if (fa_el_ix >= 2 && fa_el_ix <= x_sz + 1) { + // middle (2...x_sz+1 cells) + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_step_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell->setParam(ID::WIDTH, 1); + cell->setPort(ID::A, fa_sum_n[(fa_row_ix - 1) * fa_count + fa_el_ix + 2]); + cell->setPort(ID::B, PPij[(fa_row_ix + 1) * dec_count + fa_el_ix - 2]); + cell->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + } + + else if (fa_el_ix > x_sz + 1) { + // end two bits: sign extension + std::string se_inv_name; + se_inv_name = "bfa_" + std::to_string(fa_row_ix) + "_se_inv_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cellinv = module->addCell(new_id(se_inv_name, __LINE__, ""), ID($_NOT_)); + cellinv->add_strpool_attribute(ID::src, cellinv->get_strpool_attribute(ID::src)); + RTLIL::Wire *d_inv = module->addWire(NEW_ID, 1); + cellinv->setPort(ID::A, PPij[((fa_row_ix + 1) * dec_count) + dec_count - 1]); + cellinv->setPort(ID::Y, d_inv); + + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell1 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell1->setParam(ID::WIDTH, 1); + cell1->setPort(ID::A, fa_carry_n[((fa_row_ix - 1) * fa_count) + fa_count - 1]); + cell1->setPort(ID::B, d_inv); + cell1->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell1->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell1->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + fa_el_ix++; + + // sign extension + bfa_name = "bfa_" + std::to_string(fa_row_ix) + "_se_" + std::to_string(fa_row_ix) + "_" + + std::to_string(fa_el_ix) + "_L"; + auto cell2 = module->addCell(new_id(bfa_name, __LINE__, ""), ID($fa)); + cell2->setParam(ID::WIDTH, 1); + cell2->setPort(ID::A, State::S0); + cell2->setPort(ID::B, State::S1); + cell2->setPort(ID::C, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix - 1]); + cell2->setPort(ID::X, fa_carry_n[(fa_row_ix * fa_count) + fa_el_ix]); + cell2->setPort(ID::Y, fa_sum_n[(fa_row_ix * fa_count) + fa_el_ix]); + } + } + } + } + + // instantiate the cpa + RTLIL::Wire **cpa_carry = new RTLIL::Wire *[z_sz]; + + for (int cix = 0; cix < z_sz; cix++) { + std::string cpa_cix_name = "cpa_carry_" + std::to_string(cix) + "_"; + cpa_carry[cix] = module->addWire(new_id(cpa_cix_name, __LINE__, ""), 1); + } + + for (int cpa_ix = 0; cpa_ix < z_sz; cpa_ix++) { + + // The end case where we pass the last two summands + // from prior row directly to product output + // without using a cpa cell. This is always + // 0,1 index of prior fa row + if (cpa_ix <= fa_row_count * 2 - 1) { + int fa_row_ix = cpa_ix / 2; + + std::string buf_name = + "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; + auto buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 0]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + + cpa_ix++; + buf_name = "pp_buf_" + std::to_string(cpa_ix) + "_" + "driven_by_fa_row_" + std::to_string(fa_row_ix) + "_"; + buf = module->addCell(new_id(buf_name, __LINE__, ""), ID($pos)); + buf->setPort(ID::A, fa_sum_n[(fa_row_ix * fa_count) + 1]); + buf->setParam(ID::A_WIDTH, 1); + buf->setParam(ID::Y_WIDTH, 1); + buf->setParam(ID::A_SIGNED, true); + buf->setPort(ID::Y, SigSpec(Z, cpa_ix, 1)); + } else { + int offset = fa_row_count * 2; + bool base_case = cpa_ix - offset == 0 ? true : false; + std::string cpa_name = "cpa_" + std::to_string(cpa_ix - offset) + "_"; + + RTLIL::Wire *ci_wire; + if (base_case) + ci_wire = cori_n_int[enc_count - 1]; + else + ci_wire = cpa_carry[cpa_ix - offset - 1]; + + RTLIL::Wire *op_wire = module->addWire(NEW_ID, 1); + BuildHa(cpa_name, fa_sum_n[(fa_row_count - 1) * fa_count + cpa_ix - offset + 2], ci_wire, op_wire, + cpa_carry[cpa_ix - offset]); + module->connect(op_wire, SigSpec(Z, cpa_ix, 1)); + } + } + + // + // instantiate the quadrant 1 cell. This is the upper right + // quadrant which can be realized using non-booth encoded logic. + // + std::string q1_name = "icb_booth_q1_"; + + RTLIL::Wire *pp0_o_int; + RTLIL::Wire *pp1_o_int; + RTLIL::Wire *nxj_o_int; + RTLIL::Wire *cor_o_int; + + BuildBoothQ1(q1_name, + negi_n_int[0], // negi + cori_n_int[0], // cori + + mk_wireFromSigSpec(SigSpec(X, 0, 1)), // x0 + mk_wireFromSigSpec(SigSpec(X, 1, 1)), // x1 + mk_wireFromSigSpec(SigSpec(Y, 0, 1)), // y0 + mk_wireFromSigSpec(SigSpec(Y, 1, 1)), // y1 + + nxj_o_int, cor_o_int, pp0_o_int, pp1_o_int); + + join_wires_with_buffer(pp0_o_int, fa_sum_n[(0 * fa_count) + 0]); + join_wires_with_buffer(pp1_o_int, fa_sum_n[(0 * fa_count) + 1]); + join_wires_with_buffer(cor_o_int, fa_carry_n[(0 * fa_count) + 1]); + join_wires_with_buffer(nxj_o_int, nxj[(0 * dec_count) + 2]); + + delete[] negi_n_int; + delete[] twoi_n_int; + delete[] onei_n_int; + delete[] cori_n_int; + + delete[] fa_sum_n; + delete[] fa_carry_n; + delete[] cpa_carry; + } +}; + +struct BoothPass : public Pass { + BoothPass() : Pass("booth", "Map $mul to booth multipliers") {} + void execute(vector args, RTLIL::Design *design) override + { + (void)args; + log_header(design, + "Executing booth pass. Generating Booth Multiplier structures for signed/unsigned multipliers of 4 bits or more\n"); + for (auto mod : design->selected_modules()) + if (!mod->has_processes_warn()) { + BoothPassWorker worker(mod); + worker.run(); + log_header(design, "Created %d booth multipliers.\n", worker.booth_counter); + } + } +} MultPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/common/prep.cc b/techlibs/common/prep.cc index c354956bcf4..e9176304d48 100644 --- a/techlibs/common/prep.cc +++ b/techlibs/common/prep.cc @@ -189,6 +189,7 @@ struct PrepPass : public ScriptPass run(ifxmode ? "proc -ifx" : "proc"); if (help_mode || flatten) run("flatten", "(if -flatten)"); + run("future"); run(nokeepdc ? "opt_expr" : "opt_expr -keepdc"); run("opt_clean"); run("check"); diff --git a/techlibs/common/simlib.v b/techlibs/common/simlib.v index 9cb68e7252f..fd804786fd8 100644 --- a/techlibs/common/simlib.v +++ b/techlibs/common/simlib.v @@ -1799,6 +1799,24 @@ end endmodule +// -------------------------------------------------------- + +module \$print (EN, TRG, ARGS); + +parameter FORMAT = ""; +parameter ARGS_WIDTH = 0; +parameter PRIORITY = 0; +parameter TRG_ENABLE = 1; + +parameter TRG_WIDTH = 0; +parameter TRG_POLARITY = 0; + +input EN; +input [TRG_WIDTH-1:0] TRG; +input [ARGS_WIDTH-1:0] ARGS; + +endmodule + // -------------------------------------------------------- `ifndef SIMLIB_NOSR @@ -2653,3 +2671,73 @@ endmodule `endif // -------------------------------------------------------- + +module \$set_tag (A, SET, CLR, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +input [WIDTH-1:0] SET; +input [WIDTH-1:0] CLR; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + +module \$get_tag (A, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + +module \$overwrite_tag (A, SET, CLR); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +input [WIDTH-1:0] SET; +input [WIDTH-1:0] CLR; + +endmodule + +// -------------------------------------------------------- + +module \$original_tag (A, Y); + +parameter TAG = ""; +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- + +module \$future_ff (A, Y); + +parameter WIDTH = 0; + +input [WIDTH-1:0] A; +output [WIDTH-1:0] Y; + +assign Y = A; + +endmodule + +// -------------------------------------------------------- diff --git a/techlibs/common/synth.cc b/techlibs/common/synth.cc index 63395c36802..006a3c8dd84 100644 --- a/techlibs/common/synth.cc +++ b/techlibs/common/synth.cc @@ -17,17 +17,16 @@ * */ -#include "kernel/register.h" #include "kernel/celltypes.h" -#include "kernel/rtlil.h" #include "kernel/log.h" +#include "kernel/register.h" +#include "kernel/rtlil.h" USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct SynthPass : public ScriptPass -{ - SynthPass() : ScriptPass("synth", "generic synthesis script") { } +struct SynthPass : public ScriptPass { + SynthPass() : ScriptPass("synth", "generic synthesis script") {} void help() override { @@ -60,6 +59,9 @@ struct SynthPass : public ScriptPass log(" -noabc\n"); log(" do not run abc (as if yosys was compiled without ABC support)\n"); log("\n"); + log(" -booth\n"); + log(" run the booth pass to convert $mul to Booth encoded multipliers"); + log("\n"); log(" -noalumacc\n"); log(" do not run 'alumacc' pass. i.e. keep arithmetic operators in\n"); log(" their direct form ($add, $sub, etc.).\n"); @@ -93,7 +95,8 @@ struct SynthPass : public ScriptPass } string top_module, fsm_opts, memory_opts, abc; - bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap; + bool autotop, flatten, noalumacc, nofsm, noabc, noshare, flowmap, booth; + int lut; void clear_flags() override @@ -110,6 +113,7 @@ struct SynthPass : public ScriptPass noabc = false; noshare = false; flowmap = false; + booth = false; abc = "abc"; } @@ -119,24 +123,23 @@ struct SynthPass : public ScriptPass clear_flags(); size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { + for (argidx = 1; argidx < args.size(); argidx++) { + if (args[argidx] == "-top" && argidx + 1 < args.size()) { top_module = args[++argidx]; continue; } - if (args[argidx] == "-encfile" && argidx+1 < args.size()) { + if (args[argidx] == "-encfile" && argidx + 1 < args.size()) { fsm_opts = " -encfile " + args[++argidx]; continue; } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); + if (args[argidx] == "-run" && argidx + 1 < args.size()) { + size_t pos = args[argidx + 1].find(':'); if (pos == std::string::npos) { run_from = args[++argidx]; run_to = args[argidx]; } else { run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); + run_to = args[argidx].substr(pos + 1); } continue; } @@ -164,6 +167,11 @@ struct SynthPass : public ScriptPass noalumacc = true; continue; } + if (args[argidx] == "-booth") { + booth = true; + continue; + } + if (args[argidx] == "-nordff") { memory_opts += " -nordff"; continue; @@ -206,8 +214,7 @@ struct SynthPass : public ScriptPass void script() override { - if (check_label("begin")) - { + if (check_label("begin")) { if (help_mode) { run("hierarchy -check [-top | -auto-top]"); } else { @@ -221,8 +228,7 @@ struct SynthPass : public ScriptPass } } - if (check_label("coarse")) - { + if (check_label("coarse")) { run("proc"); if (help_mode || flatten) run("flatten", " (if -flatten)"); @@ -240,6 +246,8 @@ struct SynthPass : public ScriptPass run("techmap -map +/cmp2lut.v -map +/cmp2lcu.v", " (if -lut)"); else if (lut) run(stringf("techmap -map +/cmp2lut.v -map +/cmp2lcu.v -D LUT_WIDTH=%d", lut)); + if (booth) + run("booth"); if (!noalumacc) run("alumacc", " (unless -noalumacc)"); if (!noshare) @@ -249,50 +257,40 @@ struct SynthPass : public ScriptPass run("opt_clean"); } - if (check_label("fine")) - { + if (check_label("fine")) { run("opt -fast -full"); run("memory_map"); run("opt -full"); run("techmap"); - if (help_mode) - { + if (help_mode) { run("techmap -map +/gate2lut.v", "(if -noabc and -lut)"); run("clean; opt_lut", " (if -noabc and -lut)"); run("flowmap -maxlut K", " (if -flowmap and -lut)"); - } - else if (noabc && lut) - { + } else if (noabc && lut) { run(stringf("techmap -map +/gate2lut.v -D LUT_WIDTH=%d", lut)); run("clean; opt_lut"); - } - else if (flowmap) - { + } else if (flowmap) { run(stringf("flowmap -maxlut %d", lut)); } run("opt -fast"); if (!noabc && !flowmap) { - #ifdef YOSYS_ENABLE_ABC - if (help_mode) - { +#ifdef YOSYS_ENABLE_ABC + if (help_mode) { run(abc + " -fast", " (unless -noabc, unless -lut)"); run(abc + " -fast -lut k", "(unless -noabc, if -lut)"); - } - else - { + } else { if (lut) run(stringf("%s -fast -lut %d", abc.c_str(), lut)); else run(abc + " -fast"); } run("opt -fast", " (unless -noabc)"); - #endif +#endif } } - if (check_label("check")) - { + if (check_label("check")) { run("hierarchy -check"); run("stat"); run("check"); diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index f9fa79ab9ad..a1c9bfc5233 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,5 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_gsr.o +OBJS += techlibs/ecp5/synth_ecp5.o $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_ff.vh)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_io.vh)) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index 82e23486844..fdc36e55267 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -359,7 +359,7 @@ struct SynthEcp5Pass : public ScriptPass run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("opt_expr -undriven -mux_undef"); run("simplemap"); - run("ecp5_gsr"); + run("lattice_gsr"); run("attrmvcp -copy -attr syn_useioff"); run("opt_clean"); } @@ -404,7 +404,7 @@ struct SynthEcp5Pass : public ScriptPass run("techmap -map +/ecp5/cells_map.v", "(skip if -vpr)"); else if (!vpr) run("techmap -map +/ecp5/cells_map.v"); - run("opt_lut_ins -tech ecp5"); + run("opt_lut_ins -tech lattice"); run("clean"); } diff --git a/techlibs/lattice/Makefile.inc b/techlibs/lattice/Makefile.inc new file mode 100644 index 00000000000..fd9ec2ed5e0 --- /dev/null +++ b/techlibs/lattice/Makefile.inc @@ -0,0 +1,28 @@ + +OBJS += techlibs/lattice/synth_lattice.o +OBJS += techlibs/lattice/lattice_gsr.o + +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_ff.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_io.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_map.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/common_sim.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/ccu2d_sim.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/ccu2c_sim.vh)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_ecp5.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo2.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo3.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_sim_xo3d.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_ecp5.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo2.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/cells_bb_xo3d.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams_map.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/lutrams.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_16kd.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_16kd.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_map_8kc.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/brams_8kc.txt)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2c.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/arith_map_ccu2d.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/latches_map.v)) +$(eval $(call add_share_file,share/lattice,techlibs/lattice/dsp_map_18x18.v)) diff --git a/techlibs/lattice/arith_map_ccu2c.v b/techlibs/lattice/arith_map_ccu2c.v new file mode 100644 index 00000000000..a5efc35613a --- /dev/null +++ b/techlibs/lattice/arith_map_ccu2c.v @@ -0,0 +1,90 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * Copyright (C) 2018 gatecat + * + * 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. + * + */ + +(* techmap_celltype = "$alu" *) +module _80_ccu2c_alu (A, B, CI, BI, X, Y, CO); + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + parameter A_WIDTH = 1; + parameter B_WIDTH = 1; + parameter Y_WIDTH = 1; + + (* force_downto *) + input [A_WIDTH-1:0] A; + (* force_downto *) + input [B_WIDTH-1:0] B; + (* force_downto *) + output [Y_WIDTH-1:0] X, Y; + + input CI, BI; + (* force_downto *) + output [Y_WIDTH-1:0] CO; + + wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; + + (* force_downto *) + wire [Y_WIDTH-1:0] A_buf, B_buf; + \$pos #(.A_SIGNED(A_SIGNED), .A_WIDTH(A_WIDTH), .Y_WIDTH(Y_WIDTH)) A_conv (.A(A), .Y(A_buf)); + \$pos #(.A_SIGNED(B_SIGNED), .A_WIDTH(B_WIDTH), .Y_WIDTH(Y_WIDTH)) B_conv (.A(B), .Y(B_buf)); + + function integer round_up2; + input integer N; + begin + round_up2 = ((N + 1) / 2) * 2; + end + endfunction + + localparam Y_WIDTH2 = round_up2(Y_WIDTH); + + (* force_downto *) + wire [Y_WIDTH2-1:0] AA = A_buf; + (* force_downto *) + wire [Y_WIDTH2-1:0] BB = BI ? ~B_buf : B_buf; + (* force_downto *) + wire [Y_WIDTH2-1:0] BX = B_buf; + (* force_downto *) + wire [Y_WIDTH2-1:0] C = {CO, CI}; + (* force_downto *) + wire [Y_WIDTH2-1:0] FCO, Y1; + + genvar i; + generate for (i = 0; i < Y_WIDTH2; i = i + 2) begin:slice + CCU2C #( + .INIT0(16'b1001011010101010), + .INIT1(16'b1001011010101010), + .INJECT1_0("NO"), + .INJECT1_1("NO") + ) ccu2c_i ( + .CIN(C[i]), + .A0(AA[i]), .B0(BX[i]), .C0(BI), .D0(1'b1), + .A1(AA[i+1]), .B1(BX[i+1]), .C1(BI), .D1(1'b1), + .S0(Y[i]), .S1(Y1[i]), + .COUT(FCO[i]) + ); + + assign CO[i] = (AA[i] && BB[i]) || (C[i] && (AA[i] || BB[i])); + if (i+1 < Y_WIDTH) begin + assign CO[i+1] = FCO[i]; + assign Y[i+1] = Y1[i]; + end + end endgenerate + + assign X = AA ^ BB; +endmodule diff --git a/techlibs/machxo2/arith_map.v b/techlibs/lattice/arith_map_ccu2d.v similarity index 98% rename from techlibs/machxo2/arith_map.v rename to techlibs/lattice/arith_map_ccu2d.v index ab4a6b1da6c..31e4afe09a1 100644 --- a/techlibs/machxo2/arith_map.v +++ b/techlibs/lattice/arith_map_ccu2d.v @@ -19,7 +19,7 @@ */ (* techmap_celltype = "$alu" *) -module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); +module _80_ccu2d_alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; parameter B_SIGNED = 0; parameter A_WIDTH = 1; diff --git a/techlibs/lattice/brams_16kd.txt b/techlibs/lattice/brams_16kd.txt new file mode 100644 index 00000000000..ccdf490501f --- /dev/null +++ b/techlibs/lattice/brams_16kd.txt @@ -0,0 +1,52 @@ +ram block $__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 $__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/machxo2/brams.txt b/techlibs/lattice/brams_8kc.txt similarity index 100% rename from techlibs/machxo2/brams.txt rename to techlibs/lattice/brams_8kc.txt diff --git a/techlibs/lattice/brams_map_16kd.v b/techlibs/lattice/brams_map_16kd.v new file mode 100644 index 00000000000..da4d8041770 --- /dev/null +++ b/techlibs/lattice/brams_map_16kd.v @@ -0,0 +1,489 @@ +module $__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 $__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 diff --git a/techlibs/machxo2/brams_map.v b/techlibs/lattice/brams_map_8kc.v similarity index 100% rename from techlibs/machxo2/brams_map.v rename to techlibs/lattice/brams_map_8kc.v diff --git a/techlibs/lattice/ccu2c_sim.vh b/techlibs/lattice/ccu2c_sim.vh new file mode 100644 index 00000000000..d9eb69ab455 --- /dev/null +++ b/techlibs/lattice/ccu2c_sim.vh @@ -0,0 +1,61 @@ +// --------------------------------------- +(* abc9_box, lib_whitebox *) +module CCU2C( + (* abc9_carry *) + input CIN, + input A0, B0, C0, D0, A1, B1, C1, D1, + output S0, S1, + (* abc9_carry *) + output COUT +); + parameter [15:0] INIT0 = 16'h0000; + parameter [15:0] INIT1 = 16'h0000; + parameter INJECT1_0 = "YES"; + parameter INJECT1_1 = "YES"; + + // First half + wire LUT4_0, LUT2_0; + LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); + LUT2 #(.INIT(INIT0[3:0])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); + wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; + assign S0 = LUT4_0 ^ gated_cin_0; + + wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0; + wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN); + + // Second half + wire LUT4_1, LUT2_1; + LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); + LUT2 #(.INIT(INIT1[3:0])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); + wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; + assign S1 = LUT4_1 ^ gated_cin_1; + + wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1; + assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0); + + specify + (A0 => S0) = 379; + (B0 => S0) = 379; + (C0 => S0) = 275; + (D0 => S0) = 141; + (CIN => S0) = 257; + (A0 => S1) = 630; + (B0 => S1) = 630; + (C0 => S1) = 526; + (D0 => S1) = 392; + (A1 => S1) = 379; + (B1 => S1) = 379; + (C1 => S1) = 275; + (D1 => S1) = 141; + (CIN => S1) = 273; + (A0 => COUT) = 516; + (B0 => COUT) = 516; + (C0 => COUT) = 412; + (D0 => COUT) = 278; + (A1 => COUT) = 516; + (B1 => COUT) = 516; + (C1 => COUT) = 412; + (D1 => COUT) = 278; + (CIN => COUT) = 43; + endspecify +endmodule diff --git a/techlibs/lattice/ccu2d_sim.vh b/techlibs/lattice/ccu2d_sim.vh new file mode 100644 index 00000000000..5b9c95cc9ef --- /dev/null +++ b/techlibs/lattice/ccu2d_sim.vh @@ -0,0 +1,33 @@ +// --------------------------------------- +(* lib_whitebox *) +module CCU2D ( + input CIN, + input A0, B0, C0, D0, A1, B1, C1, D1, + output S0, S1, + output COUT +); + parameter [15:0] INIT0 = 16'h0000; + parameter [15:0] INIT1 = 16'h0000; + parameter INJECT1_0 = "YES"; + parameter INJECT1_1 = "YES"; + + // First half + wire LUT4_0, LUT2_0; + LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); + LUT2 #(.INIT(~INIT0[15:12])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); + wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; + assign S0 = LUT4_0 ^ gated_cin_0; + + wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0; + wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN); + + // Second half + wire LUT4_1, LUT2_1; + LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); + LUT2 #(.INIT(~INIT1[15:12])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); + wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; + assign S1 = LUT4_1 ^ gated_cin_1; + + wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1; + assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0); +endmodule diff --git a/techlibs/lattice/cells_bb_ecp5.v b/techlibs/lattice/cells_bb_ecp5.v new file mode 100644 index 00000000000..fc22495e2ff --- /dev/null +++ b/techlibs/lattice/cells_bb_ecp5.v @@ -0,0 +1,2175 @@ +// Created by cells_xtra.py from Lattice models + +(* blackbox *) (* keep *) +module GSR (...); + input GSR; +endmodule + +(* blackbox *) +module PUR (...); + parameter RST_PULSE = 1; + input PUR; +endmodule + +(* blackbox *) (* keep *) +module SGSR (...); + input GSR; + input CLK; +endmodule + +(* blackbox *) +module DP16KD (...); + parameter DATA_WIDTH_A = 18; + parameter DATA_WIDTH_B = 18; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + parameter GSR = "ENABLED"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_DATA = "STATIC"; + input DIA17; + input DIA16; + input DIA15; + input DIA14; + input DIA13; + input DIA12; + input DIA11; + input DIA10; + input DIA9; + input DIA8; + input DIA7; + input DIA6; + input DIA5; + input DIA4; + input DIA3; + input DIA2; + input DIA1; + input DIA0; + input ADA13; + input ADA12; + input ADA11; + input ADA10; + input ADA9; + input ADA8; + input ADA7; + input ADA6; + input ADA5; + input ADA4; + input ADA3; + input ADA2; + input ADA1; + input ADA0; + input CEA; + input OCEA; + input CLKA; + input WEA; + input CSA2; + input CSA1; + input CSA0; + input RSTA; + input DIB17; + input DIB16; + input DIB15; + input DIB14; + input DIB13; + input DIB12; + input DIB11; + input DIB10; + input DIB9; + input DIB8; + input DIB7; + input DIB6; + input DIB5; + input DIB4; + input DIB3; + input DIB2; + input DIB1; + input DIB0; + input ADB13; + input ADB12; + input ADB11; + input ADB10; + input ADB9; + input ADB8; + input ADB7; + input ADB6; + input ADB5; + input ADB4; + input ADB3; + input ADB2; + input ADB1; + input ADB0; + input CEB; + input OCEB; + input CLKB; + input WEB; + input CSB2; + input CSB1; + input CSB0; + input RSTB; + output DOA17; + output DOA16; + output DOA15; + output DOA14; + output DOA13; + output DOA12; + output DOA11; + output DOA10; + output DOA9; + output DOA8; + output DOA7; + output DOA6; + output DOA5; + output DOA4; + output DOA3; + output DOA2; + output DOA1; + output DOA0; + output DOB17; + output DOB16; + output DOB15; + output DOB14; + output DOB13; + output DOB12; + output DOB11; + output DOB10; + output DOB9; + output DOB8; + output DOB7; + output DOB6; + output DOB5; + output DOB4; + output DOB3; + output DOB2; + output DOB1; + output DOB0; +endmodule + +(* blackbox *) +module PDPW16KD (...); + parameter DATA_WIDTH_W = 36; + parameter DATA_WIDTH_R = 36; + parameter GSR = "ENABLED"; + parameter REGMODE = "NOREG"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CSDECODE_W = "0b000"; + parameter CSDECODE_R = "0b000"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_20 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_21 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_22 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_23 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_24 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_25 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_26 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_27 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_28 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_29 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_2F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_30 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_31 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_32 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_33 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_34 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_35 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_36 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_37 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_38 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_39 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_DATA = "STATIC"; + input DI35; + input DI34; + input DI33; + input DI32; + input DI31; + input DI30; + input DI29; + input DI28; + input DI27; + input DI26; + input DI25; + input DI24; + input DI23; + input DI22; + input DI21; + input DI20; + input DI19; + input DI18; + input DI17; + input DI16; + input DI15; + input DI14; + input DI13; + input DI12; + input DI11; + input DI10; + input DI9; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input ADW8; + input ADW7; + input ADW6; + input ADW5; + input ADW4; + input ADW3; + input ADW2; + input ADW1; + input ADW0; + input BE3; + input BE2; + input BE1; + input BE0; + input CEW; + input CLKW; + input CSW2; + input CSW1; + input CSW0; + input ADR13; + input ADR12; + input ADR11; + input ADR10; + input ADR9; + input ADR8; + input ADR7; + input ADR6; + input ADR5; + input ADR4; + input ADR3; + input ADR2; + input ADR1; + input ADR0; + input CER; + input OCER; + input CLKR; + input CSR2; + input CSR1; + input CSR0; + input RST; + output DO35; + output DO34; + output DO33; + output DO32; + output DO31; + output DO30; + output DO29; + output DO28; + output DO27; + output DO26; + output DO25; + output DO24; + output DO23; + output DO22; + output DO21; + output DO20; + output DO19; + output DO18; + output DO17; + output DO16; + output DO15; + output DO14; + output DO13; + output DO12; + output DO11; + output DO10; + output DO9; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module MULT18X18D (...); + parameter REG_INPUTA_CLK = "NONE"; + parameter REG_INPUTA_CE = "CE0"; + parameter REG_INPUTA_RST = "RST0"; + parameter REG_INPUTB_CLK = "NONE"; + parameter REG_INPUTB_CE = "CE0"; + parameter REG_INPUTB_RST = "RST0"; + parameter REG_INPUTC_CLK = "NONE"; + parameter REG_INPUTC_CE = "CE0"; + parameter REG_INPUTC_RST = "RST0"; + parameter REG_PIPELINE_CLK = "NONE"; + parameter REG_PIPELINE_CE = "CE0"; + parameter REG_PIPELINE_RST = "RST0"; + parameter REG_OUTPUT_CLK = "NONE"; + parameter REG_OUTPUT_CE = "CE0"; + parameter REG_OUTPUT_RST = "RST0"; + parameter CLK0_DIV = "ENABLED"; + parameter CLK1_DIV = "ENABLED"; + parameter CLK2_DIV = "ENABLED"; + parameter CLK3_DIV = "ENABLED"; + parameter HIGHSPEED_CLK = "NONE"; + parameter GSR = "ENABLED"; + parameter CAS_MATCH_REG = "FALSE"; + parameter SOURCEB_MODE = "B_SHIFT"; + parameter MULT_BYPASS = "DISABLED"; + parameter RESETMODE = "SYNC"; + input A17; + input A16; + input A15; + input A14; + input A13; + input A12; + input A11; + input A10; + input A9; + input A8; + input A7; + input A6; + input A5; + input A4; + input A3; + input A2; + input A1; + input A0; + input B17; + input B16; + input B15; + input B14; + input B13; + input B12; + input B11; + input B10; + input B9; + input B8; + input B7; + input B6; + input B5; + input B4; + input B3; + input B2; + input B1; + input B0; + input C17; + input C16; + input C15; + input C14; + input C13; + input C12; + input C11; + input C10; + input C9; + input C8; + input C7; + input C6; + input C5; + input C4; + input C3; + input C2; + input C1; + input C0; + input SIGNEDA; + input SIGNEDB; + input SOURCEA; + input SOURCEB; + input CLK3; + input CLK2; + input CLK1; + input CLK0; + input CE3; + input CE2; + input CE1; + input CE0; + input RST3; + input RST2; + input RST1; + input RST0; + input SRIA17; + input SRIA16; + input SRIA15; + input SRIA14; + input SRIA13; + input SRIA12; + input SRIA11; + input SRIA10; + input SRIA9; + input SRIA8; + input SRIA7; + input SRIA6; + input SRIA5; + input SRIA4; + input SRIA3; + input SRIA2; + input SRIA1; + input SRIA0; + input SRIB17; + input SRIB16; + input SRIB15; + input SRIB14; + input SRIB13; + input SRIB12; + input SRIB11; + input SRIB10; + input SRIB9; + input SRIB8; + input SRIB7; + input SRIB6; + input SRIB5; + input SRIB4; + input SRIB3; + input SRIB2; + input SRIB1; + input SRIB0; + output SROA17; + output SROA16; + output SROA15; + output SROA14; + output SROA13; + output SROA12; + output SROA11; + output SROA10; + output SROA9; + output SROA8; + output SROA7; + output SROA6; + output SROA5; + output SROA4; + output SROA3; + output SROA2; + output SROA1; + output SROA0; + output SROB17; + output SROB16; + output SROB15; + output SROB14; + output SROB13; + output SROB12; + output SROB11; + output SROB10; + output SROB9; + output SROB8; + output SROB7; + output SROB6; + output SROB5; + output SROB4; + output SROB3; + output SROB2; + output SROB1; + output SROB0; + output ROA17; + output ROA16; + output ROA15; + output ROA14; + output ROA13; + output ROA12; + output ROA11; + output ROA10; + output ROA9; + output ROA8; + output ROA7; + output ROA6; + output ROA5; + output ROA4; + output ROA3; + output ROA2; + output ROA1; + output ROA0; + output ROB17; + output ROB16; + output ROB15; + output ROB14; + output ROB13; + output ROB12; + output ROB11; + output ROB10; + output ROB9; + output ROB8; + output ROB7; + output ROB6; + output ROB5; + output ROB4; + output ROB3; + output ROB2; + output ROB1; + output ROB0; + output ROC17; + output ROC16; + output ROC15; + output ROC14; + output ROC13; + output ROC12; + output ROC11; + output ROC10; + output ROC9; + output ROC8; + output ROC7; + output ROC6; + output ROC5; + output ROC4; + output ROC3; + output ROC2; + output ROC1; + output ROC0; + output P35; + output P34; + output P33; + output P32; + output P31; + output P30; + output P29; + output P28; + output P27; + output P26; + output P25; + output P24; + output P23; + output P22; + output P21; + output P20; + output P19; + output P18; + output P17; + output P16; + output P15; + output P14; + output P13; + output P12; + output P11; + output P10; + output P9; + output P8; + output P7; + output P6; + output P5; + output P4; + output P3; + output P2; + output P1; + output P0; + output SIGNEDP; +endmodule + +(* blackbox *) +module ALU54B (...); + parameter REG_INPUTC0_CLK = "NONE"; + parameter REG_INPUTC0_CE = "CE0"; + parameter REG_INPUTC0_RST = "RST0"; + parameter REG_INPUTC1_CLK = "NONE"; + parameter REG_INPUTC1_CE = "CE0"; + parameter REG_INPUTC1_RST = "RST0"; + parameter REG_OPCODEOP0_0_CLK = "NONE"; + parameter REG_OPCODEOP0_0_CE = "CE0"; + parameter REG_OPCODEOP0_0_RST = "RST0"; + parameter REG_OPCODEOP1_0_CLK = "NONE"; + parameter REG_OPCODEOP0_1_CLK = "NONE"; + parameter REG_OPCODEOP0_1_CE = "CE0"; + parameter REG_OPCODEOP0_1_RST = "RST0"; + parameter REG_OPCODEOP1_1_CLK = "NONE"; + parameter REG_OPCODEIN_0_CLK = "NONE"; + parameter REG_OPCODEIN_0_CE = "CE0"; + parameter REG_OPCODEIN_0_RST = "RST0"; + parameter REG_OPCODEIN_1_CLK = "NONE"; + parameter REG_OPCODEIN_1_CE = "CE0"; + parameter REG_OPCODEIN_1_RST = "RST0"; + parameter REG_OUTPUT0_CLK = "NONE"; + parameter REG_OUTPUT0_CE = "CE0"; + parameter REG_OUTPUT0_RST = "RST0"; + parameter REG_OUTPUT1_CLK = "NONE"; + parameter REG_OUTPUT1_CE = "CE0"; + parameter REG_OUTPUT1_RST = "RST0"; + parameter REG_FLAG_CLK = "NONE"; + parameter REG_FLAG_CE = "CE0"; + parameter REG_FLAG_RST = "RST0"; + parameter MCPAT_SOURCE = "STATIC"; + parameter MASKPAT_SOURCE = "STATIC"; + parameter MASK01 = "0x00000000000000"; + parameter REG_INPUTCFB_CLK = "NONE"; + parameter REG_INPUTCFB_CE = "CE0"; + parameter REG_INPUTCFB_RST = "RST0"; + parameter CLK0_DIV = "ENABLED"; + parameter CLK1_DIV = "ENABLED"; + parameter CLK2_DIV = "ENABLED"; + parameter CLK3_DIV = "ENABLED"; + parameter MCPAT = "0x00000000000000"; + parameter MASKPAT = "0x00000000000000"; + parameter RNDPAT = "0x00000000000000"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter MULT9_MODE = "DISABLED"; + parameter FORCE_ZERO_BARREL_SHIFT = "DISABLED"; + parameter LEGACY = "DISABLED"; + input CE3; + input CE2; + input CE1; + input CE0; + input CLK3; + input CLK2; + input CLK1; + input CLK0; + input RST3; + input RST2; + input RST1; + input RST0; + input SIGNEDIA; + input SIGNEDIB; + input SIGNEDCIN; + input A35; + input A34; + input A33; + input A32; + input A31; + input A30; + input A29; + input A28; + input A27; + input A26; + input A25; + input A24; + input A23; + input A22; + input A21; + input A20; + input A19; + input A18; + input A17; + input A16; + input A15; + input A14; + input A13; + input A12; + input A11; + input A10; + input A9; + input A8; + input A7; + input A6; + input A5; + input A4; + input A3; + input A2; + input A1; + input A0; + input B35; + input B34; + input B33; + input B32; + input B31; + input B30; + input B29; + input B28; + input B27; + input B26; + input B25; + input B24; + input B23; + input B22; + input B21; + input B20; + input B19; + input B18; + input B17; + input B16; + input B15; + input B14; + input B13; + input B12; + input B11; + input B10; + input B9; + input B8; + input B7; + input B6; + input B5; + input B4; + input B3; + input B2; + input B1; + input B0; + input C53; + input C52; + input C51; + input C50; + input C49; + input C48; + input C47; + input C46; + input C45; + input C44; + input C43; + input C42; + input C41; + input C40; + input C39; + input C38; + input C37; + input C36; + input C35; + input C34; + input C33; + input C32; + input C31; + input C30; + input C29; + input C28; + input C27; + input C26; + input C25; + input C24; + input C23; + input C22; + input C21; + input C20; + input C19; + input C18; + input C17; + input C16; + input C15; + input C14; + input C13; + input C12; + input C11; + input C10; + input C9; + input C8; + input C7; + input C6; + input C5; + input C4; + input C3; + input C2; + input C1; + input C0; + input CFB53; + input CFB52; + input CFB51; + input CFB50; + input CFB49; + input CFB48; + input CFB47; + input CFB46; + input CFB45; + input CFB44; + input CFB43; + input CFB42; + input CFB41; + input CFB40; + input CFB39; + input CFB38; + input CFB37; + input CFB36; + input CFB35; + input CFB34; + input CFB33; + input CFB32; + input CFB31; + input CFB30; + input CFB29; + input CFB28; + input CFB27; + input CFB26; + input CFB25; + input CFB24; + input CFB23; + input CFB22; + input CFB21; + input CFB20; + input CFB19; + input CFB18; + input CFB17; + input CFB16; + input CFB15; + input CFB14; + input CFB13; + input CFB12; + input CFB11; + input CFB10; + input CFB9; + input CFB8; + input CFB7; + input CFB6; + input CFB5; + input CFB4; + input CFB3; + input CFB2; + input CFB1; + input CFB0; + input MA35; + input MA34; + input MA33; + input MA32; + input MA31; + input MA30; + input MA29; + input MA28; + input MA27; + input MA26; + input MA25; + input MA24; + input MA23; + input MA22; + input MA21; + input MA20; + input MA19; + input MA18; + input MA17; + input MA16; + input MA15; + input MA14; + input MA13; + input MA12; + input MA11; + input MA10; + input MA9; + input MA8; + input MA7; + input MA6; + input MA5; + input MA4; + input MA3; + input MA2; + input MA1; + input MA0; + input MB35; + input MB34; + input MB33; + input MB32; + input MB31; + input MB30; + input MB29; + input MB28; + input MB27; + input MB26; + input MB25; + input MB24; + input MB23; + input MB22; + input MB21; + input MB20; + input MB19; + input MB18; + input MB17; + input MB16; + input MB15; + input MB14; + input MB13; + input MB12; + input MB11; + input MB10; + input MB9; + input MB8; + input MB7; + input MB6; + input MB5; + input MB4; + input MB3; + input MB2; + input MB1; + input MB0; + input CIN53; + input CIN52; + input CIN51; + input CIN50; + input CIN49; + input CIN48; + input CIN47; + input CIN46; + input CIN45; + input CIN44; + input CIN43; + input CIN42; + input CIN41; + input CIN40; + input CIN39; + input CIN38; + input CIN37; + input CIN36; + input CIN35; + input CIN34; + input CIN33; + input CIN32; + input CIN31; + input CIN30; + input CIN29; + input CIN28; + input CIN27; + input CIN26; + input CIN25; + input CIN24; + input CIN23; + input CIN22; + input CIN21; + input CIN20; + input CIN19; + input CIN18; + input CIN17; + input CIN16; + input CIN15; + input CIN14; + input CIN13; + input CIN12; + input CIN11; + input CIN10; + input CIN9; + input CIN8; + input CIN7; + input CIN6; + input CIN5; + input CIN4; + input CIN3; + input CIN2; + input CIN1; + input CIN0; + input OP10; + input OP9; + input OP8; + input OP7; + input OP6; + input OP5; + input OP4; + input OP3; + input OP2; + input OP1; + input OP0; + output R53; + output R52; + output R51; + output R50; + output R49; + output R48; + output R47; + output R46; + output R45; + output R44; + output R43; + output R42; + output R41; + output R40; + output R39; + output R38; + output R37; + output R36; + output R35; + output R34; + output R33; + output R32; + output R31; + output R30; + output R29; + output R28; + output R27; + output R26; + output R25; + output R24; + output R23; + output R22; + output R21; + output R20; + output R19; + output R18; + output R17; + output R16; + output R15; + output R14; + output R13; + output R12; + output R11; + output R10; + output R9; + output R8; + output R7; + output R6; + output R5; + output R4; + output R3; + output R2; + output R1; + output R0; + output CO53; + output CO52; + output CO51; + output CO50; + output CO49; + output CO48; + output CO47; + output CO46; + output CO45; + output CO44; + output CO43; + output CO42; + output CO41; + output CO40; + output CO39; + output CO38; + output CO37; + output CO36; + output CO35; + output CO34; + output CO33; + output CO32; + output CO31; + output CO30; + output CO29; + output CO28; + output CO27; + output CO26; + output CO25; + output CO24; + output CO23; + output CO22; + output CO21; + output CO20; + output CO19; + output CO18; + output CO17; + output CO16; + output CO15; + output CO14; + output CO13; + output CO12; + output CO11; + output CO10; + output CO9; + output CO8; + output CO7; + output CO6; + output CO5; + output CO4; + output CO3; + output CO2; + output CO1; + output CO0; + output EQZ; + output EQZM; + output EQOM; + output EQPAT; + output EQPATB; + output OVER; + output UNDER; + output OVERUNDER; + output SIGNEDR; +endmodule + +(* blackbox *) +module CLKDIVF (...); + parameter GSR = "DISABLED"; + parameter DIV = "2.0"; + input CLKI; + input RST; + input ALIGNWD; + output CDIVX; +endmodule + +(* blackbox *) +module PCSCLKDIV (...); + parameter GSR = "DISABLED"; + input CLKI; + input RST; + input SEL2; + input SEL1; + input SEL0; + output CDIV1; + output CDIVX; +endmodule + +(* blackbox *) +module DCSC (...); + parameter DCSMODE = "POS"; + input CLK1; + input CLK0; + input SEL1; + input SEL0; + input MODESEL; + output DCSOUT; +endmodule + +(* blackbox *) +module DCCA (...); + input CLKI; + input CE; + output CLKO; +endmodule + +(* blackbox *) +module ECLKSYNCB (...); + input ECLKI; + input STOP; + output ECLKO; +endmodule + +(* blackbox *) +module ECLKBRIDGECS (...); + input CLK0; + input CLK1; + input SEL; + output ECSOUT; +endmodule + +(* blackbox *) +module DELAYF (...); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; + input A; + input LOADN; + input MOVE; + input DIRECTION; + output Z; + output CFLAG; +endmodule + +(* blackbox *) +module DELAYG (...); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; + input A; + output Z; +endmodule + +(* blackbox *) (* keep *) +module USRMCLK (...); + input USRMCLKI; + input USRMCLKTS; +endmodule + +(* blackbox *) +module DQSBUFM (...); + parameter DQS_LI_DEL_VAL = 4; + parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LO_DEL_VAL = 0; + parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; + parameter GSR = "ENABLED"; + input DQSI; + input READ1; + input READ0; + input READCLKSEL2; + input READCLKSEL1; + input READCLKSEL0; + input DDRDEL; + input ECLK; + input SCLK; + input RST; + input DYNDELAY7; + input DYNDELAY6; + input DYNDELAY5; + input DYNDELAY4; + input DYNDELAY3; + input DYNDELAY2; + input DYNDELAY1; + input DYNDELAY0; + input PAUSE; + input RDLOADN; + input RDMOVE; + input RDDIRECTION; + input WRLOADN; + input WRMOVE; + input WRDIRECTION; + output DQSR90; + output DQSW; + output DQSW270; + output RDPNTR2; + output RDPNTR1; + output RDPNTR0; + output WRPNTR2; + output WRPNTR1; + output WRPNTR0; + output DATAVALID; + output BURSTDET; + output RDCFLAG; + output WRCFLAG; +endmodule + +(* blackbox *) +module DDRDLLA (...); + parameter FORCE_MAX_DELAY = "NO"; + parameter GSR = "ENABLED"; + input CLK; + input RST; + input UDDCNTLN; + input FREEZE; + output DDRDEL; + output LOCK; + output DCNTL7; + output DCNTL6; + output DCNTL5; + output DCNTL4; + output DCNTL3; + output DCNTL2; + output DCNTL1; + output DCNTL0; +endmodule + +(* blackbox *) +module DLLDELD (...); + input A; + input DDRDEL; + input LOADN; + input MOVE; + input DIRECTION; + output Z; + output CFLAG; +endmodule + +(* blackbox *) +module IDDRX1F (...); + parameter GSR = "ENABLED"; + input D; + input SCLK; + input RST; + output Q0; + output Q1; +endmodule + +(* blackbox *) +module IDDRX2F (...); + parameter GSR = "ENABLED"; + input D; + input SCLK; + input ECLK; + input RST; + input ALIGNWD; + output Q3; + output Q2; + output Q1; + output Q0; +endmodule + +(* blackbox *) +module IDDR71B (...); + parameter GSR = "ENABLED"; + input D; + input SCLK; + input ECLK; + input RST; + input ALIGNWD; + output Q6; + output Q5; + output Q4; + output Q3; + output Q2; + output Q1; + output Q0; +endmodule + +(* blackbox *) +module IDDRX2DQA (...); + parameter GSR = "ENABLED"; + input SCLK; + input ECLK; + input DQSR90; + input D; + input RST; + input RDPNTR2; + input RDPNTR1; + input RDPNTR0; + input WRPNTR2; + input WRPNTR1; + input WRPNTR0; + output Q3; + output Q2; + output Q1; + output Q0; + output QWL; +endmodule + +(* blackbox *) +module ODDRX1F (...); + parameter GSR = "ENABLED"; + input SCLK; + input RST; + input D0; + input D1; + output Q; +endmodule + +(* blackbox *) +module ODDRX2F (...); + parameter GSR = "ENABLED"; + input SCLK; + input ECLK; + input RST; + input D3; + input D2; + input D1; + input D0; + output Q; +endmodule + +(* blackbox *) +module ODDR71B (...); + parameter GSR = "ENABLED"; + input SCLK; + input ECLK; + input RST; + input D6; + input D5; + input D4; + input D3; + input D2; + input D1; + input D0; + output Q; +endmodule + +(* blackbox *) +module OSHX2A (...); + parameter GSR = "ENABLED"; + input D1; + input D0; + input SCLK; + input ECLK; + input RST; + output Q; +endmodule + +(* blackbox *) +module TSHX2DQA (...); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; + input T1; + input T0; + input SCLK; + input ECLK; + input DQSW270; + input RST; + output Q; +endmodule + +(* blackbox *) +module TSHX2DQSA (...); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; + input T1; + input T0; + input SCLK; + input ECLK; + input DQSW; + input RST; + output Q; +endmodule + +(* blackbox *) +module ODDRX2DQA (...); + parameter GSR = "ENABLED"; + input D3; + input D2; + input D1; + input D0; + input DQSW270; + input SCLK; + input ECLK; + input RST; + output Q; +endmodule + +(* blackbox *) +module ODDRX2DQSB (...); + parameter GSR = "ENABLED"; + input D3; + input D2; + input D1; + input D0; + input SCLK; + input ECLK; + input DQSW; + input RST; + output Q; +endmodule + +(* blackbox *) +module EHXPLLL (...); + parameter CLKI_DIV = 1; + parameter CLKFB_DIV = 1; + parameter CLKOP_DIV = 8; + parameter CLKOS_DIV = 8; + parameter CLKOS2_DIV = 8; + parameter CLKOS3_DIV = 8; + parameter CLKOP_ENABLE = "ENABLED"; + parameter CLKOS_ENABLE = "DISABLED"; + parameter CLKOS2_ENABLE = "DISABLED"; + parameter CLKOS3_ENABLE = "DISABLED"; + parameter CLKOP_CPHASE = 0; + parameter CLKOS_CPHASE = 0; + parameter CLKOS2_CPHASE = 0; + parameter CLKOS3_CPHASE = 0; + parameter CLKOP_FPHASE = 0; + parameter CLKOS_FPHASE = 0; + parameter CLKOS2_FPHASE = 0; + parameter CLKOS3_FPHASE = 0; + parameter FEEDBK_PATH = "CLKOP"; + parameter CLKOP_TRIM_POL = "RISING"; + parameter CLKOP_TRIM_DELAY = 0; + parameter CLKOS_TRIM_POL = "RISING"; + parameter CLKOS_TRIM_DELAY = 0; + parameter OUTDIVIDER_MUXA = "DIVA"; + parameter OUTDIVIDER_MUXB = "DIVB"; + parameter OUTDIVIDER_MUXC = "DIVC"; + parameter OUTDIVIDER_MUXD = "DIVD"; + parameter PLL_LOCK_MODE = 0; + parameter PLL_LOCK_DELAY = 200; + parameter STDBY_ENABLE = "DISABLED"; + parameter REFIN_RESET = "DISABLED"; + parameter SYNC_ENABLE = "DISABLED"; + parameter INT_LOCK_STICKY = "ENABLED"; + parameter DPHASE_SOURCE = "DISABLED"; + parameter PLLRST_ENA = "DISABLED"; + parameter INTFB_WAKE = "DISABLED"; + input CLKI; + input CLKFB; + input PHASESEL1; + input PHASESEL0; + input PHASEDIR; + input PHASESTEP; + input PHASELOADREG; + input STDBY; + input PLLWAKESYNC; + input RST; + input ENCLKOP; + input ENCLKOS; + input ENCLKOS2; + input ENCLKOS3; + output CLKOP; + output CLKOS; + output CLKOS2; + output CLKOS3; + output LOCK; + output INTLOCK; + output REFCLK; + output CLKINTFB; +endmodule + +(* blackbox *) +module DTR (...); + parameter DTR_TEMP = 25; + input STARTPULSE; + output DTROUT7; + output DTROUT6; + output DTROUT5; + output DTROUT4; + output DTROUT3; + output DTROUT2; + output DTROUT1; + output DTROUT0; +endmodule + +(* blackbox *) +module OSCG (...); + parameter DIV = 128; + output OSC; +endmodule + +(* blackbox *) +module EXTREFB (...); + parameter REFCK_PWDNB = "DONTCARE"; + parameter REFCK_RTERM = "DONTCARE"; + parameter REFCK_DCBIAS_EN = "DONTCARE"; + (* iopad_external_pin *) + input REFCLKP; + (* iopad_external_pin *) + input REFCLKN; + output REFCLKO; +endmodule + +(* blackbox *) (* keep *) +module JTAGG (...); + parameter ER1 = "ENABLED"; + parameter ER2 = "ENABLED"; + (* iopad_external_pin *) + input TCK; + (* iopad_external_pin *) + input TMS; + (* iopad_external_pin *) + input TDI; + input JTDO2; + input JTDO1; + (* iopad_external_pin *) + output TDO; + output JTDI; + output JTCK; + output JRTI2; + output JRTI1; + output JSHIFT; + output JUPDATE; + output JRSTN; + output JCE2; + output JCE1; +endmodule + +(* blackbox *) (* keep *) +module DCUA (...); + parameter D_MACROPDB = "DONTCARE"; + parameter D_IB_PWDNB = "DONTCARE"; + parameter D_XGE_MODE = "DONTCARE"; + parameter D_LOW_MARK = "DONTCARE"; + parameter D_HIGH_MARK = "DONTCARE"; + parameter D_BUS8BIT_SEL = "DONTCARE"; + parameter D_CDR_LOL_SET = "DONTCARE"; + parameter D_BITCLK_LOCAL_EN = "DONTCARE"; + parameter D_BITCLK_ND_EN = "DONTCARE"; + parameter D_BITCLK_FROM_ND_EN = "DONTCARE"; + parameter D_SYNC_LOCAL_EN = "DONTCARE"; + parameter D_SYNC_ND_EN = "DONTCARE"; + parameter CH0_UC_MODE = "DONTCARE"; + parameter CH1_UC_MODE = "DONTCARE"; + parameter CH0_PCIE_MODE = "DONTCARE"; + parameter CH1_PCIE_MODE = "DONTCARE"; + parameter CH0_RIO_MODE = "DONTCARE"; + parameter CH1_RIO_MODE = "DONTCARE"; + parameter CH0_WA_MODE = "DONTCARE"; + parameter CH1_WA_MODE = "DONTCARE"; + parameter CH0_INVERT_RX = "DONTCARE"; + parameter CH1_INVERT_RX = "DONTCARE"; + parameter CH0_INVERT_TX = "DONTCARE"; + parameter CH1_INVERT_TX = "DONTCARE"; + parameter CH0_PRBS_SELECTION = "DONTCARE"; + parameter CH1_PRBS_SELECTION = "DONTCARE"; + parameter CH0_GE_AN_ENABLE = "DONTCARE"; + parameter CH1_GE_AN_ENABLE = "DONTCARE"; + parameter CH0_PRBS_LOCK = "DONTCARE"; + parameter CH1_PRBS_LOCK = "DONTCARE"; + parameter CH0_PRBS_ENABLE = "DONTCARE"; + parameter CH1_PRBS_ENABLE = "DONTCARE"; + parameter CH0_ENABLE_CG_ALIGN = "DONTCARE"; + parameter CH1_ENABLE_CG_ALIGN = "DONTCARE"; + parameter CH0_TX_GEAR_MODE = "DONTCARE"; + parameter CH1_TX_GEAR_MODE = "DONTCARE"; + parameter CH0_RX_GEAR_MODE = "DONTCARE"; + parameter CH1_RX_GEAR_MODE = "DONTCARE"; + parameter CH0_PCS_DET_TIME_SEL = "DONTCARE"; + parameter CH1_PCS_DET_TIME_SEL = "DONTCARE"; + parameter CH0_PCIE_EI_EN = "DONTCARE"; + parameter CH1_PCIE_EI_EN = "DONTCARE"; + parameter CH0_TX_GEAR_BYPASS = "DONTCARE"; + parameter CH1_TX_GEAR_BYPASS = "DONTCARE"; + parameter CH0_ENC_BYPASS = "DONTCARE"; + parameter CH1_ENC_BYPASS = "DONTCARE"; + parameter CH0_SB_BYPASS = "DONTCARE"; + parameter CH1_SB_BYPASS = "DONTCARE"; + parameter CH0_RX_SB_BYPASS = "DONTCARE"; + parameter CH1_RX_SB_BYPASS = "DONTCARE"; + parameter CH0_WA_BYPASS = "DONTCARE"; + parameter CH1_WA_BYPASS = "DONTCARE"; + parameter CH0_DEC_BYPASS = "DONTCARE"; + parameter CH1_DEC_BYPASS = "DONTCARE"; + parameter CH0_CTC_BYPASS = "DONTCARE"; + parameter CH1_CTC_BYPASS = "DONTCARE"; + parameter CH0_RX_GEAR_BYPASS = "DONTCARE"; + parameter CH1_RX_GEAR_BYPASS = "DONTCARE"; + parameter CH0_LSM_DISABLE = "DONTCARE"; + parameter CH1_LSM_DISABLE = "DONTCARE"; + parameter CH0_MATCH_2_ENABLE = "DONTCARE"; + parameter CH1_MATCH_2_ENABLE = "DONTCARE"; + parameter CH0_MATCH_4_ENABLE = "DONTCARE"; + parameter CH1_MATCH_4_ENABLE = "DONTCARE"; + parameter CH0_MIN_IPG_CNT = "DONTCARE"; + parameter CH1_MIN_IPG_CNT = "DONTCARE"; + parameter CH0_CC_MATCH_1 = "DONTCARE"; + parameter CH1_CC_MATCH_1 = "DONTCARE"; + parameter CH0_CC_MATCH_2 = "DONTCARE"; + parameter CH1_CC_MATCH_2 = "DONTCARE"; + parameter CH0_CC_MATCH_3 = "DONTCARE"; + parameter CH1_CC_MATCH_3 = "DONTCARE"; + parameter CH0_CC_MATCH_4 = "DONTCARE"; + parameter CH1_CC_MATCH_4 = "DONTCARE"; + parameter CH0_UDF_COMMA_MASK = "DONTCARE"; + parameter CH1_UDF_COMMA_MASK = "DONTCARE"; + parameter CH0_UDF_COMMA_A = "DONTCARE"; + parameter CH1_UDF_COMMA_A = "DONTCARE"; + parameter CH0_UDF_COMMA_B = "DONTCARE"; + parameter CH1_UDF_COMMA_B = "DONTCARE"; + parameter CH0_RX_DCO_CK_DIV = "DONTCARE"; + parameter CH1_RX_DCO_CK_DIV = "DONTCARE"; + parameter CH0_RCV_DCC_EN = "DONTCARE"; + parameter CH1_RCV_DCC_EN = "DONTCARE"; + parameter CH0_REQ_LVL_SET = "DONTCARE"; + parameter CH1_REQ_LVL_SET = "DONTCARE"; + parameter CH0_REQ_EN = "DONTCARE"; + parameter CH1_REQ_EN = "DONTCARE"; + parameter CH0_RTERM_RX = "DONTCARE"; + parameter CH1_RTERM_RX = "DONTCARE"; + parameter CH0_PDEN_SEL = "DONTCARE"; + parameter CH1_PDEN_SEL = "DONTCARE"; + parameter CH0_LDR_RX2CORE_SEL = "DONTCARE"; + parameter CH1_LDR_RX2CORE_SEL = "DONTCARE"; + parameter CH0_LDR_CORE2TX_SEL = "DONTCARE"; + parameter CH1_LDR_CORE2TX_SEL = "DONTCARE"; + parameter CH0_TPWDNB = "DONTCARE"; + parameter CH1_TPWDNB = "DONTCARE"; + parameter CH0_RATE_MODE_TX = "DONTCARE"; + parameter CH1_RATE_MODE_TX = "DONTCARE"; + parameter CH0_RTERM_TX = "DONTCARE"; + parameter CH1_RTERM_TX = "DONTCARE"; + parameter CH0_TX_CM_SEL = "DONTCARE"; + parameter CH1_TX_CM_SEL = "DONTCARE"; + parameter CH0_TDRV_PRE_EN = "DONTCARE"; + parameter CH1_TDRV_PRE_EN = "DONTCARE"; + parameter CH0_TDRV_SLICE0_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE0_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE1_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE1_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE2_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE2_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE3_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE3_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE4_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE4_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE5_SEL = "DONTCARE"; + parameter CH1_TDRV_SLICE5_SEL = "DONTCARE"; + parameter CH0_TDRV_SLICE0_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE0_CUR = "DONTCARE"; + parameter CH0_TDRV_SLICE1_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE1_CUR = "DONTCARE"; + parameter CH0_TDRV_SLICE2_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE2_CUR = "DONTCARE"; + parameter CH0_TDRV_SLICE3_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE3_CUR = "DONTCARE"; + parameter CH0_TDRV_SLICE4_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE4_CUR = "DONTCARE"; + parameter CH0_TDRV_SLICE5_CUR = "DONTCARE"; + parameter CH1_TDRV_SLICE5_CUR = "DONTCARE"; + parameter CH0_TDRV_DAT_SEL = "DONTCARE"; + parameter CH1_TDRV_DAT_SEL = "DONTCARE"; + parameter CH0_TX_DIV11_SEL = "DONTCARE"; + parameter CH1_TX_DIV11_SEL = "DONTCARE"; + parameter CH0_RPWDNB = "DONTCARE"; + parameter CH1_RPWDNB = "DONTCARE"; + parameter CH0_RATE_MODE_RX = "DONTCARE"; + parameter CH1_RATE_MODE_RX = "DONTCARE"; + parameter CH0_RLOS_SEL = "DONTCARE"; + parameter CH1_RLOS_SEL = "DONTCARE"; + parameter CH0_RX_LOS_LVL = "DONTCARE"; + parameter CH1_RX_LOS_LVL = "DONTCARE"; + parameter CH0_RX_LOS_CEQ = "DONTCARE"; + parameter CH1_RX_LOS_CEQ = "DONTCARE"; + parameter CH0_RX_LOS_HYST_EN = "DONTCARE"; + parameter CH1_RX_LOS_HYST_EN = "DONTCARE"; + parameter CH0_RX_LOS_EN = "DONTCARE"; + parameter CH1_RX_LOS_EN = "DONTCARE"; + parameter CH0_RX_DIV11_SEL = "DONTCARE"; + parameter CH1_RX_DIV11_SEL = "DONTCARE"; + parameter CH0_SEL_SD_RX_CLK = "DONTCARE"; + parameter CH1_SEL_SD_RX_CLK = "DONTCARE"; + parameter CH0_FF_RX_H_CLK_EN = "DONTCARE"; + parameter CH1_FF_RX_H_CLK_EN = "DONTCARE"; + parameter CH0_FF_RX_F_CLK_DIS = "DONTCARE"; + parameter CH1_FF_RX_F_CLK_DIS = "DONTCARE"; + parameter CH0_FF_TX_H_CLK_EN = "DONTCARE"; + parameter CH1_FF_TX_H_CLK_EN = "DONTCARE"; + parameter CH0_FF_TX_F_CLK_DIS = "DONTCARE"; + parameter CH1_FF_TX_F_CLK_DIS = "DONTCARE"; + parameter CH0_RX_RATE_SEL = "DONTCARE"; + parameter CH1_RX_RATE_SEL = "DONTCARE"; + parameter CH0_TDRV_POST_EN = "DONTCARE"; + parameter CH1_TDRV_POST_EN = "DONTCARE"; + parameter CH0_TX_POST_SIGN = "DONTCARE"; + parameter CH1_TX_POST_SIGN = "DONTCARE"; + parameter CH0_TX_PRE_SIGN = "DONTCARE"; + parameter CH1_TX_PRE_SIGN = "DONTCARE"; + parameter CH0_RXTERM_CM = "DONTCARE"; + parameter CH1_RXTERM_CM = "DONTCARE"; + parameter CH0_RXIN_CM = "DONTCARE"; + parameter CH1_RXIN_CM = "DONTCARE"; + parameter CH0_LEQ_OFFSET_SEL = "DONTCARE"; + parameter CH1_LEQ_OFFSET_SEL = "DONTCARE"; + parameter CH0_LEQ_OFFSET_TRIM = "DONTCARE"; + parameter CH1_LEQ_OFFSET_TRIM = "DONTCARE"; + parameter D_TX_MAX_RATE = "DONTCARE"; + parameter CH0_CDR_MAX_RATE = "DONTCARE"; + parameter CH1_CDR_MAX_RATE = "DONTCARE"; + parameter CH0_TXAMPLITUDE = "DONTCARE"; + parameter CH1_TXAMPLITUDE = "DONTCARE"; + parameter CH0_TXDEPRE = "DONTCARE"; + parameter CH1_TXDEPRE = "DONTCARE"; + parameter CH0_TXDEPOST = "DONTCARE"; + parameter CH1_TXDEPOST = "DONTCARE"; + parameter CH0_PROTOCOL = "DONTCARE"; + parameter CH1_PROTOCOL = "DONTCARE"; + parameter D_ISETLOS = "DONTCARE"; + parameter D_SETIRPOLY_AUX = "DONTCARE"; + parameter D_SETICONST_AUX = "DONTCARE"; + parameter D_SETIRPOLY_CH = "DONTCARE"; + parameter D_SETICONST_CH = "DONTCARE"; + parameter D_REQ_ISET = "DONTCARE"; + parameter D_PD_ISET = "DONTCARE"; + parameter D_DCO_CALIB_TIME_SEL = "DONTCARE"; + parameter CH0_DCOCTLGI = "DONTCARE"; + parameter CH1_DCOCTLGI = "DONTCARE"; + parameter CH0_DCOATDDLY = "DONTCARE"; + parameter CH1_DCOATDDLY = "DONTCARE"; + parameter CH0_DCOATDCFG = "DONTCARE"; + parameter CH1_DCOATDCFG = "DONTCARE"; + parameter CH0_DCOBYPSATD = "DONTCARE"; + parameter CH1_DCOBYPSATD = "DONTCARE"; + parameter CH0_DCOSCALEI = "DONTCARE"; + parameter CH1_DCOSCALEI = "DONTCARE"; + parameter CH0_DCOITUNE4LSB = "DONTCARE"; + parameter CH1_DCOITUNE4LSB = "DONTCARE"; + parameter CH0_DCOIOSTUNE = "DONTCARE"; + parameter CH1_DCOIOSTUNE = "DONTCARE"; + parameter CH0_DCODISBDAVOID = "DONTCARE"; + parameter CH1_DCODISBDAVOID = "DONTCARE"; + parameter CH0_DCOCALDIV = "DONTCARE"; + parameter CH1_DCOCALDIV = "DONTCARE"; + parameter CH0_DCONUOFLSB = "DONTCARE"; + parameter CH1_DCONUOFLSB = "DONTCARE"; + parameter CH0_DCOIUPDNX2 = "DONTCARE"; + parameter CH1_DCOIUPDNX2 = "DONTCARE"; + parameter CH0_DCOSTEP = "DONTCARE"; + parameter CH1_DCOSTEP = "DONTCARE"; + parameter CH0_DCOSTARTVAL = "DONTCARE"; + parameter CH1_DCOSTARTVAL = "DONTCARE"; + parameter CH0_DCOFLTDAC = "DONTCARE"; + parameter CH1_DCOFLTDAC = "DONTCARE"; + parameter CH0_DCOITUNE = "DONTCARE"; + parameter CH1_DCOITUNE = "DONTCARE"; + parameter CH0_DCOFTNRG = "DONTCARE"; + parameter CH1_DCOFTNRG = "DONTCARE"; + parameter CH0_CDR_CNT4SEL = "DONTCARE"; + parameter CH1_CDR_CNT4SEL = "DONTCARE"; + parameter CH0_CDR_CNT8SEL = "DONTCARE"; + parameter CH1_CDR_CNT8SEL = "DONTCARE"; + parameter CH0_BAND_THRESHOLD = "DONTCARE"; + parameter CH1_BAND_THRESHOLD = "DONTCARE"; + parameter CH0_AUTO_FACQ_EN = "DONTCARE"; + parameter CH1_AUTO_FACQ_EN = "DONTCARE"; + parameter CH0_AUTO_CALIB_EN = "DONTCARE"; + parameter CH1_AUTO_CALIB_EN = "DONTCARE"; + parameter CH0_CALIB_CK_MODE = "DONTCARE"; + parameter CH1_CALIB_CK_MODE = "DONTCARE"; + parameter CH0_REG_BAND_OFFSET = "DONTCARE"; + parameter CH1_REG_BAND_OFFSET = "DONTCARE"; + parameter CH0_REG_BAND_SEL = "DONTCARE"; + parameter CH1_REG_BAND_SEL = "DONTCARE"; + parameter CH0_REG_IDAC_SEL = "DONTCARE"; + parameter CH1_REG_IDAC_SEL = "DONTCARE"; + parameter CH0_REG_IDAC_EN = "DONTCARE"; + parameter CH1_REG_IDAC_EN = "DONTCARE"; + parameter D_TXPLL_PWDNB = "DONTCARE"; + parameter D_SETPLLRC = "DONTCARE"; + parameter D_REFCK_MODE = "DONTCARE"; + parameter D_TX_VCO_CK_DIV = "DONTCARE"; + parameter D_PLL_LOL_SET = "DONTCARE"; + parameter D_RG_EN = "DONTCARE"; + parameter D_RG_SET = "DONTCARE"; + parameter D_CMUSETISCL4VCO = "DONTCARE"; + parameter D_CMUSETI4VCO = "DONTCARE"; + parameter D_CMUSETINITVCT = "DONTCARE"; + parameter D_CMUSETZGM = "DONTCARE"; + parameter D_CMUSETP2AGM = "DONTCARE"; + parameter D_CMUSETP1GM = "DONTCARE"; + parameter D_CMUSETI4CPZ = "DONTCARE"; + parameter D_CMUSETI4CPP = "DONTCARE"; + parameter D_CMUSETICP4Z = "DONTCARE"; + parameter D_CMUSETICP4P = "DONTCARE"; + parameter D_CMUSETBIASI = "DONTCARE"; + (* iopad_external_pin *) + (* iopad_external_pin *) + input CH0_HDINP; + (* iopad_external_pin *) + input CH1_HDINP; + (* iopad_external_pin *) + input CH0_HDINN; + (* iopad_external_pin *) + input CH1_HDINN; + input D_TXBIT_CLKP_FROM_ND; + input D_TXBIT_CLKN_FROM_ND; + input D_SYNC_ND; + input D_TXPLL_LOL_FROM_ND; + input CH0_RX_REFCLK; + input CH1_RX_REFCLK; + input CH0_FF_RXI_CLK; + input CH1_FF_RXI_CLK; + input CH0_FF_TXI_CLK; + input CH1_FF_TXI_CLK; + input CH0_FF_EBRD_CLK; + input CH1_FF_EBRD_CLK; + input CH0_FF_TX_D_0; + input CH1_FF_TX_D_0; + input CH0_FF_TX_D_1; + input CH1_FF_TX_D_1; + input CH0_FF_TX_D_2; + input CH1_FF_TX_D_2; + input CH0_FF_TX_D_3; + input CH1_FF_TX_D_3; + input CH0_FF_TX_D_4; + input CH1_FF_TX_D_4; + input CH0_FF_TX_D_5; + input CH1_FF_TX_D_5; + input CH0_FF_TX_D_6; + input CH1_FF_TX_D_6; + input CH0_FF_TX_D_7; + input CH1_FF_TX_D_7; + input CH0_FF_TX_D_8; + input CH1_FF_TX_D_8; + input CH0_FF_TX_D_9; + input CH1_FF_TX_D_9; + input CH0_FF_TX_D_10; + input CH1_FF_TX_D_10; + input CH0_FF_TX_D_11; + input CH1_FF_TX_D_11; + input CH0_FF_TX_D_12; + input CH1_FF_TX_D_12; + input CH0_FF_TX_D_13; + input CH1_FF_TX_D_13; + input CH0_FF_TX_D_14; + input CH1_FF_TX_D_14; + input CH0_FF_TX_D_15; + input CH1_FF_TX_D_15; + input CH0_FF_TX_D_16; + input CH1_FF_TX_D_16; + input CH0_FF_TX_D_17; + input CH1_FF_TX_D_17; + input CH0_FF_TX_D_18; + input CH1_FF_TX_D_18; + input CH0_FF_TX_D_19; + input CH1_FF_TX_D_19; + input CH0_FF_TX_D_20; + input CH1_FF_TX_D_20; + input CH0_FF_TX_D_21; + input CH1_FF_TX_D_21; + input CH0_FF_TX_D_22; + input CH1_FF_TX_D_22; + input CH0_FF_TX_D_23; + input CH1_FF_TX_D_23; + input CH0_FFC_EI_EN; + input CH1_FFC_EI_EN; + input CH0_FFC_PCIE_DET_EN; + input CH1_FFC_PCIE_DET_EN; + input CH0_FFC_PCIE_CT; + input CH1_FFC_PCIE_CT; + input CH0_FFC_SB_INV_RX; + input CH1_FFC_SB_INV_RX; + input CH0_FFC_ENABLE_CGALIGN; + input CH1_FFC_ENABLE_CGALIGN; + input CH0_FFC_SIGNAL_DETECT; + input CH1_FFC_SIGNAL_DETECT; + input CH0_FFC_FB_LOOPBACK; + input CH1_FFC_FB_LOOPBACK; + input CH0_FFC_SB_PFIFO_LP; + input CH1_FFC_SB_PFIFO_LP; + input CH0_FFC_PFIFO_CLR; + input CH1_FFC_PFIFO_CLR; + input CH0_FFC_RATE_MODE_RX; + input CH1_FFC_RATE_MODE_RX; + input CH0_FFC_RATE_MODE_TX; + input CH1_FFC_RATE_MODE_TX; + input CH0_FFC_DIV11_MODE_RX; + input CH1_FFC_DIV11_MODE_RX; + input CH0_FFC_RX_GEAR_MODE; + input CH1_FFC_RX_GEAR_MODE; + input CH0_FFC_TX_GEAR_MODE; + input CH1_FFC_TX_GEAR_MODE; + input CH0_FFC_DIV11_MODE_TX; + input CH1_FFC_DIV11_MODE_TX; + input CH0_FFC_LDR_CORE2TX_EN; + input CH1_FFC_LDR_CORE2TX_EN; + input CH0_FFC_LANE_TX_RST; + input CH1_FFC_LANE_TX_RST; + input CH0_FFC_LANE_RX_RST; + input CH1_FFC_LANE_RX_RST; + input CH0_FFC_RRST; + input CH1_FFC_RRST; + input CH0_FFC_TXPWDNB; + input CH1_FFC_TXPWDNB; + input CH0_FFC_RXPWDNB; + input CH1_FFC_RXPWDNB; + input CH0_LDR_CORE2TX; + input CH1_LDR_CORE2TX; + input D_SCIWDATA0; + input D_SCIWDATA1; + input D_SCIWDATA2; + input D_SCIWDATA3; + input D_SCIWDATA4; + input D_SCIWDATA5; + input D_SCIWDATA6; + input D_SCIWDATA7; + input D_SCIADDR0; + input D_SCIADDR1; + input D_SCIADDR2; + input D_SCIADDR3; + input D_SCIADDR4; + input D_SCIADDR5; + input D_SCIENAUX; + input D_SCISELAUX; + input CH0_SCIEN; + input CH1_SCIEN; + input CH0_SCISEL; + input CH1_SCISEL; + input D_SCIRD; + input D_SCIWSTN; + input D_CYAWSTN; + input D_FFC_SYNC_TOGGLE; + input D_FFC_DUAL_RST; + input D_FFC_MACRO_RST; + input D_FFC_MACROPDB; + input D_FFC_TRST; + input CH0_FFC_CDR_EN_BITSLIP; + input CH1_FFC_CDR_EN_BITSLIP; + input D_SCAN_ENABLE; + input D_SCAN_IN_0; + input D_SCAN_IN_1; + input D_SCAN_IN_2; + input D_SCAN_IN_3; + input D_SCAN_IN_4; + input D_SCAN_IN_5; + input D_SCAN_IN_6; + input D_SCAN_IN_7; + input D_SCAN_MODE; + input D_SCAN_RESET; + input D_CIN0; + input D_CIN1; + input D_CIN2; + input D_CIN3; + input D_CIN4; + input D_CIN5; + input D_CIN6; + input D_CIN7; + input D_CIN8; + input D_CIN9; + input D_CIN10; + input D_CIN11; + output CH0_HDOUTP; + output CH1_HDOUTP; + output CH0_HDOUTN; + output CH1_HDOUTN; + output D_TXBIT_CLKP_TO_ND; + output D_TXBIT_CLKN_TO_ND; + output D_SYNC_PULSE2ND; + output D_TXPLL_LOL_TO_ND; + output CH0_FF_RX_F_CLK; + output CH1_FF_RX_F_CLK; + output CH0_FF_RX_H_CLK; + output CH1_FF_RX_H_CLK; + output CH0_FF_TX_F_CLK; + output CH1_FF_TX_F_CLK; + output CH0_FF_TX_H_CLK; + output CH1_FF_TX_H_CLK; + output CH0_FF_RX_PCLK; + output CH1_FF_RX_PCLK; + output CH0_FF_TX_PCLK; + output CH1_FF_TX_PCLK; + output CH0_FF_RX_D_0; + output CH1_FF_RX_D_0; + output CH0_FF_RX_D_1; + output CH1_FF_RX_D_1; + output CH0_FF_RX_D_2; + output CH1_FF_RX_D_2; + output CH0_FF_RX_D_3; + output CH1_FF_RX_D_3; + output CH0_FF_RX_D_4; + output CH1_FF_RX_D_4; + output CH0_FF_RX_D_5; + output CH1_FF_RX_D_5; + output CH0_FF_RX_D_6; + output CH1_FF_RX_D_6; + output CH0_FF_RX_D_7; + output CH1_FF_RX_D_7; + output CH0_FF_RX_D_8; + output CH1_FF_RX_D_8; + output CH0_FF_RX_D_9; + output CH1_FF_RX_D_9; + output CH0_FF_RX_D_10; + output CH1_FF_RX_D_10; + output CH0_FF_RX_D_11; + output CH1_FF_RX_D_11; + output CH0_FF_RX_D_12; + output CH1_FF_RX_D_12; + output CH0_FF_RX_D_13; + output CH1_FF_RX_D_13; + output CH0_FF_RX_D_14; + output CH1_FF_RX_D_14; + output CH0_FF_RX_D_15; + output CH1_FF_RX_D_15; + output CH0_FF_RX_D_16; + output CH1_FF_RX_D_16; + output CH0_FF_RX_D_17; + output CH1_FF_RX_D_17; + output CH0_FF_RX_D_18; + output CH1_FF_RX_D_18; + output CH0_FF_RX_D_19; + output CH1_FF_RX_D_19; + output CH0_FF_RX_D_20; + output CH1_FF_RX_D_20; + output CH0_FF_RX_D_21; + output CH1_FF_RX_D_21; + output CH0_FF_RX_D_22; + output CH1_FF_RX_D_22; + output CH0_FF_RX_D_23; + output CH1_FF_RX_D_23; + output CH0_FFS_PCIE_DONE; + output CH1_FFS_PCIE_DONE; + output CH0_FFS_PCIE_CON; + output CH1_FFS_PCIE_CON; + output CH0_FFS_RLOS; + output CH1_FFS_RLOS; + output CH0_FFS_LS_SYNC_STATUS; + output CH1_FFS_LS_SYNC_STATUS; + output CH0_FFS_CC_UNDERRUN; + output CH1_FFS_CC_UNDERRUN; + output CH0_FFS_CC_OVERRUN; + output CH1_FFS_CC_OVERRUN; + output CH0_FFS_RXFBFIFO_ERROR; + output CH1_FFS_RXFBFIFO_ERROR; + output CH0_FFS_TXFBFIFO_ERROR; + output CH1_FFS_TXFBFIFO_ERROR; + output CH0_FFS_RLOL; + output CH1_FFS_RLOL; + output CH0_FFS_SKP_ADDED; + output CH1_FFS_SKP_ADDED; + output CH0_FFS_SKP_DELETED; + output CH1_FFS_SKP_DELETED; + output CH0_LDR_RX2CORE; + output CH1_LDR_RX2CORE; + output D_SCIRDATA0; + output D_SCIRDATA1; + output D_SCIRDATA2; + output D_SCIRDATA3; + output D_SCIRDATA4; + output D_SCIRDATA5; + output D_SCIRDATA6; + output D_SCIRDATA7; + output D_SCIINT; + output D_SCAN_OUT_0; + output D_SCAN_OUT_1; + output D_SCAN_OUT_2; + output D_SCAN_OUT_3; + output D_SCAN_OUT_4; + output D_SCAN_OUT_5; + output D_SCAN_OUT_6; + output D_SCAN_OUT_7; + output D_COUT0; + output D_COUT1; + output D_COUT2; + output D_COUT3; + output D_COUT4; + output D_COUT5; + output D_COUT6; + output D_COUT7; + output D_COUT8; + output D_COUT9; + output D_COUT10; + output D_COUT11; + output D_COUT12; + output D_COUT13; + output D_COUT14; + output D_COUT15; + output D_COUT16; + output D_COUT17; + output D_COUT18; + output D_COUT19; + input D_REFCLKI; + output D_FFS_PLOL; +endmodule + diff --git a/techlibs/lattice/cells_bb_xo2.v b/techlibs/lattice/cells_bb_xo2.v new file mode 100644 index 00000000000..fdf8331b731 --- /dev/null +++ b/techlibs/lattice/cells_bb_xo2.v @@ -0,0 +1,571 @@ +// Created by cells_xtra.py from Lattice models + +(* blackbox *) (* keep *) +module GSR (...); + input GSR; +endmodule + +(* blackbox *) (* keep *) +module SGSR (...); + input GSR; + input CLK; +endmodule + +(* blackbox *) +module DP8KC (...); + parameter DATA_WIDTH_A = 9; + parameter DATA_WIDTH_B = 9; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DIA8; + input DIA7; + input DIA6; + input DIA5; + input DIA4; + input DIA3; + input DIA2; + input DIA1; + input DIA0; + input ADA12; + input ADA11; + input ADA10; + input ADA9; + input ADA8; + input ADA7; + input ADA6; + input ADA5; + input ADA4; + input ADA3; + input ADA2; + input ADA1; + input ADA0; + input CEA; + input OCEA; + input CLKA; + input WEA; + input CSA2; + input CSA1; + input CSA0; + input RSTA; + input DIB8; + input DIB7; + input DIB6; + input DIB5; + input DIB4; + input DIB3; + input DIB2; + input DIB1; + input DIB0; + input ADB12; + input ADB11; + input ADB10; + input ADB9; + input ADB8; + input ADB7; + input ADB6; + input ADB5; + input ADB4; + input ADB3; + input ADB2; + input ADB1; + input ADB0; + input CEB; + input OCEB; + input CLKB; + input WEB; + input CSB2; + input CSB1; + input CSB0; + input RSTB; + output DOA8; + output DOA7; + output DOA6; + output DOA5; + output DOA4; + output DOA3; + output DOA2; + output DOA1; + output DOA0; + output DOB8; + output DOB7; + output DOB6; + output DOB5; + output DOB4; + output DOB3; + output DOB2; + output DOB1; + output DOB0; +endmodule + +(* blackbox *) +module PDPW8KC (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE_W = "0b000"; + parameter CSDECODE_R = "0b000"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI17; + input DI16; + input DI15; + input DI14; + input DI13; + input DI12; + input DI11; + input DI10; + input DI9; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input ADW8; + input ADW7; + input ADW6; + input ADW5; + input ADW4; + input ADW3; + input ADW2; + input ADW1; + input ADW0; + input BE1; + input BE0; + input CEW; + input CLKW; + input CSW2; + input CSW1; + input CSW0; + input ADR12; + input ADR11; + input ADR10; + input ADR9; + input ADR8; + input ADR7; + input ADR6; + input ADR5; + input ADR4; + input ADR3; + input ADR2; + input ADR1; + input ADR0; + input CER; + input OCER; + input CLKR; + input CSR2; + input CSR1; + input CSR0; + input RST; + output DO17; + output DO16; + output DO15; + output DO14; + output DO13; + output DO12; + output DO11; + output DO10; + output DO9; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module SP8KC (...); + parameter DATA_WIDTH = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE = "0b000"; + parameter WRITEMODE = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input AD12; + input AD11; + input AD10; + input AD9; + input AD8; + input AD7; + input AD6; + input AD5; + input AD4; + input AD3; + input AD2; + input AD1; + input AD0; + input CE; + input OCE; + input CLK; + input WE; + input CS2; + input CS1; + input CS0; + input RST; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module FIFO8KB (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 18; + parameter REGMODE = "NOREG"; + parameter RESETMODE = "ASYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CSDECODE_W = "0b00"; + parameter CSDECODE_R = "0b00"; + parameter AEPOINTER = "0b00000000000000"; + parameter AEPOINTER1 = "0b00000000000000"; + parameter AFPOINTER = "0b00000000000000"; + parameter AFPOINTER1 = "0b00000000000000"; + parameter FULLPOINTER = "0b00000000000000"; + parameter FULLPOINTER1 = "0b00000000000000"; + parameter GSR = "DISABLED"; + input DI0; + input DI1; + input DI2; + input DI3; + input DI4; + input DI5; + input DI6; + input DI7; + input DI8; + input DI9; + input DI10; + input DI11; + input DI12; + input DI13; + input DI14; + input DI15; + input DI16; + input DI17; + input CSW0; + input CSW1; + input CSR0; + input CSR1; + input WE; + input RE; + input ORE; + input CLKW; + input CLKR; + input RST; + input RPRST; + input FULLI; + input EMPTYI; + output DO0; + output DO1; + output DO2; + output DO3; + output DO4; + output DO5; + output DO6; + output DO7; + output DO8; + output DO9; + output DO10; + output DO11; + output DO12; + output DO13; + output DO14; + output DO15; + output DO16; + output DO17; + output EF; + output AEF; + output AFF; + output FF; +endmodule + +(* blackbox *) +module CLKDIVC (...); + parameter GSR = "DISABLED"; + parameter DIV = "2.0"; + input RST; + input CLKI; + input ALIGNWD; + output CDIV1; + output CDIVX; +endmodule + +(* blackbox *) +module DCMA (...); + input CLK0; + input CLK1; + input SEL; + output DCMOUT; +endmodule + +(* blackbox *) +module ECLKSYNCA (...); + input ECLKI; + input STOP; + output ECLKO; +endmodule + +(* blackbox *) +module ECLKBRIDGECS (...); + input CLK0; + input CLK1; + input SEL; + output ECSOUT; +endmodule + +(* blackbox *) +module DCCA (...); + input CLKI; + input CE; + output CLKO; +endmodule + +(* blackbox *) (* keep *) +module START (...); + input STARTCLK; +endmodule + +(* blackbox *) +module EHXPLLJ (...); + parameter CLKI_DIV = 1; + parameter CLKFB_DIV = 1; + parameter CLKOP_DIV = 8; + parameter CLKOS_DIV = 8; + parameter CLKOS2_DIV = 8; + parameter CLKOS3_DIV = 8; + parameter CLKOP_ENABLE = "ENABLED"; + parameter CLKOS_ENABLE = "ENABLED"; + parameter CLKOS2_ENABLE = "ENABLED"; + parameter CLKOS3_ENABLE = "ENABLED"; + parameter VCO_BYPASS_A0 = "DISABLED"; + parameter VCO_BYPASS_B0 = "DISABLED"; + parameter VCO_BYPASS_C0 = "DISABLED"; + parameter VCO_BYPASS_D0 = "DISABLED"; + parameter CLKOP_CPHASE = 0; + parameter CLKOS_CPHASE = 0; + parameter CLKOS2_CPHASE = 0; + parameter CLKOS3_CPHASE = 0; + parameter CLKOP_FPHASE = 0; + parameter CLKOS_FPHASE = 0; + parameter CLKOS2_FPHASE = 0; + parameter CLKOS3_FPHASE = 0; + parameter FEEDBK_PATH = "CLKOP"; + parameter FRACN_ENABLE = "DISABLED"; + parameter FRACN_DIV = 0; + parameter CLKOP_TRIM_POL = "RISING"; + parameter CLKOP_TRIM_DELAY = 0; + parameter CLKOS_TRIM_POL = "RISING"; + parameter CLKOS_TRIM_DELAY = 0; + parameter PLL_USE_WB = "DISABLED"; + parameter PREDIVIDER_MUXA1 = 0; + parameter PREDIVIDER_MUXB1 = 0; + parameter PREDIVIDER_MUXC1 = 0; + parameter PREDIVIDER_MUXD1 = 0; + parameter OUTDIVIDER_MUXA2 = "DIVA"; + parameter OUTDIVIDER_MUXB2 = "DIVB"; + parameter OUTDIVIDER_MUXC2 = "DIVC"; + parameter OUTDIVIDER_MUXD2 = "DIVD"; + parameter PLL_LOCK_MODE = 0; + parameter STDBY_ENABLE = "DISABLED"; + parameter DPHASE_SOURCE = "DISABLED"; + parameter PLLRST_ENA = "DISABLED"; + parameter MRST_ENA = "DISABLED"; + parameter DCRST_ENA = "DISABLED"; + parameter DDRST_ENA = "DISABLED"; + parameter INTFB_WAKE = "DISABLED"; + input CLKI; + input CLKFB; + input PHASESEL1; + input PHASESEL0; + input PHASEDIR; + input PHASESTEP; + input LOADREG; + input STDBY; + input PLLWAKESYNC; + input RST; + input RESETM; + input RESETC; + input RESETD; + input ENCLKOP; + input ENCLKOS; + input ENCLKOS2; + input ENCLKOS3; + input PLLCLK; + input PLLRST; + input PLLSTB; + input PLLWE; + input PLLDATI7; + input PLLDATI6; + input PLLDATI5; + input PLLDATI4; + input PLLDATI3; + input PLLDATI2; + input PLLDATI1; + input PLLDATI0; + input PLLADDR4; + input PLLADDR3; + input PLLADDR2; + input PLLADDR1; + input PLLADDR0; + output CLKOP; + output CLKOS; + output CLKOS2; + output CLKOS3; + output LOCK; + output INTLOCK; + output REFCLK; + output PLLDATO7; + output PLLDATO6; + output PLLDATO5; + output PLLDATO4; + output PLLDATO3; + output PLLDATO2; + output PLLDATO1; + output PLLDATO0; + output PLLACK; + output DPHSRC; + output CLKINTFB; +endmodule + +(* blackbox *) +module OSCH (...); + parameter NOM_FREQ = "2.08"; + input STDBY; + output OSC; + output SEDSTDBY; +endmodule + +(* blackbox *) (* keep *) +module TSALL (...); + input TSALL; +endmodule + diff --git a/techlibs/lattice/cells_bb_xo3.v b/techlibs/lattice/cells_bb_xo3.v new file mode 100644 index 00000000000..fdf8331b731 --- /dev/null +++ b/techlibs/lattice/cells_bb_xo3.v @@ -0,0 +1,571 @@ +// Created by cells_xtra.py from Lattice models + +(* blackbox *) (* keep *) +module GSR (...); + input GSR; +endmodule + +(* blackbox *) (* keep *) +module SGSR (...); + input GSR; + input CLK; +endmodule + +(* blackbox *) +module DP8KC (...); + parameter DATA_WIDTH_A = 9; + parameter DATA_WIDTH_B = 9; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DIA8; + input DIA7; + input DIA6; + input DIA5; + input DIA4; + input DIA3; + input DIA2; + input DIA1; + input DIA0; + input ADA12; + input ADA11; + input ADA10; + input ADA9; + input ADA8; + input ADA7; + input ADA6; + input ADA5; + input ADA4; + input ADA3; + input ADA2; + input ADA1; + input ADA0; + input CEA; + input OCEA; + input CLKA; + input WEA; + input CSA2; + input CSA1; + input CSA0; + input RSTA; + input DIB8; + input DIB7; + input DIB6; + input DIB5; + input DIB4; + input DIB3; + input DIB2; + input DIB1; + input DIB0; + input ADB12; + input ADB11; + input ADB10; + input ADB9; + input ADB8; + input ADB7; + input ADB6; + input ADB5; + input ADB4; + input ADB3; + input ADB2; + input ADB1; + input ADB0; + input CEB; + input OCEB; + input CLKB; + input WEB; + input CSB2; + input CSB1; + input CSB0; + input RSTB; + output DOA8; + output DOA7; + output DOA6; + output DOA5; + output DOA4; + output DOA3; + output DOA2; + output DOA1; + output DOA0; + output DOB8; + output DOB7; + output DOB6; + output DOB5; + output DOB4; + output DOB3; + output DOB2; + output DOB1; + output DOB0; +endmodule + +(* blackbox *) +module PDPW8KC (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE_W = "0b000"; + parameter CSDECODE_R = "0b000"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI17; + input DI16; + input DI15; + input DI14; + input DI13; + input DI12; + input DI11; + input DI10; + input DI9; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input ADW8; + input ADW7; + input ADW6; + input ADW5; + input ADW4; + input ADW3; + input ADW2; + input ADW1; + input ADW0; + input BE1; + input BE0; + input CEW; + input CLKW; + input CSW2; + input CSW1; + input CSW0; + input ADR12; + input ADR11; + input ADR10; + input ADR9; + input ADR8; + input ADR7; + input ADR6; + input ADR5; + input ADR4; + input ADR3; + input ADR2; + input ADR1; + input ADR0; + input CER; + input OCER; + input CLKR; + input CSR2; + input CSR1; + input CSR0; + input RST; + output DO17; + output DO16; + output DO15; + output DO14; + output DO13; + output DO12; + output DO11; + output DO10; + output DO9; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module SP8KC (...); + parameter DATA_WIDTH = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE = "0b000"; + parameter WRITEMODE = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input AD12; + input AD11; + input AD10; + input AD9; + input AD8; + input AD7; + input AD6; + input AD5; + input AD4; + input AD3; + input AD2; + input AD1; + input AD0; + input CE; + input OCE; + input CLK; + input WE; + input CS2; + input CS1; + input CS0; + input RST; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module FIFO8KB (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 18; + parameter REGMODE = "NOREG"; + parameter RESETMODE = "ASYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CSDECODE_W = "0b00"; + parameter CSDECODE_R = "0b00"; + parameter AEPOINTER = "0b00000000000000"; + parameter AEPOINTER1 = "0b00000000000000"; + parameter AFPOINTER = "0b00000000000000"; + parameter AFPOINTER1 = "0b00000000000000"; + parameter FULLPOINTER = "0b00000000000000"; + parameter FULLPOINTER1 = "0b00000000000000"; + parameter GSR = "DISABLED"; + input DI0; + input DI1; + input DI2; + input DI3; + input DI4; + input DI5; + input DI6; + input DI7; + input DI8; + input DI9; + input DI10; + input DI11; + input DI12; + input DI13; + input DI14; + input DI15; + input DI16; + input DI17; + input CSW0; + input CSW1; + input CSR0; + input CSR1; + input WE; + input RE; + input ORE; + input CLKW; + input CLKR; + input RST; + input RPRST; + input FULLI; + input EMPTYI; + output DO0; + output DO1; + output DO2; + output DO3; + output DO4; + output DO5; + output DO6; + output DO7; + output DO8; + output DO9; + output DO10; + output DO11; + output DO12; + output DO13; + output DO14; + output DO15; + output DO16; + output DO17; + output EF; + output AEF; + output AFF; + output FF; +endmodule + +(* blackbox *) +module CLKDIVC (...); + parameter GSR = "DISABLED"; + parameter DIV = "2.0"; + input RST; + input CLKI; + input ALIGNWD; + output CDIV1; + output CDIVX; +endmodule + +(* blackbox *) +module DCMA (...); + input CLK0; + input CLK1; + input SEL; + output DCMOUT; +endmodule + +(* blackbox *) +module ECLKSYNCA (...); + input ECLKI; + input STOP; + output ECLKO; +endmodule + +(* blackbox *) +module ECLKBRIDGECS (...); + input CLK0; + input CLK1; + input SEL; + output ECSOUT; +endmodule + +(* blackbox *) +module DCCA (...); + input CLKI; + input CE; + output CLKO; +endmodule + +(* blackbox *) (* keep *) +module START (...); + input STARTCLK; +endmodule + +(* blackbox *) +module EHXPLLJ (...); + parameter CLKI_DIV = 1; + parameter CLKFB_DIV = 1; + parameter CLKOP_DIV = 8; + parameter CLKOS_DIV = 8; + parameter CLKOS2_DIV = 8; + parameter CLKOS3_DIV = 8; + parameter CLKOP_ENABLE = "ENABLED"; + parameter CLKOS_ENABLE = "ENABLED"; + parameter CLKOS2_ENABLE = "ENABLED"; + parameter CLKOS3_ENABLE = "ENABLED"; + parameter VCO_BYPASS_A0 = "DISABLED"; + parameter VCO_BYPASS_B0 = "DISABLED"; + parameter VCO_BYPASS_C0 = "DISABLED"; + parameter VCO_BYPASS_D0 = "DISABLED"; + parameter CLKOP_CPHASE = 0; + parameter CLKOS_CPHASE = 0; + parameter CLKOS2_CPHASE = 0; + parameter CLKOS3_CPHASE = 0; + parameter CLKOP_FPHASE = 0; + parameter CLKOS_FPHASE = 0; + parameter CLKOS2_FPHASE = 0; + parameter CLKOS3_FPHASE = 0; + parameter FEEDBK_PATH = "CLKOP"; + parameter FRACN_ENABLE = "DISABLED"; + parameter FRACN_DIV = 0; + parameter CLKOP_TRIM_POL = "RISING"; + parameter CLKOP_TRIM_DELAY = 0; + parameter CLKOS_TRIM_POL = "RISING"; + parameter CLKOS_TRIM_DELAY = 0; + parameter PLL_USE_WB = "DISABLED"; + parameter PREDIVIDER_MUXA1 = 0; + parameter PREDIVIDER_MUXB1 = 0; + parameter PREDIVIDER_MUXC1 = 0; + parameter PREDIVIDER_MUXD1 = 0; + parameter OUTDIVIDER_MUXA2 = "DIVA"; + parameter OUTDIVIDER_MUXB2 = "DIVB"; + parameter OUTDIVIDER_MUXC2 = "DIVC"; + parameter OUTDIVIDER_MUXD2 = "DIVD"; + parameter PLL_LOCK_MODE = 0; + parameter STDBY_ENABLE = "DISABLED"; + parameter DPHASE_SOURCE = "DISABLED"; + parameter PLLRST_ENA = "DISABLED"; + parameter MRST_ENA = "DISABLED"; + parameter DCRST_ENA = "DISABLED"; + parameter DDRST_ENA = "DISABLED"; + parameter INTFB_WAKE = "DISABLED"; + input CLKI; + input CLKFB; + input PHASESEL1; + input PHASESEL0; + input PHASEDIR; + input PHASESTEP; + input LOADREG; + input STDBY; + input PLLWAKESYNC; + input RST; + input RESETM; + input RESETC; + input RESETD; + input ENCLKOP; + input ENCLKOS; + input ENCLKOS2; + input ENCLKOS3; + input PLLCLK; + input PLLRST; + input PLLSTB; + input PLLWE; + input PLLDATI7; + input PLLDATI6; + input PLLDATI5; + input PLLDATI4; + input PLLDATI3; + input PLLDATI2; + input PLLDATI1; + input PLLDATI0; + input PLLADDR4; + input PLLADDR3; + input PLLADDR2; + input PLLADDR1; + input PLLADDR0; + output CLKOP; + output CLKOS; + output CLKOS2; + output CLKOS3; + output LOCK; + output INTLOCK; + output REFCLK; + output PLLDATO7; + output PLLDATO6; + output PLLDATO5; + output PLLDATO4; + output PLLDATO3; + output PLLDATO2; + output PLLDATO1; + output PLLDATO0; + output PLLACK; + output DPHSRC; + output CLKINTFB; +endmodule + +(* blackbox *) +module OSCH (...); + parameter NOM_FREQ = "2.08"; + input STDBY; + output OSC; + output SEDSTDBY; +endmodule + +(* blackbox *) (* keep *) +module TSALL (...); + input TSALL; +endmodule + diff --git a/techlibs/lattice/cells_bb_xo3d.v b/techlibs/lattice/cells_bb_xo3d.v new file mode 100644 index 00000000000..84d7d960198 --- /dev/null +++ b/techlibs/lattice/cells_bb_xo3d.v @@ -0,0 +1,572 @@ +// Created by cells_xtra.py from Lattice models + +(* blackbox *) (* keep *) +module GSR (...); + input GSR; +endmodule + +(* blackbox *) (* keep *) +module SGSR (...); + input GSR; + input CLK; +endmodule + +(* blackbox *) +module DP8KC (...); + parameter DATA_WIDTH_A = 9; + parameter DATA_WIDTH_B = 9; + parameter REGMODE_A = "NOREG"; + parameter REGMODE_B = "NOREG"; + parameter CSDECODE_A = "0b000"; + parameter CSDECODE_B = "0b000"; + parameter WRITEMODE_A = "NORMAL"; + parameter WRITEMODE_B = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DIA8; + input DIA7; + input DIA6; + input DIA5; + input DIA4; + input DIA3; + input DIA2; + input DIA1; + input DIA0; + input ADA12; + input ADA11; + input ADA10; + input ADA9; + input ADA8; + input ADA7; + input ADA6; + input ADA5; + input ADA4; + input ADA3; + input ADA2; + input ADA1; + input ADA0; + input CEA; + input OCEA; + input CLKA; + input WEA; + input CSA2; + input CSA1; + input CSA0; + input RSTA; + input DIB8; + input DIB7; + input DIB6; + input DIB5; + input DIB4; + input DIB3; + input DIB2; + input DIB1; + input DIB0; + input ADB12; + input ADB11; + input ADB10; + input ADB9; + input ADB8; + input ADB7; + input ADB6; + input ADB5; + input ADB4; + input ADB3; + input ADB2; + input ADB1; + input ADB0; + input CEB; + input OCEB; + input CLKB; + input WEB; + input CSB2; + input CSB1; + input CSB0; + input RSTB; + output DOA8; + output DOA7; + output DOA6; + output DOA5; + output DOA4; + output DOA3; + output DOA2; + output DOA1; + output DOA0; + output DOB8; + output DOB7; + output DOB6; + output DOB5; + output DOB4; + output DOB3; + output DOB2; + output DOB1; + output DOB0; +endmodule + +(* blackbox *) +module PDPW8KC (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE_W = "0b000"; + parameter CSDECODE_R = "0b000"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI17; + input DI16; + input DI15; + input DI14; + input DI13; + input DI12; + input DI11; + input DI10; + input DI9; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input ADW8; + input ADW7; + input ADW6; + input ADW5; + input ADW4; + input ADW3; + input ADW2; + input ADW1; + input ADW0; + input BE1; + input BE0; + input CEW; + input CLKW; + input CSW2; + input CSW1; + input CSW0; + input ADR12; + input ADR11; + input ADR10; + input ADR9; + input ADR8; + input ADR7; + input ADR6; + input ADR5; + input ADR4; + input ADR3; + input ADR2; + input ADR1; + input ADR0; + input CER; + input OCER; + input CLKR; + input CSR2; + input CSR1; + input CSR0; + input RST; + output DO17; + output DO16; + output DO15; + output DO14; + output DO13; + output DO12; + output DO11; + output DO10; + output DO9; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module SP8KC (...); + parameter DATA_WIDTH = 9; + parameter REGMODE = "NOREG"; + parameter CSDECODE = "0b000"; + parameter WRITEMODE = "NORMAL"; + parameter GSR = "ENABLED"; + parameter RESETMODE = "SYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter INIT_DATA = "STATIC"; + parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; + input DI8; + input DI7; + input DI6; + input DI5; + input DI4; + input DI3; + input DI2; + input DI1; + input DI0; + input AD12; + input AD11; + input AD10; + input AD9; + input AD8; + input AD7; + input AD6; + input AD5; + input AD4; + input AD3; + input AD2; + input AD1; + input AD0; + input CE; + input OCE; + input CLK; + input WE; + input CS2; + input CS1; + input CS0; + input RST; + output DO8; + output DO7; + output DO6; + output DO5; + output DO4; + output DO3; + output DO2; + output DO1; + output DO0; +endmodule + +(* blackbox *) +module FIFO8KB (...); + parameter DATA_WIDTH_W = 18; + parameter DATA_WIDTH_R = 18; + parameter REGMODE = "NOREG"; + parameter RESETMODE = "ASYNC"; + parameter ASYNC_RESET_RELEASE = "SYNC"; + parameter CSDECODE_W = "0b00"; + parameter CSDECODE_R = "0b00"; + parameter AEPOINTER = "0b00000000000000"; + parameter AEPOINTER1 = "0b00000000000000"; + parameter AFPOINTER = "0b00000000000000"; + parameter AFPOINTER1 = "0b00000000000000"; + parameter FULLPOINTER = "0b00000000000000"; + parameter FULLPOINTER1 = "0b00000000000000"; + parameter GSR = "DISABLED"; + input DI0; + input DI1; + input DI2; + input DI3; + input DI4; + input DI5; + input DI6; + input DI7; + input DI8; + input DI9; + input DI10; + input DI11; + input DI12; + input DI13; + input DI14; + input DI15; + input DI16; + input DI17; + input CSW0; + input CSW1; + input CSR0; + input CSR1; + input WE; + input RE; + input ORE; + input CLKW; + input CLKR; + input RST; + input RPRST; + input FULLI; + input EMPTYI; + output DO0; + output DO1; + output DO2; + output DO3; + output DO4; + output DO5; + output DO6; + output DO7; + output DO8; + output DO9; + output DO10; + output DO11; + output DO12; + output DO13; + output DO14; + output DO15; + output DO16; + output DO17; + output EF; + output AEF; + output AFF; + output FF; +endmodule + +(* blackbox *) +module CLKDIVC (...); + parameter GSR = "DISABLED"; + parameter DIV = "2.0"; + input RST; + input CLKI; + input ALIGNWD; + output CDIV1; + output CDIVX; +endmodule + +(* blackbox *) +module DCMA (...); + input CLK0; + input CLK1; + input SEL; + output DCMOUT; +endmodule + +(* blackbox *) +module ECLKSYNCA (...); + input ECLKI; + input STOP; + output ECLKO; +endmodule + +(* blackbox *) +module ECLKBRIDGECS (...); + input CLK0; + input CLK1; + input SEL; + output ECSOUT; +endmodule + +(* blackbox *) +module DCCA (...); + input CLKI; + input CE; + output CLKO; +endmodule + +(* blackbox *) (* keep *) +module START (...); + input STARTCLK; +endmodule + +(* blackbox *) +module EHXPLLJ (...); + parameter CLKI_DIV = 1; + parameter CLKFB_DIV = 1; + parameter CLKOP_DIV = 8; + parameter CLKOS_DIV = 8; + parameter CLKOS2_DIV = 8; + parameter CLKOS3_DIV = 8; + parameter CLKOP_ENABLE = "ENABLED"; + parameter CLKOS_ENABLE = "ENABLED"; + parameter CLKOS2_ENABLE = "ENABLED"; + parameter CLKOS3_ENABLE = "ENABLED"; + parameter VCO_BYPASS_A0 = "DISABLED"; + parameter VCO_BYPASS_B0 = "DISABLED"; + parameter VCO_BYPASS_C0 = "DISABLED"; + parameter VCO_BYPASS_D0 = "DISABLED"; + parameter CLKOP_CPHASE = 0; + parameter CLKOS_CPHASE = 0; + parameter CLKOS2_CPHASE = 0; + parameter CLKOS3_CPHASE = 0; + parameter CLKOP_FPHASE = 0; + parameter CLKOS_FPHASE = 0; + parameter CLKOS2_FPHASE = 0; + parameter CLKOS3_FPHASE = 0; + parameter FEEDBK_PATH = "CLKOP"; + parameter FRACN_ENABLE = "DISABLED"; + parameter FRACN_DIV = 0; + parameter CLKOP_TRIM_POL = "RISING"; + parameter CLKOP_TRIM_DELAY = 0; + parameter CLKOS_TRIM_POL = "RISING"; + parameter CLKOS_TRIM_DELAY = 0; + parameter PLL_USE_WB = "DISABLED"; + parameter PREDIVIDER_MUXA1 = 0; + parameter PREDIVIDER_MUXB1 = 0; + parameter PREDIVIDER_MUXC1 = 0; + parameter PREDIVIDER_MUXD1 = 0; + parameter OUTDIVIDER_MUXA2 = "DIVA"; + parameter OUTDIVIDER_MUXB2 = "DIVB"; + parameter OUTDIVIDER_MUXC2 = "DIVC"; + parameter OUTDIVIDER_MUXD2 = "DIVD"; + parameter PLL_LOCK_MODE = 0; + parameter STDBY_ENABLE = "DISABLED"; + parameter DPHASE_SOURCE = "DISABLED"; + parameter PLLRST_ENA = "DISABLED"; + parameter MRST_ENA = "DISABLED"; + parameter DCRST_ENA = "DISABLED"; + parameter DDRST_ENA = "DISABLED"; + parameter INTFB_WAKE = "DISABLED"; + input CLKI; + input CLKFB; + input PHASESEL1; + input PHASESEL0; + input PHASEDIR; + input PHASESTEP; + input LOADREG; + input STDBY; + input PLLWAKESYNC; + input RST; + input RESETM; + input RESETC; + input RESETD; + input ENCLKOP; + input ENCLKOS; + input ENCLKOS2; + input ENCLKOS3; + input PLLCLK; + input PLLRST; + input PLLSTB; + input PLLWE; + input PLLDATI7; + input PLLDATI6; + input PLLDATI5; + input PLLDATI4; + input PLLDATI3; + input PLLDATI2; + input PLLDATI1; + input PLLDATI0; + input PLLADDR4; + input PLLADDR3; + input PLLADDR2; + input PLLADDR1; + input PLLADDR0; + output CLKOP; + output CLKOS; + output CLKOS2; + output CLKOS3; + output LOCK; + output INTLOCK; + output REFCLK; + output PLLDATO7; + output PLLDATO6; + output PLLDATO5; + output PLLDATO4; + output PLLDATO3; + output PLLDATO2; + output PLLDATO1; + output PLLDATO0; + output PLLACK; + output DPHSRC; + output CLKINTFB; +endmodule + +(* blackbox *) +module OSCJ (...); + parameter NOM_FREQ = "2.08"; + input STDBY; + output OSC; + output SEDSTDBY; + output OSCESB; +endmodule + +(* blackbox *) (* keep *) +module TSALL (...); + input TSALL; +endmodule + diff --git a/techlibs/lattice/cells_ff.vh b/techlibs/lattice/cells_ff.vh new file mode 100644 index 00000000000..6b745f391ee --- /dev/null +++ b/techlibs/lattice/cells_ff.vh @@ -0,0 +1,40 @@ +// Diamond flip-flops +module FD1P3AX(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3AY(input D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3BX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3DX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3IX(input CD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1P3JX(input PD, D, SP, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module FD1S3AX(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .DI(D), .Q(Q)); endmodule +module FD1S3AY(input D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(|0), .DI(D), .Q(Q)); endmodule +module FD1S3BX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule +module FD1S3DX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3IX(input CD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(CD), .DI(D), .Q(Q)); endmodule +module FD1S3JX(input PD, D, CK, output Q); parameter GSR = "ENABLED"; TRELLIS_FF #(.GSR(GSR), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond latches +// module FL1P3AY(); endmodule +// module FL1P3AZ(); endmodule +// module FL1P3BX(); endmodule +// module FL1P3DX(); endmodule +// module FL1P3IY(); endmodule +// module FL1P3JY(); endmodule +// module FL1S3AX(); endmodule +// module FL1S3AY(); endmodule + +// Diamond I/O registers +module IFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module IFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="input" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +module OFS1P3BX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3DX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3IX(input CD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(CD), .CE(SP), .DI(D), .Q(Q)); endmodule +module OFS1P3JX(input PD, D, SP, SCLK, output Q); parameter GSR = "ENABLED"; (* syn_useioff, ioff_dir="output" *) TRELLIS_FF #(.GSR(GSR), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(SCLK), .LSR(PD), .CE(SP), .DI(D), .Q(Q)); endmodule + +// TODO: Diamond I/O latches +// module IFS1S1B(input PD, D, SCLK, output Q); endmodule +// module IFS1S1D(input CD, D, SCLK, output Q); endmodule +// module IFS1S1I(input PD, D, SCLK, output Q); endmodule +// module IFS1S1J(input CD, D, SCLK, output Q); endmodule diff --git a/techlibs/lattice/cells_io.vh b/techlibs/lattice/cells_io.vh new file mode 100644 index 00000000000..220460c4467 --- /dev/null +++ b/techlibs/lattice/cells_io.vh @@ -0,0 +1,14 @@ +// Diamond I/O buffers +module IB ((* iopad_external_pin *) input I, output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPU ((* iopad_external_pin *) input I, output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module IBPD ((* iopad_external_pin *) input I, output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(I), .O(O)); endmodule +module OB (input I, (* iopad_external_pin *) output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I)); endmodule +module OBZ (input I, T, (* iopad_external_pin *) output O); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPU(input I, T, (* iopad_external_pin *) output O); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBZPD(input I, T, (* iopad_external_pin *) output O); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(O), .I(I), .T(T)); endmodule +module OBCO (input I, output OT, OC); OLVDS olvds (.A(I), .Z(OT), .ZN(OC)); endmodule +module BB (input I, T, output O, (* iopad_external_pin *) inout B); (* PULLMODE="NONE" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPU (input I, T, output O, (* iopad_external_pin *) inout B); (* PULLMODE="UP" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module BBPD (input I, T, output O, (* iopad_external_pin *) inout B); (* PULLMODE="DOWN" *) TRELLIS_IO #(.DIR("BIDIR")) _TECHMAP_REPLACE_ (.B(B), .I(I), .O(O), .T(T)); endmodule +module ILVDS(input A, AN, (* iopad_external_pin *) output Z ); TRELLIS_IO #(.DIR("INPUT")) _TECHMAP_REPLACE_ (.B(A), .O(Z)); endmodule +module OLVDS(input A, (* iopad_external_pin *) output Z, output ZN); TRELLIS_IO #(.DIR("OUTPUT")) _TECHMAP_REPLACE_ (.B(Z), .I(A)); endmodule diff --git a/techlibs/machxo2/cells_map.v b/techlibs/lattice/cells_map.v similarity index 64% rename from techlibs/machxo2/cells_map.v rename to techlibs/lattice/cells_map.v index 22994a634df..4944ece4569 100644 --- a/techlibs/machxo2/cells_map.v +++ b/techlibs/lattice/cells_map.v @@ -88,30 +88,104 @@ module \$_SDFFE_NP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), module \$_SDFFE_PP0N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule module \$_SDFFE_PP1N_ (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("AUTO"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); wire _TECHMAP_REMOVEINIT_Q_ = 1'b1; endmodule -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; - input [WIDTH-1:0] A; - output Y; - - localparam rep = 1<<(4-WIDTH); - wire [3:0] I; - - generate - if(WIDTH == 1) begin - assign I = {1'b0, 1'b0, 1'b0, A[0]}; - end else if(WIDTH == 2) begin - assign I = {1'b0, 1'b0, A[1], A[0]}; - end else if(WIDTH == 3) begin - assign I = {1'b0, A[2], A[1], A[0]}; - end else if(WIDTH == 4) begin - assign I = {A[3], A[2], A[1], A[0]}; - end else begin - wire _TECHMAP_FAIL_ = 1; - end - endgenerate - - LUT4 #(.INIT({rep{LUT}})) _TECHMAP_REPLACE_ (.A(I[0]), .B(I[1]), .C(I[2]), .D(I[3]), .Z(Y)); -endmodule +module \$_ALDFF_NP_ (input C, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule +module \$_ALDFF_PP_ (input C, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule +module \$_ALDFFE_NPN_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule +module \$_ALDFFE_NPP_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("INV"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule +module \$_ALDFFE_PPN_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("INV"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule +module \$_ALDFFE_PPP_ (input C, E, L, AD, D, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMODE("PRLD"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(L), .DI(D), .M(AD), .Q(Q)); endmodule + +`include "cells_ff.vh" `include "cells_io.vh" + +`ifndef NO_LUT +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + (* force_downto *) + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + localparam [15:0] INIT = {{8{LUT[1]}}, {8{LUT[0]}}}; + LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(1'b0), .C(1'b0), .D(A[0])); + end else + if (WIDTH == 2) begin + localparam [15:0] INIT = {{4{LUT[3]}}, {4{LUT[2]}}, {4{LUT[1]}}, {4{LUT[0]}}}; + LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(1'b0), .C(A[0]), .D(A[1])); + end else + if (WIDTH == 3) begin + localparam [15:0] INIT = {{2{LUT[7]}}, {2{LUT[6]}}, {2{LUT[5]}}, {2{LUT[4]}}, {2{LUT[3]}}, {2{LUT[2]}}, {2{LUT[1]}}, {2{LUT[0]}}}; + LUT4 #(.INIT(INIT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(1'b0), .B(A[0]), .C(A[1]), .D(A[2])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.Z(Y), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + `ifndef NO_PFUMUX + end else + if (WIDTH == 5) begin + wire f0, f1; + LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + PFUMX mux5(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(Y)); + end else + if (WIDTH == 6) begin + wire f0, f1, f2, f3, g0, g1; + LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); + PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); + L6MUX21 mux6 (.D0(g0), .D1(g1), .SD(A[5]), .Z(Y)); + end else + if (WIDTH == 7) begin + wire f0, f1, f2, f3, f4, f5, f6, f7, g0, g1, g2, g3, h0, h1; + LUT4 #(.INIT(LUT[15: 0])) lut0 (.Z(f0), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[31:16])) lut1 (.Z(f1), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + LUT4 #(.INIT(LUT[47:32])) lut2 (.Z(f2), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[63:48])) lut3 (.Z(f3), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + LUT4 #(.INIT(LUT[79:64])) lut4 (.Z(f4), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[95:80])) lut5 (.Z(f5), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + LUT4 #(.INIT(LUT[111: 96])) lut6 (.Z(f6), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + LUT4 #(.INIT(LUT[127:112])) lut7 (.Z(f7), + .A(A[0]), .B(A[1]), .C(A[2]), .D(A[3])); + + PFUMX mux50(.ALUT(f1), .BLUT(f0), .C0(A[4]), .Z(g0)); + PFUMX mux51(.ALUT(f3), .BLUT(f2), .C0(A[4]), .Z(g1)); + PFUMX mux52(.ALUT(f5), .BLUT(f4), .C0(A[4]), .Z(g2)); + PFUMX mux53(.ALUT(f7), .BLUT(f6), .C0(A[4]), .Z(g3)); + L6MUX21 mux60 (.D0(g0), .D1(g1), .SD(A[5]), .Z(h0)); + L6MUX21 mux61 (.D0(g2), .D1(g3), .SD(A[5]), .Z(h1)); + L6MUX21 mux7 (.D0(h0), .D1(h1), .SD(A[6]), .Z(Y)); + `endif + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule +`endif diff --git a/techlibs/lattice/cells_sim_ecp5.v b/techlibs/lattice/cells_sim_ecp5.v new file mode 100644 index 00000000000..9439e3a5b31 --- /dev/null +++ b/techlibs/lattice/cells_sim_ecp5.v @@ -0,0 +1,9 @@ +`include "common_sim.vh" +`include "ccu2c_sim.vh" + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/lattice/cells_sim_xo2.v b/techlibs/lattice/cells_sim_xo2.v new file mode 100644 index 00000000000..54414287572 --- /dev/null +++ b/techlibs/lattice/cells_sim_xo2.v @@ -0,0 +1,9 @@ +`include "common_sim.vh" +`include "ccu2d_sim.vh" + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/lattice/cells_sim_xo3.v b/techlibs/lattice/cells_sim_xo3.v new file mode 100644 index 00000000000..54414287572 --- /dev/null +++ b/techlibs/lattice/cells_sim_xo3.v @@ -0,0 +1,9 @@ +`include "common_sim.vh" +`include "ccu2d_sim.vh" + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/lattice/cells_sim_xo3d.v b/techlibs/lattice/cells_sim_xo3d.v new file mode 100644 index 00000000000..54414287572 --- /dev/null +++ b/techlibs/lattice/cells_sim_xo3d.v @@ -0,0 +1,9 @@ +`include "common_sim.vh" +`include "ccu2d_sim.vh" + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/lattice/cells_xtra.py b/techlibs/lattice/cells_xtra.py new file mode 100644 index 00000000000..c17281cc753 --- /dev/null +++ b/techlibs/lattice/cells_xtra.py @@ -0,0 +1,856 @@ +#!/usr/bin/env python3 + +# Based on Xilinx cells_xtra.py; modified for Lattice's structure + +from argparse import ArgumentParser +from io import StringIO +from enum import Enum, auto +import os.path +import sys +import re + + +class Cell: + def __init__(self, name, keep=False, port_attrs={}): + self.name = name + self.keep = keep + self.port_attrs = port_attrs + self.found = False + +class State(Enum): + OUTSIDE = auto() + IN_MODULE = auto() + IN_OTHER_MODULE = auto() + IN_FUNCTION = auto() + IN_TASK = auto() + +devices = [ + ("cells_bb_ecp5.v", "ecp5u", [ + #Cell("AND2"), + #Cell("AND3"), + #Cell("AND4"), + #Cell("AND5"), + #Cell("BB"), + #Cell("BBPD"), + #Cell("BBPU"), + #Cell("CCU2C"), + #Cell("FD1P3AX"), + #Cell("FD1P3AY"), + #Cell("FD1P3BX"), + #Cell("FD1P3DX"), + #Cell("FD1P3IX"), + #Cell("FD1P3JX"), + #Cell("FD1S3AX"), + #Cell("FD1S3AY"), + #Cell("FD1S3BX"), + #Cell("FD1S3DX"), + #Cell("FD1S3IX"), + #Cell("FD1S3JX"), + #Cell("FL1P3AY"), + #Cell("FL1P3AZ"), + #Cell("FL1P3BX"), + #Cell("FL1P3DX"), + #Cell("FL1P3IY"), + #Cell("FL1P3JY"), + #Cell("FL1S3AX"), + #Cell("FL1S3AY"), + Cell("GSR", True), + #Cell("IB"), + #Cell("IBPD"), + #Cell("IBPU"), + #Cell("IFS1P3BX"), + #Cell("IFS1P3DX"), + #Cell("IFS1P3IX"), + #Cell("IFS1P3JX"), + #Cell("IFS1S1B"), + #Cell("IFS1S1D"), + #Cell("IFS1S1I"), + #Cell("IFS1S1J"), + #Cell("ILVDS"), + #Cell("INV"), + #Cell("L6MUX21"), + #Cell("LUT4"), + #Cell("LUT5"), + #Cell("LUT6"), + #Cell("LUT7"), + #Cell("LUT8"), + #Cell("MUX161"), + #Cell("MUX21"), + #Cell("MUX321"), + #Cell("MUX41"), + #Cell("MUX81"), + #Cell("ND2"), + #Cell("ND3"), + #Cell("ND4"), + #Cell("ND5"), + #Cell("NR2"), + #Cell("NR3"), + #Cell("NR4"), + #Cell("NR5"), + #Cell("OB"), + #Cell("OBCO"), + #Cell("OBZ"), + #Cell("OBZPU"), + #Cell("OFS1P3BX"), + #Cell("OFS1P3DX"), + #Cell("OFS1P3IX"), + #Cell("OFS1P3JX"), + #Cell("OLVDS"), + #Cell("OR2"), + #Cell("OR3"), + #Cell("OR4"), + #Cell("OR5"), + #Cell("PFUMX"), + Cell("PUR"), + #Cell("ROM128X1A"), + #Cell("ROM16X1A"), + #Cell("ROM256X1A"), + #Cell("ROM32X1A"), + #Cell("ROM64X1A"), + Cell("SGSR", True), + #Cell("VHI"), + #Cell("VLO"), + #Cell("XNOR2"), + #Cell("XNOR3"), + #Cell("XNOR4"), + #Cell("XNOR5"), + #Cell("XOR11"), + #Cell("XOR2"), + #Cell("XOR21"), + #Cell("XOR3"), + #Cell("XOR4"), + #Cell("XOR5"), + Cell("DP16KD"), + Cell("PDPW16KD"), + #Cell("DPR16X4C"), + #Cell("SPR16X4C"), + #Cell("LVDSOB"), + #Cell("IMIPI"), + #Cell("MULT9X9C"), + #Cell("MULT9X9D"), + #Cell("MULT18X18C"), + Cell("MULT18X18D"), + #Cell("ALU24A"), + #Cell("ALU54A"), + #Cell("ALU24B"), + Cell("ALU54B"), + #Cell("PRADD9A"), + #Cell("PRADD18A"), + #Cell("BCINRD"), + #Cell("BCLVDSOB"), + #Cell("INRDB"), + Cell("CLKDIVF"), + Cell("PCSCLKDIV"), + Cell("DCSC"), + Cell("DCCA"), + Cell("ECLKSYNCB"), + Cell("ECLKBRIDGECS"), + #Cell("PLLREFCS"), + Cell("DELAYF"), + Cell("DELAYG"), + #Cell("START"), + Cell("USRMCLK", True), + Cell("DQSBUFM"), + Cell("DDRDLLA"), + Cell("DLLDELD"), + Cell("IDDRX1F"), + Cell("IDDRX2F"), + Cell("IDDR71B"), + Cell("IDDRX2DQA"), + Cell("ODDRX1F"), + Cell("ODDRX2F"), + Cell("ODDR71B"), + Cell("OSHX2A"), + Cell("TSHX2DQA"), + Cell("TSHX2DQSA"), + Cell("ODDRX2DQA"), + Cell("ODDRX2DQSB"), + Cell("EHXPLLL"), + Cell("DTR"), + Cell("OSCG"), + Cell("EXTREFB"), + Cell("JTAGG", True, port_attrs={'TCK': ['iopad_external_pin'], 'TMS': ['iopad_external_pin'], 'TDO': ['iopad_external_pin'], 'TDI': ['iopad_external_pin']}), + #Cell("SEDGA"), + Cell("DCUA", True, port_attrs={'CH0_HDINP': ['iopad_external_pin'], 'CH1_HDINP': ['iopad_external_pin'], 'CH0_HDINN': ['iopad_external_pin'], 'CH1_HDINN': ['iopad_external_pin']}), + ]), + ("cells_bb_xo2.v", "machxo2", [ + #Cell("AGEB2"), + #Cell("ALEB2"), + #Cell("AND2"), + #Cell("AND3"), + #Cell("AND4"), + #Cell("AND5"), + #Cell("ANEB2"), + #Cell("BB"), + #Cell("BBPD"), + #Cell("BBPU"), + #Cell("BBW"), + #Cell("CB2"), + #Cell("CD2"), + #Cell("CU2"), + #Cell("FADD2B"), + #Cell("FADSU2"), + #Cell("FD1P3AX"), + #Cell("FD1P3AY"), + #Cell("FD1P3BX"), + #Cell("FD1P3DX"), + #Cell("FD1P3IX"), + #Cell("FD1P3JX"), + #Cell("FD1S1A"), + #Cell("FD1S1AY"), + #Cell("FD1S1B"), + #Cell("FD1S1D"), + #Cell("FD1S1I"), + #Cell("FD1S1J"), + #Cell("FD1S3AX"), + #Cell("FD1S3AY"), + #Cell("FD1S3BX"), + #Cell("FD1S3DX"), + #Cell("FD1S3IX"), + #Cell("FD1S3JX"), + #Cell("FL1P3AY"), + #Cell("FL1P3AZ"), + #Cell("FL1P3BX"), + #Cell("FL1P3DX"), + #Cell("FL1P3IY"), + #Cell("FL1P3JY"), + #Cell("FL1S1A"), + #Cell("FL1S1AY"), + #Cell("FL1S1B"), + #Cell("FL1S1D"), + #Cell("FL1S1I"), + #Cell("FL1S1J"), + #Cell("FL1S3AX"), + #Cell("FL1S3AY"), + #Cell("FSUB2B"), + Cell("GSR", True), + #Cell("IB"), + #Cell("IBPD"), + #Cell("IBPU"), + #Cell("IFS1P3BX"), + #Cell("IFS1P3DX"), + #Cell("IFS1P3IX"), + #Cell("IFS1P3JX"), + #Cell("ILVDS"), + #Cell("INV"), + #Cell("L6MUX21"), + #Cell("LB2P3AX"), + #Cell("LB2P3AY"), + #Cell("LB2P3BX"), + #Cell("LB2P3DX"), + #Cell("LB2P3IX"), + #Cell("LB2P3JX"), + #Cell("LD2P3AX"), + #Cell("LD2P3AY"), + #Cell("LD2P3BX"), + #Cell("LD2P3DX"), + #Cell("LD2P3IX"), + #Cell("LD2P3JX"), + #Cell("LU2P3AX"), + #Cell("LU2P3AY"), + #Cell("LU2P3BX"), + #Cell("LU2P3DX"), + #Cell("LU2P3IX"), + #Cell("LU2P3JX"), + #Cell("MULT2"), + #Cell("MUX161"), + #Cell("MUX21"), + #Cell("MUX321"), + #Cell("MUX41"), + #Cell("MUX81"), + #Cell("ND2"), + #Cell("ND3"), + #Cell("ND4"), + #Cell("ND5"), + #Cell("NR2"), + #Cell("NR3"), + #Cell("NR4"), + #Cell("NR5"), + #Cell("OB"), + #Cell("OBCO"), + #Cell("OBZ"), + #Cell("OBZPU"), + #Cell("OFS1P3BX"), + #Cell("OFS1P3DX"), + #Cell("OFS1P3IX"), + #Cell("OFS1P3JX"), + #Cell("OLVDS"), + #Cell("OR2"), + #Cell("OR3"), + #Cell("OR4"), + #Cell("OR5"), + #Cell("LUT4"), + #Cell("LUT5"), + #Cell("LUT6"), + #Cell("LUT7"), + #Cell("LUT8"), + #Cell("PFUMX"), + #Cell("PUR"), + #Cell("ROM128X1A"), + #Cell("ROM16X1A"), + #Cell("ROM256X1A"), + #Cell("ROM32X1A"), + #Cell("ROM64X1A"), + #Cell("CCU2D"), + #Cell("VHI"), + #Cell("VLO"), + #Cell("XNOR2"), + #Cell("XNOR3"), + #Cell("XNOR4"), + #Cell("XNOR5"), + #Cell("XOR11"), + #Cell("XOR2"), + #Cell("XOR21"), + #Cell("XOR3"), + #Cell("XOR4"), + #Cell("XOR5"), + #Cell("IFS1S1B"), + #Cell("IFS1S1D"), + #Cell("IFS1S1I"), + #Cell("IFS1S1J"), + #Cell("DPR16X4C"), + #Cell("SPR16X4C"), + Cell("SGSR", True), + Cell("DP8KC"), + Cell("PDPW8KC"), + Cell("SP8KC"), + Cell("FIFO8KB"), + Cell("CLKDIVC"), + Cell("DCMA"), + Cell("ECLKSYNCA"), + Cell("ECLKBRIDGECS"), + Cell("DCCA"), + #Cell("JTAGF", True, port_attrs={'TCK': ['iopad_external_pin'], 'TMS': ['iopad_external_pin'], 'TDO': ['iopad_external_pin'], 'TDI': ['iopad_external_pin']}), + Cell("START", True), + #Cell("SEDFA"), + #Cell("SEDFB"), + #Cell("IDDRXE"), + #Cell("IDDRX2E"), + #Cell("IDDRX4B"), + #Cell("IDDRDQSX1A"), + #Cell("IDDRX71A"), + #Cell("ODDRXE"), + #Cell("ODDRX2E"), + #Cell("ODDRX4B"), + #Cell("ODDRDQSX1A"), + #Cell("ODDRX71A"), + #Cell("TDDRA"), + #Cell("DQSBUFH"), + #Cell("DQSDLLC"), + #Cell("DELAYE"), + #Cell("DELAYD"), + #Cell("DLLDELC"), + #Cell("CLKFBBUFA"), + #Cell("PCNTR"), + #Cell("BCINRD"), + #Cell("BCLVDSO"), + #Cell("INRDB"), + #Cell("LVDSOB"), + #Cell("PG"), + Cell("EHXPLLJ"), + #Cell("PLLREFCS"), + Cell("OSCH"), + #Cell("EFB"), + Cell("TSALL", True), + ]), + ("cells_bb_xo3.v", "machxo3lf", [ + #Cell("AGEB2"), + #Cell("ALEB2"), + #Cell("AND2"), + #Cell("AND3"), + #Cell("AND4"), + #Cell("AND5"), + #Cell("ANEB2"), + #Cell("BB"), + #Cell("BBPD"), + #Cell("BBPU"), + #Cell("BBW"), + #Cell("CB2"), + #Cell("CD2"), + #Cell("CU2"), + #Cell("FADD2B"), + #Cell("FADSU2"), + #Cell("FD1P3AX"), + #Cell("FD1P3AY"), + #Cell("FD1P3BX"), + #Cell("FD1P3DX"), + #Cell("FD1P3IX"), + #Cell("FD1P3JX"), + #Cell("FD1S1A"), + #Cell("FD1S1AY"), + #Cell("FD1S1B"), + #Cell("FD1S1D"), + #Cell("FD1S1I"), + #Cell("FD1S1J"), + #Cell("FD1S3AX"), + #Cell("FD1S3AY"), + #Cell("FD1S3BX"), + #Cell("FD1S3DX"), + #Cell("FD1S3IX"), + #Cell("FD1S3JX"), + #Cell("FL1P3AY"), + #Cell("FL1P3AZ"), + #Cell("FL1P3BX"), + #Cell("FL1P3DX"), + #Cell("FL1P3IY"), + #Cell("FL1P3JY"), + #Cell("FL1S1A"), + #Cell("FL1S1AY"), + #Cell("FL1S1B"), + #Cell("FL1S1D"), + #Cell("FL1S1I"), + #Cell("FL1S1J"), + #Cell("FL1S3AX"), + #Cell("FL1S3AY"), + #Cell("FSUB2B"), + Cell("GSR", True), + #Cell("IB"), + #Cell("IBPD"), + #Cell("IBPU"), + #Cell("IFS1P3BX"), + #Cell("IFS1P3DX"), + #Cell("IFS1P3IX"), + #Cell("IFS1P3JX"), + #Cell("ILVDS"), + #Cell("INV"), + #Cell("L6MUX21"), + #Cell("LB2P3AX"), + #Cell("LB2P3AY"), + #Cell("LB2P3BX"), + #Cell("LB2P3DX"), + #Cell("LB2P3IX"), + #Cell("LB2P3JX"), + #Cell("LD2P3AX"), + #Cell("LD2P3AY"), + #Cell("LD2P3BX"), + #Cell("LD2P3DX"), + #Cell("LD2P3IX"), + #Cell("LD2P3JX"), + #Cell("LU2P3AX"), + #Cell("LU2P3AY"), + #Cell("LU2P3BX"), + #Cell("LU2P3DX"), + #Cell("LU2P3IX"), + #Cell("LU2P3JX"), + #Cell("MULT2"), + #Cell("MUX161"), + #Cell("MUX21"), + #Cell("MUX321"), + #Cell("MUX41"), + #Cell("MUX81"), + #Cell("ND2"), + #Cell("ND3"), + #Cell("ND4"), + #Cell("ND5"), + #Cell("NR2"), + #Cell("NR3"), + #Cell("NR4"), + #Cell("NR5"), + #Cell("OB"), + #Cell("OBCO"), + #Cell("OBZ"), + #Cell("OBZPU"), + #Cell("OFS1P3BX"), + #Cell("OFS1P3DX"), + #Cell("OFS1P3IX"), + #Cell("OFS1P3JX"), + #Cell("OLVDS"), + #Cell("OR2"), + #Cell("OR3"), + #Cell("OR4"), + #Cell("OR5"), + #Cell("LUT4"), + #Cell("LUT5"), + #Cell("LUT6"), + #Cell("LUT7"), + #Cell("LUT8"), + #Cell("PFUMX"), + #Cell("PUR"), + #Cell("ROM128X1A"), + #Cell("ROM16X1A"), + #Cell("ROM256X1A"), + #Cell("ROM32X1A"), + #Cell("ROM64X1A"), + #Cell("CCU2D"), + #Cell("VHI"), + #Cell("VLO"), + #Cell("XNOR2"), + #Cell("XNOR3"), + #Cell("XNOR4"), + #Cell("XNOR5"), + #Cell("XOR11"), + #Cell("XOR2"), + #Cell("XOR21"), + #Cell("XOR3"), + #Cell("XOR4"), + #Cell("XOR5"), + #Cell("IFS1S1B"), + #Cell("IFS1S1D"), + #Cell("IFS1S1I"), + #Cell("IFS1S1J"), + #Cell("DPR16X4C"), + #Cell("SPR16X4C"), + Cell("SGSR", True), + Cell("DP8KC"), + Cell("PDPW8KC"), + Cell("SP8KC"), + Cell("FIFO8KB"), + Cell("CLKDIVC"), + Cell("DCMA"), + Cell("ECLKSYNCA"), + Cell("ECLKBRIDGECS"), + Cell("DCCA"), + #Cell("JTAGF", True, port_attrs={'TCK': ['iopad_external_pin'], 'TMS': ['iopad_external_pin'], 'TDO': ['iopad_external_pin'], 'TDI': ['iopad_external_pin']}), + Cell("START", True), + #Cell("SEDFA"), + #Cell("SEDFB"), + #Cell("IDDRXE"), + #Cell("IDDRX2E"), + #Cell("IDDRX4B"), + #Cell("IDDRX71A"), + #Cell("ODDRXE"), + #Cell("ODDRX2E"), + #Cell("ODDRX4B"), + #Cell("ODDRX71A"), + #Cell("DQSDLLC"), + #Cell("DELAYE"), + #Cell("DELAYD"), + #Cell("DLLDELC"), + #Cell("CLKFBBUFA"), + #Cell("PCNTR"), + #Cell("BCINRD"), + #Cell("BCLVDSO"), + #Cell("INRDB"), + #Cell("LVDSOB"), + #Cell("PG"), + Cell("EHXPLLJ"), + #Cell("PLLREFCS"), + Cell("OSCH"), + #Cell("EFB"), + Cell("TSALL", True), + ]), + ("cells_bb_xo3d.v", "machxo3d", [ + #Cell("AGEB2"), + #Cell("ALEB2"), + #Cell("AND2"), + #Cell("AND3"), + #Cell("AND4"), + #Cell("AND5"), + #Cell("ANEB2"), + #Cell("BB"), + #Cell("BBPD"), + #Cell("BBPU"), + #Cell("BBI3C"), + #Cell("BBW"), + #Cell("CB2"), + #Cell("CD2"), + #Cell("CU2"), + #Cell("FADD2B"), + #Cell("FADSU2"), + #Cell("FD1P3AX"), + #Cell("FD1P3AY"), + #Cell("FD1P3BX"), + #Cell("FD1P3DX"), + #Cell("FD1P3IX"), + #Cell("FD1P3JX"), + #Cell("FD1S1A"), + #Cell("FD1S1AY"), + #Cell("FD1S1B"), + #Cell("FD1S1D"), + #Cell("FD1S1I"), + #Cell("FD1S1J"), + #Cell("FD1S3AX"), + #Cell("FD1S3AY"), + #Cell("FD1S3BX"), + #Cell("FD1S3DX"), + #Cell("FD1S3IX"), + #Cell("FD1S3JX"), + #Cell("FL1P3AY"), + #Cell("FL1P3AZ"), + #Cell("FL1P3BX"), + #Cell("FL1P3DX"), + #Cell("FL1P3IY"), + #Cell("FL1P3JY"), + #Cell("FL1S1A"), + #Cell("FL1S1AY"), + #Cell("FL1S1B"), + #Cell("FL1S1D"), + #Cell("FL1S1I"), + #Cell("FL1S1J"), + #Cell("FL1S3AX"), + #Cell("FL1S3AY"), + #Cell("FSUB2B"), + Cell("GSR", True), + #Cell("IB"), + #Cell("IBPD"), + #Cell("IBPU"), + #Cell("IFS1P3BX"), + #Cell("IFS1P3DX"), + #Cell("IFS1P3IX"), + #Cell("IFS1P3JX"), + #Cell("ILVDS"), + #Cell("INV"), + #Cell("L6MUX21"), + #Cell("LB2P3AX"), + #Cell("LB2P3AY"), + #Cell("LB2P3BX"), + #Cell("LB2P3DX"), + #Cell("LB2P3IX"), + #Cell("LB2P3JX"), + #Cell("LD2P3AX"), + #Cell("LD2P3AY"), + #Cell("LD2P3BX"), + #Cell("LD2P3DX"), + #Cell("LD2P3IX"), + #Cell("LD2P3JX"), + #Cell("LU2P3AX"), + #Cell("LU2P3AY"), + #Cell("LU2P3BX"), + #Cell("LU2P3DX"), + #Cell("LU2P3IX"), + #Cell("LU2P3JX"), + #Cell("MULT2"), + #Cell("MUX161"), + #Cell("MUX21"), + #Cell("MUX321"), + #Cell("MUX41"), + #Cell("MUX81"), + #Cell("ND2"), + #Cell("ND3"), + #Cell("ND4"), + #Cell("ND5"), + #Cell("NR2"), + #Cell("NR3"), + #Cell("NR4"), + #Cell("NR5"), + #Cell("OB"), + #Cell("OBCO"), + #Cell("OBZ"), + #Cell("OBZPU"), + #Cell("OFS1P3BX"), + #Cell("OFS1P3DX"), + #Cell("OFS1P3IX"), + #Cell("OFS1P3JX"), + #Cell("OLVDS"), + #Cell("OR2"), + #Cell("OR3"), + #Cell("OR4"), + #Cell("OR5"), + #Cell("LUT4"), + #Cell("LUT5"), + #Cell("LUT6"), + #Cell("LUT7"), + #Cell("LUT8"), + #Cell("PFUMX"), + #Cell("PUR"), + #Cell("ROM128X1A"), + #Cell("ROM16X1A"), + #Cell("ROM256X1A"), + #Cell("ROM32X1A"), + #Cell("ROM64X1A"), + #Cell("CCU2D"), + #Cell("VHI"), + #Cell("VLO"), + #Cell("XNOR2"), + #Cell("XNOR3"), + #Cell("XNOR4"), + #Cell("XNOR5"), + #Cell("XOR11"), + #Cell("XOR2"), + #Cell("XOR21"), + #Cell("XOR3"), + #Cell("XOR4"), + #Cell("XOR5"), + #Cell("IFS1S1B"), + #Cell("IFS1S1D"), + #Cell("IFS1S1I"), + #Cell("IFS1S1J"), + #Cell("DPR16X4C"), + #Cell("SPR16X4C"), + Cell("SGSR", True), + Cell("DP8KC"), + Cell("PDPW8KC"), + Cell("SP8KC"), + Cell("FIFO8KB"), + Cell("CLKDIVC"), + Cell("DCMA"), + Cell("ECLKSYNCA"), + Cell("ECLKBRIDGECS"), + Cell("DCCA"), + #Cell("JTAGF", True, port_attrs={'TCK': ['iopad_external_pin'], 'TMS': ['iopad_external_pin'], 'TDO': ['iopad_external_pin'], 'TDI': ['iopad_external_pin']}), + Cell("START", True), + #Cell("SEDFA"), + #Cell("SEDFB"), + #Cell("IDDRXE"), + #Cell("IDDRX2E"), + #Cell("IDDRX4B"), + #Cell("IDDRX71A"), + #Cell("ODDRXE"), + #Cell("ODDRX2E"), + #Cell("ODDRX4B"), + #Cell("ODDRX71A"), + #Cell("DQSDLLC"), + #Cell("DELAYE"), + #Cell("DELAYD"), + #Cell("DLLDELC"), + #Cell("CLKFBBUFA"), + #Cell("PCNTR"), + #Cell("BCINRD"), + #Cell("BCLVDSO"), + #Cell("INRDB"), + #Cell("LVDSOB"), + #Cell("PG"), + Cell("EHXPLLJ"), + #Cell("PLLREFCS"), + Cell("OSCJ"), + #Cell("EFBB"), + Cell("TSALL", True), + #Cell("ESBA"), + #Cell("BCSLEWRATEA"), + ]) +] + +def xtract_cells_decl(device, cells, dirs, outf): + fname = os.path.join(dir, device + '.v') + with open(fname) as f: + state = State.OUTSIDE + # Probably the most horrible Verilog "parser" ever written. + cell = None + kind = None + for l in f: + l, _, comment = l.partition('//') + l = l.strip() + m = re.search(r'synthesis .*black_box_pad_pin="([^"]*)"', comment) + if m: + iopad_pin = set(m.group(1).split(",")) + + if l.startswith("module "): + cell_name = l[7:l.find('(')].strip() + cell = None + kind = None + module_ports = [] + iopad_pin = set() + if state != State.OUTSIDE: + print('Nested modules in {}.'.format(fname)) + sys.exit(1) + for c in cells: + if c.name != cell_name: + continue + cell = c + state = State.IN_MODULE + outf.write('(* blackbox *)') + if cell.keep: + outf.write(' (* keep *)\n') + else: + outf.write('\n') + outf.write('module {} (...);\n'.format(cell.name)) + cell.found = True + if cell is None: + state = State.IN_OTHER_MODULE + elif l.startswith('task '): + if state == State.IN_MODULE: + state = State.IN_TASK + elif l.startswith('function '): + if state == State.IN_MODULE: + state = State.IN_FUNCTION + elif l == 'endtask': + if state == State.IN_TASK: + state = State.IN_MODULE + elif l == 'endfunction': + if state == State.IN_FUNCTION: + state = State.IN_MODULE + elif l == 'endmodule': + if state == State.IN_MODULE: + for kind, rng, port in module_ports: + for attr in cell.port_attrs.get(port, []): + outf.write(' (* {} *)\n'.format(attr)) + if port in iopad_pin: + outf.write(' (* iopad_external_pin *)\n') + if rng is None: + outf.write(' {} {};\n'.format(kind, port)) + else: + outf.write(' {} {} {};\n'.format(kind, rng, port)) + outf.write(l + '\n') + outf.write('\n') + elif state != State.IN_OTHER_MODULE: + print('endmodule in weird place in {}.'.format(cell.name, fname)) + sys.exit(1) + state = State.OUTSIDE + elif l.startswith(('input ', 'output ', 'inout ')) and state == State.IN_MODULE: + l = l.strip() + if l == "": + continue + if l.endswith((';', ',', ")")): + l = l[:-1] + l = l.replace(")","") + if ';' in l: + print('Weird port line in {} [{}].'.format(fname, l)) + sys.exit(1) + kind, _, ports = l.partition(' ') + for port in ports.split(','): + port = port.strip() + if port.startswith('['): + rng, port = port.split() + else: + rng = None + module_ports.append((kind, rng, port)) + elif l.startswith('parameter ') and state == State.IN_MODULE: + l = l.strip() + if l.endswith((';', ',')): + l = l[:-1] + while ' ' in l: + l = l.replace(' ', ' ') + + if "INITVAL" in l: + l = l.replace('"0x', "320'h") + l = l.replace('"', '') + if ';' in l: + print('Weird parameter line in {} [{}].'.format(fname, l)) + sys.exit(1) + outf.write(' {};\n'.format(l)) + elif kind is not None and state == State.IN_MODULE: + l = l.strip() + if l == "": + continue + if l.endswith((';', ',', ")")): + l = l[:-1] + l = l.replace(")","") + if l == "": + continue + if ';' in l: + print('Weird port line in {} [{}].'.format(fname, l)) + sys.exit(1) + ports = l + for port in ports.split(','): + port = port.strip() + if port.startswith('['): + rng, port = port.split() + else: + rng = None + module_ports.append((kind, rng, port)) + + if state != State.OUTSIDE: + print('endmodule not found in {}.'.format(fname)) + sys.exit(1) + for cell in cells: + if not cell.found: + print('cell {} not found in {}.'.format(cell.name, fname)) +if __name__ == '__main__': + parser = ArgumentParser(description='Extract Lattice blackbox cell definitions from Lattice Diamond.') + parser.add_argument('diamond_dir', nargs='?', default='/usr/local/diamond/3.12/') + args = parser.parse_args() + + dirs = [ + os.path.join(args.diamond_dir, 'cae_library/synthesis/verilog/'), + ] + for dir in dirs: + if not os.path.isdir(dir): + print('{} is not a directory'.format(dir)) + + for fn, device, cells in devices: + out = StringIO() + xtract_cells_decl(device, cells, dirs, out) + with open(fn, 'w') as f: + f.write('// Created by cells_xtra.py from Lattice models\n') + f.write('\n') + f.write(out.getvalue()) diff --git a/techlibs/lattice/common_sim.vh b/techlibs/lattice/common_sim.vh new file mode 100644 index 00000000000..2f8e1db1a82 --- /dev/null +++ b/techlibs/lattice/common_sim.vh @@ -0,0 +1,411 @@ +// --------------------------------------- + +(* abc9_lut=1, lib_whitebox *) +module LUT4(input A, B, C, D, output Z); + parameter [15:0] INIT = 16'h0000; + wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0]; + wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0]; + wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0]; + assign Z = A ? s1[1] : s1[0]; + specify + (A => Z) = 141; + (B => Z) = 275; + (C => Z) = 379; + (D => Z) = 379; + endspecify +endmodule + +// This is a placeholder for ABC9 to extract the area/delay +// cost of 5-input LUTs and is not intended to be instantiated +// LUT5 = 2x LUT4 + PFUMX +(* abc9_lut=2 *) +module \$__ABC9_LUT5 (input M0, D, C, B, A, output Z); + specify + (M0 => Z) = 151; + (D => Z) = 239; + (C => Z) = 373; + (B => Z) = 477; + (A => Z) = 477; + endspecify +endmodule + +// This is a placeholder for ABC9 to extract the area/delay +// of 6-input LUTs and is not intended to be instantiated +// LUT6 = 2x LUT5 + MUX2 +(* abc9_lut=4 *) +module \$__ABC9_LUT6 (input M1, M0, D, C, B, A, output Z); + specify + (M1 => Z) = 148; + (M0 => Z) = 292; + (D => Z) = 380; + (C => Z) = 514; + (B => Z) = 618; + (A => Z) = 618; + endspecify +endmodule + +// This is a placeholder for ABC9 to extract the area/delay +// of 7-input LUTs and is not intended to be instantiated +// LUT7 = 2x LUT6 + MUX2 +(* abc9_lut=8 *) +module \$__ABC9_LUT7 (input M2, M1, M0, D, C, B, A, output Z); + specify + (M2 => Z) = 148; + (M1 => Z) = 289; + (M0 => Z) = 433; + (D => Z) = 521; + (C => Z) = 655; + (B => Z) = 759; + (A => Z) = 759; + endspecify +endmodule + +// --------------------------------------- +(* abc9_box, lib_whitebox *) +module L6MUX21 (input D0, D1, SD, output Z); + assign Z = SD ? D1 : D0; + specify + (D0 => Z) = 140; + (D1 => Z) = 141; + (SD => Z) = 148; + endspecify +endmodule + +// --------------------------------------- + +module TRELLIS_RAM16X2 ( + input DI0, DI1, + input WAD0, WAD1, WAD2, WAD3, + input WRE, WCK, + input RAD0, RAD1, RAD2, RAD3, + output DO0, DO1 +); + parameter WCKMUX = "WCK"; + parameter WREMUX = "WRE"; + parameter INITVAL_0 = 16'h0000; + parameter INITVAL_1 = 16'h0000; + + reg [1:0] mem[15:0]; + + integer i; + initial begin + for (i = 0; i < 16; i = i + 1) + mem[i] <= {INITVAL_1[i], INITVAL_0[i]}; + end + + wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; + + reg muxwre; + always @(*) + case (WREMUX) + "1": muxwre = 1'b1; + "0": muxwre = 1'b0; + "INV": muxwre = ~WRE; + default: muxwre = WRE; + endcase + + + always @(posedge muxwck) + if (muxwre) + mem[{WAD3, WAD2, WAD1, WAD0}] <= {DI1, DI0}; + + assign {DO1, DO0} = mem[{RAD3, RAD2, RAD1, RAD0}]; +endmodule + +// --------------------------------------- +(* abc9_box, lib_whitebox *) +module PFUMX (input ALUT, BLUT, C0, output Z); + assign Z = C0 ? ALUT : BLUT; + specify + (ALUT => Z) = 98; + (BLUT => Z) = 98; + (C0 => Z) = 151; + endspecify +endmodule + +// --------------------------------------- +(* abc9_box, lib_whitebox *) +module TRELLIS_DPR16X4 ( + input [3:0] DI, + input [3:0] WAD, + input WRE, + input WCK, + input [3:0] RAD, + output [3:0] DO +); + parameter WCKMUX = "WCK"; + parameter WREMUX = "WRE"; + parameter [63:0] INITVAL = 64'h0000000000000000; + + reg [3:0] mem[15:0]; + + integer i; + initial begin + for (i = 0; i < 16; i = i + 1) + mem[i] <= INITVAL[4*i +: 4]; + end + + wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; + + reg muxwre; + always @(*) + case (WREMUX) + "1": muxwre = 1'b1; + "0": muxwre = 1'b0; + "INV": muxwre = ~WRE; + default: muxwre = WRE; + endcase + + always @(posedge muxwck) + if (muxwre) + mem[WAD] <= DI; + + assign DO = mem[RAD]; + + specify + // TODO + (RAD *> DO) = 0; + endspecify +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 +); + // For legacy Lattice compatibility, INITIVAL is a hex + // string rather than a numeric parameter + 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]; + + specify + // TODO + (RAD *> DO) = 0; + endspecify +endmodule + +// --------------------------------------- + +(* lib_whitebox *) +module LUT2(input A, B, output Z); + parameter [3:0] INIT = 4'h0; + wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0]; + assign Z = A ? s1[1] : s1[0]; +endmodule + +// --------------------------------------- + +`ifdef YOSYS +(* abc9_flop=(SRMODE != "ASYNC"), abc9_box=(SRMODE == "ASYNC"), lib_whitebox *) +`endif +module TRELLIS_FF(input CLK, LSR, CE, DI, M, output reg Q); + parameter GSR = "ENABLED"; + parameter [127:0] CEMUX = "1"; + parameter CLKMUX = "CLK"; + parameter LSRMUX = "LSR"; + parameter SRMODE = "LSR_OVER_CE"; + parameter REGSET = "RESET"; + parameter [127:0] LSRMODE = "LSR"; + + wire muxce; + generate + case (CEMUX) + "1": assign muxce = 1'b1; + "0": assign muxce = 1'b0; + "INV": assign muxce = ~CE; + default: assign muxce = CE; + endcase + endgenerate + + wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; + wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; + wire srval; + generate + if (LSRMODE == "PRLD") + assign srval = M; + else + assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; + endgenerate + + initial Q = srval; + + generate + if (SRMODE == "ASYNC") begin + always @(posedge muxclk, posedge muxlsr) + if (muxlsr) + Q <= srval; + else if (muxce) + Q <= DI; + end else begin + always @(posedge muxclk) + if (muxlsr) + Q <= srval; + else if (muxce) + Q <= DI; + end + endgenerate + + specify + $setup(DI, negedge CLK &&& CLKMUX == "INV", 0); + $setup(CE, negedge CLK &&& CLKMUX == "INV", 0); + $setup(LSR, negedge CLK &&& CLKMUX == "INV", 0); + $setup(DI, posedge CLK &&& CLKMUX != "INV", 0); + $setup(CE, posedge CLK &&& CLKMUX != "INV", 0); + $setup(LSR, posedge CLK &&& CLKMUX != "INV", 0); +`ifndef YOSYS + if (SRMODE == "ASYNC" && muxlsr && CLKMUX == "INV") (negedge CLK => (Q : srval)) = 0; + if (SRMODE == "ASYNC" && muxlsr && CLKMUX != "INV") (posedge CLK => (Q : srval)) = 0; +`else + if (SRMODE == "ASYNC" && muxlsr) (LSR => Q) = 0; // Technically, this should be an edge sensitive path + // but for facilitating a bypass box, let's pretend it's + // a simple path +`endif + if (!muxlsr && muxce && CLKMUX == "INV") (negedge CLK => (Q : DI)) = 0; + if (!muxlsr && muxce && CLKMUX != "INV") (posedge CLK => (Q : DI)) = 0; + endspecify +endmodule + +// --------------------------------------- +(* keep *) +module TRELLIS_IO( + (* iopad_external_pin *) + inout B, + input I, + input T, + output O +); + parameter DIR = "INPUT"; + reg T_pd; + always @(*) if (T === 1'bz) T_pd <= 1'b0; else T_pd <= T; + + generate + if (DIR == "INPUT") begin + assign B = 1'bz; + assign O = B; + end else if (DIR == "OUTPUT") begin + assign B = T_pd ? 1'bz : I; + assign O = 1'bx; + end else if (DIR == "BIDIR") begin + assign B = T_pd ? 1'bz : I; + assign O = B; + end else begin + ERROR_UNKNOWN_IO_MODE error(); + end + endgenerate + +endmodule + +// --------------------------------------- + +module INV(input A, output Z); + assign Z = !A; +endmodule + +// --------------------------------------- + +module TRELLIS_COMB( + input A, B, C, D, M, + input FCI, F1, FXA, FXB, + input WD, + input WAD0, WAD1, WAD2, WAD3, + input WRE, WCK, + output F, FCO, OFX +); + parameter MODE = "LOGIC"; + parameter INITVAL = 16'h0; + parameter CCU2_INJECT1 = "NO"; + parameter WREMUX = "WRE"; + parameter IS_Z1 = 1'b0; + + generate + if (MODE == "LOGIC") begin: mode_logic + LUT4 #(.INIT(INITVAL)) lut4 (.A(A), .B(B), .C(C), .D(D), .Z(F)); + end else if (MODE == "CCU2") begin: mode_ccu2 + wire l4o, l2o; + LUT4 #(.INIT(INITVAL)) lut4_0(.A(A), .B(B), .C(C), .D(D), .Z(l4o)); + LUT2 #(.INIT(INITVAL[3:0])) lut2_0(.A(A), .B(B), .Z(l2o)); + wire gated_cin_0 = (CCU2_INJECT1 == "YES") ? 1'b0 : FCI; + assign F = l4o ^ gated_cin_0; + wire gated_lut2_0 = (CCU2_INJECT1 == "YES") ? 1'b0 : l2o; + wire FCO = (~l4o & gated_lut2_0) | (l4o & FCI); + end else if (MODE == "DPRAM") begin: mode_dpram + reg [15:0] ram = INITVAL; + always @(posedge WCK) + if (WRE) + ram[{WAD3, WAD2, WAD1, WAD0}] <= WD; + assign F = ram[{A, C, B, D}]; + end else begin + $error("unsupported COMB mode %s", MODE); + end + + if (IS_Z1) + L6MUX21 lutx_mux (.D0(FXA), .D1(FXB), .SD(M), .Z(OFX)); + else + PFUMX lut5_mux (.ALUT(F1), .BLUT(F), .C0(M), .Z(OFX)); + endgenerate + +endmodule + +// Constants +module VLO(output Z); + assign Z = 1'b0; +endmodule + +module VHI(output Z); + assign Z = 1'b1; +endmodule + +`ifndef NO_INCLUDES + +`include "cells_ff.vh" +`include "cells_io.vh" + +`endif diff --git a/techlibs/lattice/dsp_map_18x18.v b/techlibs/lattice/dsp_map_18x18.v new file mode 100644 index 00000000000..df54d1d9f9f --- /dev/null +++ b/techlibs/lattice/dsp_map_18x18.v @@ -0,0 +1,17 @@ +module \$__MUL18X18 (input [17:0] A, input [17:0] B, output [35:0] Y); + + parameter A_WIDTH = 18; + parameter B_WIDTH = 18; + parameter Y_WIDTH = 36; + parameter A_SIGNED = 0; + parameter B_SIGNED = 0; + + MULT18X18D _TECHMAP_REPLACE_ ( + .A0(A[0]), .A1(A[1]), .A2(A[2]), .A3(A[3]), .A4(A[4]), .A5(A[5]), .A6(A[6]), .A7(A[7]), .A8(A[8]), .A9(A[9]), .A10(A[10]), .A11(A[11]), .A12(A[12]), .A13(A[13]), .A14(A[14]), .A15(A[15]), .A16(A[16]), .A17(A[17]), + .B0(B[0]), .B1(B[1]), .B2(B[2]), .B3(B[3]), .B4(B[4]), .B5(B[5]), .B6(B[6]), .B7(B[7]), .B8(B[8]), .B9(B[9]), .B10(B[10]), .B11(B[11]), .B12(B[12]), .B13(B[13]), .B14(B[14]), .B15(B[15]), .B16(B[16]), .B17(B[17]), + .C17(1'b0), .C16(1'b0), .C15(1'b0), .C14(1'b0), .C13(1'b0), .C12(1'b0), .C11(1'b0), .C10(1'b0), .C9(1'b0), .C8(1'b0), .C7(1'b0), .C6(1'b0), .C5(1'b0), .C4(1'b0), .C3(1'b0), .C2(1'b0), .C1(1'b0), .C0(1'b0), + .SIGNEDA(A_SIGNED ? 1'b1 : 1'b0), .SIGNEDB(B_SIGNED ? 1'b1 : 1'b0), .SOURCEA(1'b0), .SOURCEB(1'b0), + + .P0(Y[0]), .P1(Y[1]), .P2(Y[2]), .P3(Y[3]), .P4(Y[4]), .P5(Y[5]), .P6(Y[6]), .P7(Y[7]), .P8(Y[8]), .P9(Y[9]), .P10(Y[10]), .P11(Y[11]), .P12(Y[12]), .P13(Y[13]), .P14(Y[14]), .P15(Y[15]), .P16(Y[16]), .P17(Y[17]), .P18(Y[18]), .P19(Y[19]), .P20(Y[20]), .P21(Y[21]), .P22(Y[22]), .P23(Y[23]), .P24(Y[24]), .P25(Y[25]), .P26(Y[26]), .P27(Y[27]), .P28(Y[28]), .P29(Y[29]), .P30(Y[30]), .P31(Y[31]), .P32(Y[32]), .P33(Y[33]), .P34(Y[34]), .P35(Y[35]) + ); +endmodule diff --git a/techlibs/lattice/latches_map.v b/techlibs/lattice/latches_map.v new file mode 100644 index 00000000000..c28f88cf767 --- /dev/null +++ b/techlibs/lattice/latches_map.v @@ -0,0 +1,11 @@ +module \$_DLATCH_N_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = !E ? D : Q; +endmodule + +module \$_DLATCH_P_ (E, D, Q); + wire [1023:0] _TECHMAP_DO_ = "simplemap; opt"; + input E, D; + output Q = E ? D : Q; +endmodule diff --git a/techlibs/ecp5/ecp5_gsr.cc b/techlibs/lattice/lattice_gsr.cc similarity index 93% rename from techlibs/ecp5/ecp5_gsr.cc rename to techlibs/lattice/lattice_gsr.cc index 62b231aab3b..d7d41eca519 100644 --- a/techlibs/ecp5/ecp5_gsr.cc +++ b/techlibs/lattice/lattice_gsr.cc @@ -24,13 +24,13 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -struct Ecp5GsrPass : public Pass { - Ecp5GsrPass() : Pass("ecp5_gsr", "ECP5: handle GSR") { } +struct LatticeGsrPass : public Pass { + LatticeGsrPass() : Pass("lattice_gsr", "Lattice: handle GSR") { } void help() override { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| log("\n"); - log(" ecp5_gsr [options] [selection]\n"); + log(" lattice_gsr [options] [selection]\n"); log("\n"); log("Trim active low async resets connected to GSR and resolve GSR parameter,\n"); log("if a GSR or SGSR primitive is used in the design.\n"); @@ -42,7 +42,7 @@ struct Ecp5GsrPass : public Pass { } void execute(std::vector args, RTLIL::Design *design) override { - log_header(design, "Executing ECP5_GSR pass (implement FF init values).\n"); + log_header(design, "Executing LATTICE_GSR pass (implement FF init values).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -130,6 +130,6 @@ struct Ecp5GsrPass : public Pass { } } -} Ecp5GsrPass; +} LatticeGsrPass; PRIVATE_NAMESPACE_END diff --git a/techlibs/lattice/lutrams.txt b/techlibs/lattice/lutrams.txt new file mode 100644 index 00000000000..ea42d4fcb5e --- /dev/null +++ b/techlibs/lattice/lutrams.txt @@ -0,0 +1,12 @@ +ram distributed $__TRELLIS_DPR16X4_ { + abits 4; + width 4; + cost 4; + init any; + prune_rom; + port sw "W" { + clock anyedge; + } + port ar "R" { + } +} diff --git a/techlibs/lattice/lutrams_map.v b/techlibs/lattice/lutrams_map.v new file mode 100644 index 00000000000..3cb325f041e --- /dev/null +++ b/techlibs/lattice/lutrams_map.v @@ -0,0 +1,30 @@ +module $__TRELLIS_DPR16X4_(...); + +parameter INIT = 64'bx; +parameter PORT_W_CLK_POL = 1; + +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; + +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) +); + +endmodule diff --git a/techlibs/lattice/synth_lattice.cc b/techlibs/lattice/synth_lattice.cc new file mode 100644 index 00000000000..e2987d0259e --- /dev/null +++ b/techlibs/lattice/synth_lattice.cc @@ -0,0 +1,503 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Claire Xenia Wolf + * Copyright (C) 2018 gatecat + * + * 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/celltypes.h" +#include "kernel/rtlil.h" +#include "kernel/log.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SynthLatticePass : public ScriptPass +{ + SynthLatticePass() : ScriptPass("synth_lattice", "synthesis for Lattice FPGAs") { } + + void on_register() override + { + RTLIL::constpad["synth_lattice.abc9.W"] = "300"; + } + + void help() override + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" synth_lattice [options]\n"); + log("\n"); + log("This command runs synthesis for Lattice FPGAs (excluding iCE40 and Nexus).\n"); + log("\n"); + log(" -top \n"); + log(" use the specified module as top module\n"); + log("\n"); + log(" -family \n"); + log(" run synthesis for the specified Lattice architecture\n"); + log(" generate the synthesis netlist for the specified family.\n"); + log(" supported values:\n"); + log(" - ecp5: ECP5\n"); + log(" - xo2: MachXO2\n"); + log(" - xo3: MachXO3L/LF\n"); + log(" - xo3d: MachXO3D\n"); + //log(" - xo: MachXO (EXPERIMENTAL)\n"); + //log(" - pm: Platform Manager (EXPERIMENTAL)\n"); + //log(" - pm2: Platform Manager 2 (EXPERIMENTAL)\n"); + //log(" - xp: LatticeXP (EXPERIMENTAL)\n"); + //log(" - xp2: LatticeXP2 (EXPERIMENTAL)\n"); + //log(" - ecp: LatticeECP/EC (EXPERIMENTAL)\n"); + //log(" - sm: LatticeSC/M (EXPERIMENTAL)\n"); + //log(" - ecp2: LatticeECP2/M (EXPERIMENTAL)\n"); + //log(" - ecp3: LatticeECP3 (EXPERIMENTAL)\n"); + //log(" - lifmd: LIFMD (EXPERIMENTAL)\n"); + //log(" - lifmdf: LIFMDF (EXPERIMENTAL)\n"); + log("\n"); + log(" -edif \n"); + log(" write the design to the specified EDIF file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -json \n"); + log(" write the design to the specified JSON file. writing of an output file\n"); + log(" is omitted if this parameter is not specified.\n"); + log("\n"); + log(" -run :\n"); + log(" only run the commands between the labels (see below). an empty\n"); + 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(" -noflatten\n"); + log(" do not flatten design before synthesis\n"); + log("\n"); + log(" -dff\n"); + log(" run 'abc'/'abc9' with -dff option\n"); + log("\n"); + log(" -retime\n"); + log(" run 'abc' with '-dff -D 1' options\n"); + log("\n"); + log(" -noccu2\n"); + log(" do not use CCU2 cells in output netlist\n"); + log("\n"); + log(" -nodffe\n"); + log(" do not use flipflops with CE in output netlist\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(" -nowidelut\n"); + log(" do not use PFU muxes to implement LUTs larger than LUT4s\n"); + log(" (by default enabled on MachXO2/XO3/XO3D)\n"); + log("\n"); + log(" -widelut\n"); + log(" force use of PFU muxes to implement LUTs larger than LUT4s\n"); + log("\n"); + log(" -asyncprld\n"); + log(" use async PRLD mode to implement ALDFF (EXPERIMENTAL)\n"); + log("\n"); + log(" -abc2\n"); + log(" run two passes of 'abc' for slightly improved logic density\n"); + log("\n"); + log(" -abc9\n"); + log(" use new ABC9 flow (EXPERIMENTAL)\n"); + log("\n"); + log(" -iopad\n"); + log(" insert IO buffers\n"); + log("\n"); + log(" -nodsp\n"); + log(" do not map multipliers to MULT18X18D\n"); + log("\n"); + log(" -no-rw-check\n"); + log(" marks all recognized read ports as \"return don't-care value on\n"); + log(" read/write collision\" (same result as setting the no_rw_check\n"); + log(" attribute on all memories).\n"); + log("\n"); + log("\n"); + log("The following commands are executed by this synthesis command:\n"); + help_script(); + log("\n"); + } + + string top_opt, edif_file, json_file, family; + bool noccu2, nodffe, nobram, nolutram, nowidelut, asyncprld, flatten, dff, retime, abc2, abc9, iopad, nodsp, no_rw_check, have_dsp; + string postfix, arith_map, brams_map, dsp_map; + + void clear_flags() override + { + top_opt = "-auto-top"; + edif_file = ""; + json_file = ""; + family = ""; + noccu2 = false; + nodffe = false; + nobram = false; + nolutram = false; + nowidelut = false; + asyncprld = false; + flatten = true; + dff = false; + retime = false; + abc2 = false; + abc9 = false; + iopad = false; + nodsp = false; + no_rw_check = false; + postfix = ""; + arith_map = ""; + brams_map = ""; + dsp_map = ""; + have_dsp = false; + } + + void execute(std::vector args, RTLIL::Design *design) override + { + string run_from, run_to; + bool force_widelut = false; + clear_flags(); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + if (args[argidx] == "-top" && argidx+1 < args.size()) { + top_opt = "-top " + args[++argidx]; + continue; + } + if ((args[argidx] == "-family" || args[argidx] == "-arch") && argidx+1 < args.size()) { + family = args[++argidx]; + continue; + } + if (args[argidx] == "-edif" && argidx+1 < args.size()) { + edif_file = args[++argidx]; + continue; + } + if (args[argidx] == "-json" && argidx+1 < args.size()) { + json_file = args[++argidx]; + continue; + } + if (args[argidx] == "-run" && argidx+1 < args.size()) { + size_t pos = args[argidx+1].find(':'); + if (pos == std::string::npos) + break; + run_from = args[++argidx].substr(0, pos); + run_to = args[argidx].substr(pos+1); + continue; + } + if (args[argidx] == "-flatten") { + flatten = true; + continue; + } + if (args[argidx] == "-noflatten") { + flatten = false; + continue; + } + if (args[argidx] == "-dff") { + dff = true; + continue; + } + if (args[argidx] == "-retime") { + retime = true; + continue; + } + if (args[argidx] == "-noccu2") { + noccu2 = true; + continue; + } + if (args[argidx] == "-nodffe") { + nodffe = true; + continue; + } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-asyncprld") { + asyncprld = true; + continue; + } + if (args[argidx] == "-nolutram" || /*deprecated alias*/ args[argidx] == "-nodram") { + nolutram = true; + continue; + } + if (args[argidx] == "-nowidelut" || /*deprecated alias*/ args[argidx] == "-nomux") { + nowidelut = true; + force_widelut = true; + continue; + } + if (args[argidx] == "-widelut") { + nowidelut = false; + force_widelut = true; + continue; + } + if (args[argidx] == "-abc2") { + abc2 = true; + continue; + } + if (args[argidx] == "-abc9") { + abc9 = true; + continue; + } + if (args[argidx] == "-iopad") { + iopad = true; + continue; + } + if (args[argidx] == "-nodsp") { + nodsp = true; + continue; + } + if (args[argidx] == "-no-rw-check") { + no_rw_check = true; + continue; + } + break; + } + extra_args(args, argidx, design); + + if (family.empty()) + log_cmd_error("Lattice family parameter must be set.\n"); + + if (family == "ecp5") { + postfix = "_ecp5"; + arith_map = "_ccu2c"; + brams_map = "_16kd"; + dsp_map = "_18x18"; + have_dsp = true; + } else if (family == "xo2" || + family == "xo3" || + family == "xo3d" /* || + family == "pm2"*/) { + postfix = "_" + family; + arith_map = "_ccu2d"; + brams_map = "_8kc"; + have_dsp = false; + if (!force_widelut) nowidelut = true; +/* } else if (family == "xo" || + family == "pm") { + } else if (family == "xp" || + family == "xp2" || + family == "ecp" || + family == "sm" || + family == "ecp2" || + family == "ecp3" || + family == "lifmd" || + family == "lifmdf") {*/ + } else + log_cmd_error("Invalid Lattice -family setting: '%s'.\n", family.c_str()); + + if (!design->full_selection()) + log_cmd_error("This command only operates on fully selected designs!\n"); + + if (abc9 && retime) + log_cmd_error("-retime option not currently compatible with -abc9!\n"); + + log_header(design, "Executing SYNTH_LATTICE pass.\n"); + log_push(); + + run_script(design, run_from, run_to); + + log_pop(); + } + + void script() override + { + std::string no_rw_check_opt = ""; + if (no_rw_check) + no_rw_check_opt = " -no-rw-check"; + if (help_mode) + no_rw_check_opt = " [-no-rw-check]"; + + if (check_label("begin")) + { + run("read_verilog -lib -specify +/lattice/cells_sim" + postfix + ".v +/lattice/cells_bb" + postfix + ".v"); + run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); + } + + if (check_label("coarse")) + { + run("proc"); + if (flatten || help_mode) + run("flatten"); + run("tribuf -logic"); + run("deminout"); + run("opt_expr"); + run("opt_clean"); + run("check"); + run("opt -nodffe -nosdff"); + run("fsm"); + run("opt"); + run("wreduce"); + run("peepopt"); + run("opt_clean"); + run("share"); + run("techmap -map +/cmp2lut.v -D LUT_WIDTH=4"); + run("opt_expr"); + run("opt_clean"); + if (have_dsp && !nodsp) { + run("techmap -map +/mul2dsp.v -map +/lattice/dsp_map" + dsp_map + ".v -D DSP_A_MAXWIDTH=18 -D DSP_B_MAXWIDTH=18 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=$__MUL18X18", "(unless -nodsp)"); + run("chtype -set $mul t:$__soft_mul", "(unless -nodsp)"); + } + run("alumacc"); + run("opt"); + run("memory -nomap" + no_rw_check_opt); + run("opt_clean"); + } + + 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 +/lattice/lutrams.txt -lib +/lattice/brams" + brams_map + ".txt" + args, "(-no-auto-block if -nobram, -no-auto-distributed if -nolutram)"); + run("techmap -map +/lattice/lutrams_map.v -map +/lattice/brams_map" + brams_map + ".v"); + } + + if (check_label("map_ffram")) + { + run("opt -fast -mux_undef -undriven -fine"); + run("memory_map"); + run("opt -undriven -fine"); + } + + if (check_label("map_gates")) + { + if (noccu2) + run("techmap"); + else + run("techmap -map +/techmap.v -map +/lattice/arith_map" + arith_map + ".v"); + if (help_mode || iopad) { + run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad OBZ ~T:I:O -tinoutpad BB ~T:O:I:B A:top", "(only if '-iopad')"); + run("attrmvcp -attr src -attr LOC t:OB %x:+[O] t:OBZ %x:+[O] t:BB %x:+[B]"); + run("attrmvcp -attr src -attr LOC -driven t:IB %x:+[I]"); + } + run("opt -fast"); + if (retime || help_mode) + run("abc -dff -D 1", "(only if -retime)"); + } + + if (check_label("map_ffs")) + { + run("opt_clean"); + std::string dfflegalize_args = " -cell $_DFF_?_ 01 -cell $_DFF_?P?_ r -cell $_SDFF_?P?_ r"; + if (help_mode) { + dfflegalize_args += " [-cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r]"; + } else if (!nodffe) { + dfflegalize_args += " -cell $_DFFE_??_ 01 -cell $_DFFE_?P??_ r -cell $_SDFFE_?P??_ r"; + } + if (help_mode) { + dfflegalize_args += " [-cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x] [-cell $_DLATCH_?_ x]"; + } else if (asyncprld) { + dfflegalize_args += " -cell $_ALDFF_?P_ x -cell $_ALDFFE_?P?_ x"; + } else { + dfflegalize_args += " -cell $_DLATCH_?_ x"; + } + run("dfflegalize" + dfflegalize_args, "($_ALDFF_*_ only if -asyncprld, $_DLATCH_* only if not -asyncprld, $_*DFFE_* only if not -nodffe)"); + if ((abc9 && dff) || help_mode) + run("zinit -all w:* t:$_DFF_?_ t:$_DFFE_??_ t:$_SDFF*", "(only if -abc9 and -dff)"); + run("techmap -D NO_LUT -map +/lattice/cells_map.v"); + run("opt_expr -undriven -mux_undef"); + run("simplemap"); + run("lattice_gsr"); + run("attrmvcp -copy -attr syn_useioff"); + run("opt_clean"); + } + + if (check_label("map_luts")) + { + if (abc2 || help_mode) + run("abc", " (only if -abc2)"); + if (!asyncprld || help_mode) + run("techmap -map +/lattice/latches_map.v", "(skip if -asyncprld)"); + + if (abc9) { + std::string abc9_opts; + if (nowidelut) + abc9_opts += " -maxlut 4"; + std::string k = "synth_lattice.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) + abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); + else + abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); + if (nowidelut) + abc9_opts += " -maxlut 4"; + if (dff) + abc9_opts += " -dff"; + run("abc9" + abc9_opts); + } else { + std::string abc_args = " -dress"; + if (nowidelut) + abc_args += " -lut 4"; + else + abc_args += " -lut 4:7"; + if (dff) + abc_args += " -dff"; + run("abc" + abc_args); + } + run("clean"); + } + + if (check_label("map_cells")) + { + run("techmap -map +/lattice/cells_map.v"); + run("opt_lut_ins -tech lattice"); + run("clean"); + } + + if (check_label("check")) + { + run("autoname"); + run("hierarchy -check"); + run("stat"); + run("check -noinit"); + run("blackbox =A:whitebox"); + } + + if (check_label("edif")) + { + if (!edif_file.empty() || help_mode) + run(stringf("write_edif %s", help_mode ? "" : edif_file.c_str())); + } + + if (check_label("json")) + { + if (!json_file.empty() || help_mode) + run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); + } + } +} SynthLatticePass; + +/* +struct SynthEcp5Pass : public Pass +{ + SynthEcp5Pass() : Pass("synth_ecp5", "synthesis for ECP5 FPGAs") { } + + void execute(std::vector args, RTLIL::Design *design) override + { + args[0] = "synth_lattice"; + args.insert(args.begin()+1, std::string()); + args.insert(args.begin()+1, std::string()); + args[1] = "-family"; + args[2] = "ecp5"; + Pass::call(design, args); + } +} SynthEcp5Pass; +*/ + +PRIVATE_NAMESPACE_END diff --git a/techlibs/machxo2/Makefile.inc b/techlibs/machxo2/Makefile.inc deleted file mode 100644 index cd4e27884fc..00000000000 --- a/techlibs/machxo2/Makefile.inc +++ /dev/null @@ -1,14 +0,0 @@ - -OBJS += techlibs/machxo2/synth_machxo2.o - -$(eval $(call add_share_file,share/machxo2,techlibs/ecp5/cells_io.vh)) -$(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/cells_bb.v)) - -$(eval $(call add_share_file,share/machxo2,techlibs/ecp5/lutrams.txt)) -$(eval $(call add_share_file,share/machxo2,techlibs/ecp5/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)) -$(eval $(call add_share_file,share/machxo2,techlibs/machxo2/arith_map.v)) diff --git a/techlibs/machxo2/cells_bb.v b/techlibs/machxo2/cells_bb.v deleted file mode 100644 index 3d047b1692a..00000000000 --- a/techlibs/machxo2/cells_bb.v +++ /dev/null @@ -1,227 +0,0 @@ -(* blackbox *) -module EHXPLLJ ( - input CLKI, CLKFB, - input PHASESEL1, PHASESEL0, PHASEDIR, PHASESTEP, - input LOADREG, STDBY, PLLWAKESYNC, RST, RESETM, RESETC, RESETD, - input ENCLKOP, ENCLKOS, ENCLKOS2, ENCLKOS3, PLLCLK, PLLRST, PLLSTB, PLLWE, - input PLLDATI7, PLLDATI6, PLLDATI5, PLLDATI4, PLLDATI3, PLLDATI2, PLLDATI1, PLLDATI0, - input PLLADDR4, PLLADDR3, PLLADDR2, PLLADDR1, PLLADDR0, - output CLKOP, CLKOS, CLKOS2, CLKOS3, LOCK, INTLOCK, REFCLK, - output PLLDATO7, PLLDATO6, PLLDATO5, PLLDATO4, PLLDATO3, PLLDATO2, PLLDATO1, PLLDATO0, PLLACK, - output DPHSRC, CLKINTFB -); - parameter CLKI_DIV = 1; - parameter CLKFB_DIV = 1; - parameter CLKOP_DIV = 8; - parameter CLKOS_DIV = 8; - parameter CLKOS2_DIV = 8; - parameter CLKOS3_DIV = 8; - parameter CLKOP_ENABLE = "ENABLED"; - parameter CLKOS_ENABLE = "ENABLED"; - parameter CLKOS2_ENABLE = "ENABLED"; - parameter CLKOS3_ENABLE = "ENABLED"; - parameter VCO_BYPASS_A0 = "DISABLED"; - parameter VCO_BYPASS_B0 = "DISABLED"; - parameter VCO_BYPASS_C0 = "DISABLED"; - parameter VCO_BYPASS_D0 = "DISABLED"; - parameter CLKOP_CPHASE = 0; - parameter CLKOS_CPHASE = 0; - parameter CLKOS2_CPHASE = 0; - parameter CLKOS3_CPHASE = 0; - parameter CLKOP_FPHASE = 0; - parameter CLKOS_FPHASE = 0; - parameter CLKOS2_FPHASE = 0; - parameter CLKOS3_FPHASE = 0; - parameter FEEDBK_PATH = "CLKOP"; - parameter FRACN_ENABLE = "DISABLED"; - parameter FRACN_DIV = 0; - parameter CLKOP_TRIM_POL = "RISING"; - parameter CLKOP_TRIM_DELAY = 0; - parameter CLKOS_TRIM_POL = "RISING"; - parameter CLKOS_TRIM_DELAY = 0; - parameter PLL_USE_WB = "DISABLED"; - parameter PREDIVIDER_MUXA1 = 0; - parameter PREDIVIDER_MUXB1 = 0; - parameter PREDIVIDER_MUXC1 = 0; - parameter PREDIVIDER_MUXD1 = 0; - parameter OUTDIVIDER_MUXA2 = "DIVA"; - parameter OUTDIVIDER_MUXB2 = "DIVB"; - parameter OUTDIVIDER_MUXC2 = "DIVC"; - parameter OUTDIVIDER_MUXD2 = "DIVD"; - parameter PLL_LOCK_MODE = 0; - parameter STDBY_ENABLE = "DISABLED"; - parameter DPHASE_SOURCE = "DISABLED"; - parameter PLLRST_ENA = "DISABLED"; - parameter MRST_ENA = "DISABLED"; - parameter DCRST_ENA = "DISABLED"; - parameter DDRST_ENA = "DISABLED"; - parameter INTFB_WAKE = "DISABLED"; -endmodule - -(* blackbox *) -module OSCH #( - parameter NOM_FREQ = "2.08" -) ( - input STDBY, - output OSC, - output SEDSTDBY -); -endmodule - -(* blackbox *) -module DCCA ( - input CLKI, - input CE, - output CLKO -); -endmodule - -(* blackbox *) -module DCMA ( - input CLK0, - input CLK1, - input SEL, - output DCMOUT -); -endmodule - -(* blackbox *) -module PDPW8KC ( - input DI17, DI16, DI15, DI14, DI13, DI12, DI11, DI10, DI9, DI8, DI7, DI6, DI5, DI4, DI3, DI2, DI1, DI0, - input ADW8, ADW7, ADW6, ADW5, ADW4, ADW3, ADW2, ADW1, ADW0, - input BE1, BE0, - input CEW, CLKW, CSW2, CSW1, CSW0, - input ADR12, ADR11, ADR10, ADR9, ADR8, ADR7, ADR6, ADR5, ADR4, ADR3, ADR2, ADR1, ADR0, - input CER, OCER, CLKR, CSR2, CSR1, CSR0, RST, - output DO17, DO16, DO15, DO14, DO13, DO12, DO11, DO10, DO9, DO8, DO7, DO6, DO5, DO4, DO3, DO2, DO1, DO0 -); - parameter DATA_WIDTH_W = 18; - parameter DATA_WIDTH_R = 9; - - parameter GSR = "ENABLED"; - - parameter REGMODE = "NOREG"; - - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - - parameter CSDECODE_W = "0b000"; - parameter CSDECODE_R = "0b000"; - - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INIT_DATA = "STATIC"; - -endmodule - -(* blackbox *) -module SP8KC ( - input DI8, DI7, DI6, DI5, DI4, DI3, DI2, DI1, DI0, - input AD12, AD11, AD10, AD9, AD8, AD7, AD6, AD5, AD4, AD3, AD2, AD1, AD0, - input CE, OCE, CLK, WE, CS2, CS1, CS0, RST, - output DO8, DO7, DO6, DO5, DO4, DO3, DO2, DO1, DO0 -); - parameter DATA_WIDTH = 9; - parameter GSR = "ENABLED"; - - parameter REGMODE = "NOREG"; - - parameter RESETMODE = "SYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - - parameter CSDECODE = "0b000"; - - parameter WRITEMODE = "NORMAL"; - - parameter INITVAL_00 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INIT_DATA = "STATIC"; -endmodule - -(* blackbox *) -module FIFO8KB ( - input DI0, DI1, DI2, DI3, DI4, DI5, DI6, DI7, DI8, DI9, DI10, DI11, DI12, DI13, DI14, DI15, DI16, DI17, - input CSW0, CSW1, CSR0, CSR1, WE, RE, ORE, CLKW, CLKR, RST, RPRST, FULLI, EMPTYI, - output DO0, DO1, DO2, DO3, DO4, DO5, DO6, DO7, DO8, DO9, DO10, DO11, DO12, DO13, DO14, DO15, DO16, DO17, - input EF, AEF, AFF, FF -); - parameter DATA_WIDTH_W = 18; - parameter DATA_WIDTH_R = 18; - - parameter GSR = "DISABLED"; - - parameter REGMODE = "NOREG"; - - parameter RESETMODE = "ASYNC"; - parameter ASYNC_RESET_RELEASE = "SYNC"; - - parameter CSDECODE_W = "0b00"; - parameter CSDECODE_R = "0b00"; - - parameter AEPOINTER = "0b00000000000000"; - parameter AEPOINTER1 = "0b00000000000000"; - parameter AFPOINTER = "0b00000000000000"; - parameter AFPOINTER1 = "0b00000000000000"; - parameter FULLPOINTER = "0b00000000000000"; - parameter FULLPOINTER1 = "0b00000000000000"; -endmodule diff --git a/techlibs/machxo2/cells_sim.v b/techlibs/machxo2/cells_sim.v deleted file mode 100644 index 8e0e411791c..00000000000 --- a/techlibs/machxo2/cells_sim.v +++ /dev/null @@ -1,385 +0,0 @@ -module LUT2(input A, B, output Z); - parameter [3:0] INIT = 4'h0; - wire [1:0] s1 = B ? INIT[ 3:2] : INIT[1:0]; - assign Z = A ? s1[1] : s1[0]; -endmodule - -module LUT4 #( - parameter [15:0] INIT = 0 -) ( - input A, B, C, D, - output Z -); - // This form of LUT propagates as few x's as possible. - wire [7:0] s3 = D ? INIT[15:8] : INIT[7:0]; - wire [3:0] s2 = C ? s3[ 7:4] : s3[3:0]; - wire [1:0] s1 = B ? s2[ 3:2] : s2[1:0]; - assign Z = A ? s1[1] : s1[0]; -endmodule - -module TRELLIS_FF #( - parameter GSR = "ENABLED", - parameter CEMUX = "1", - parameter CLKMUX = "0", - parameter LSRMUX = "LSR", - parameter LSRONMUX = "LSRMUX", - parameter SRMODE = "LSR_OVER_CE", - parameter REGSET = "SET", - parameter REGMODE = "FF" -) ( - input CLK, DI, LSR, CE, - output reg Q -); - - wire muxce; - generate - case (CEMUX) - "1": assign muxce = 1'b1; - "0": assign muxce = 1'b0; - "INV": assign muxce = ~CE; - default: assign muxce = CE; - endcase - endgenerate - - wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; - wire muxlsron = (LSRONMUX == "LSRMUX") ? muxlsr : 1'b0; - wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; - wire srval = (REGSET == "SET") ? 1'b1 : 1'b0; - - initial Q = srval; - - generate - if (REGMODE == "FF") begin - if (SRMODE == "ASYNC") begin - always @(posedge muxclk, posedge muxlsron) - if (muxlsron) - Q <= srval; - else if (muxce) - Q <= DI; - end else begin - always @(posedge muxclk) - if (muxlsron) - Q <= srval; - else if (muxce) - Q <= DI; - end - end else if (REGMODE == "LATCH") begin - ERROR_UNSUPPORTED_FF_MODE error(); - end else begin - ERROR_UNKNOWN_FF_MODE error(); - end - endgenerate -endmodule - -/* For consistency with ECP5; represents F0/F1 => OFX0 mux in a slice. */ -module PFUMX (input ALUT, BLUT, C0, output Z); - assign Z = C0 ? ALUT : BLUT; -endmodule - -/* For consistency with ECP5; represents FXA/FXB => OFX1 mux in a slice. */ -module L6MUX21 (input D0, D1, SD, output Z); - assign Z = SD ? D1 : D0; -endmodule - -/* For consistency, input order matches TRELLIS_SLICE even though the BELs in -prjtrellis were filled in clockwise order from bottom left. */ -module TRELLIS_SLICE #( - parameter MODE = "LOGIC", - parameter GSR = "ENABLED", - parameter SRMODE = "LSR_OVER_CE", - parameter CEMUX = "1", - parameter CLKMUX = "0", - parameter LSRMUX = "LSR", - parameter LSRONMUX = "LSRMUX", - parameter LUT0_INITVAL = 16'hFFFF, - parameter LUT1_INITVAL = 16'hFFFF, - parameter REGMODE = "FF", - parameter REG0_SD = "1", - parameter REG1_SD = "1", - parameter REG0_REGSET = "SET", - parameter REG1_REGSET = "SET", - parameter CCU2_INJECT1_0 = "YES", - parameter CCU2_INJECT1_1 = "YES", - parameter WREMUX = "INV" -) ( - input A0, B0, C0, D0, - input A1, B1, C1, D1, - input M0, M1, - input FCI, FXA, FXB, - - input CLK, LSR, CE, - input DI0, DI1, - - input WD0, WD1, - input WAD0, WAD1, WAD2, WAD3, - input WRE, WCK, - - output F0, Q0, - output F1, Q1, - output FCO, OFX0, OFX1, - - output WDO0, WDO1, WDO2, WDO3, - output WADO0, WADO1, WADO2, WADO3 -); - - generate - if (MODE == "LOGIC") begin - L6MUX21 FXMUX (.D0(FXA), .D1(FXB), .SD(M1), .Z(OFX1)); - - wire k0; - wire k1; - PFUMX K0K1MUX (.ALUT(k1), .BLUT(k0), .C0(M0), .Z(OFX0)); - - LUT4 #(.INIT(LUT0_INITVAL)) LUT_0 (.A(A0), .B(B0), .C(C0), .D(D0), .Z(k0)); - LUT4 #(.INIT(LUT1_INITVAL)) LUT_1 (.A(A0), .B(B0), .C(C0), .D(D0), .Z(k1)); - - assign F0 = k0; - assign F1 = k1; - end else if (MODE == "CCU2") begin - ERROR_UNSUPPORTED_SLICE_MODE error(); - end else if (MODE == "DPRAM") begin - ERROR_UNSUPPORTED_SLICE_MODE error(); - end else begin - ERROR_UNKNOWN_SLICE_MODE error(); - end - endgenerate - - /* Reg can be fed either by M, or DI inputs; DI inputs muxes OFX and F - outputs (in other words, feeds back into TRELLIS_SLICE). */ - wire di0 = (REG0_SD == "1") ? DI0 : M0; - wire di1 = (REG1_SD == "1") ? DI1 : M1; - - TRELLIS_FF#(.GSR(GSR), .CEMUX(CEMUX), .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), - .LSRONMUX(LSRONMUX), .SRMODE(SRMODE), .REGSET(REG0_REGSET), - .REGMODE(REGMODE)) REG_0 (.CLK(CLK), .DI(di0), .LSR(LSR), .CE(CE), .Q(Q0)); - TRELLIS_FF#(.GSR(GSR), .CEMUX(CEMUX), .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), - .LSRONMUX(LSRONMUX), .SRMODE(SRMODE), .REGSET(REG1_REGSET), - .REGMODE(REGMODE)) REG_1 (.CLK(CLK), .DI(di1), .LSR(LSR), .CE(CE), .Q(Q1)); -endmodule - -module TRELLIS_IO #( - parameter DIR = "INPUT" -) ( - (* iopad_external_pin *) - inout B, - input I, T, - output O -); - generate - if (DIR == "INPUT") begin - assign O = B; - end else if (DIR == "OUTPUT") begin - assign B = T ? 1'bz : I; - end else if (DIR == "BIDIR") begin - assign B = T ? 1'bz : I; - assign O = B; - end else begin - ERROR_UNKNOWN_IO_MODE error(); - end - endgenerate -endmodule - -(* abc9_box, lib_whitebox *) -module TRELLIS_DPR16X4 ( - input [3:0] DI, - input [3:0] WAD, - input WRE, - input WCK, - input [3:0] RAD, - output [3:0] DO -); - parameter WCKMUX = "WCK"; - parameter WREMUX = "WRE"; - parameter [63:0] INITVAL = 64'h0000000000000000; - - reg [3:0] mem[15:0]; - - integer i; - initial begin - for (i = 0; i < 16; i = i + 1) - mem[i] <= INITVAL[4*i +: 4]; - end - - wire muxwck = (WCKMUX == "INV") ? ~WCK : WCK; - - reg muxwre; - always @(*) - case (WREMUX) - "1": muxwre = 1'b1; - "0": muxwre = 1'b0; - "INV": muxwre = ~WRE; - default: muxwre = WRE; - endcase - - always @(posedge muxwck) - if (muxwre) - mem[WAD] <= DI; - - assign DO = mem[RAD]; - - specify - // TODO - (RAD *> DO) = 0; - endspecify -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 - -// --------------------------------------- -(* lib_whitebox *) -module CCU2D ( - input CIN, - input A0, B0, C0, D0, A1, B1, C1, D1, - output S0, S1, - output COUT -); - parameter [15:0] INIT0 = 16'h0000; - parameter [15:0] INIT1 = 16'h0000; - parameter INJECT1_0 = "YES"; - parameter INJECT1_1 = "YES"; - - // First half - wire LUT4_0, LUT2_0; - LUT4 #(.INIT(INIT0)) lut4_0(.A(A0), .B(B0), .C(C0), .D(D0), .Z(LUT4_0)); - LUT2 #(.INIT(~INIT0[15:12])) lut2_0(.A(A0), .B(B0), .Z(LUT2_0)); - wire gated_cin_0 = (INJECT1_0 == "YES") ? 1'b0 : CIN; - assign S0 = LUT4_0 ^ gated_cin_0; - - wire gated_lut2_0 = (INJECT1_0 == "YES") ? 1'b0 : LUT2_0; - wire cout_0 = (~LUT4_0 & gated_lut2_0) | (LUT4_0 & CIN); - - // Second half - wire LUT4_1, LUT2_1; - LUT4 #(.INIT(INIT1)) lut4_1(.A(A1), .B(B1), .C(C1), .D(D1), .Z(LUT4_1)); - LUT2 #(.INIT(~INIT1[15:12])) lut2_1(.A(A1), .B(B1), .Z(LUT2_1)); - wire gated_cin_1 = (INJECT1_1 == "YES") ? 1'b0 : cout_0; - assign S1 = LUT4_1 ^ gated_cin_1; - - wire gated_lut2_1 = (INJECT1_1 == "YES") ? 1'b0 : LUT2_1; - assign COUT = (~LUT4_1 & gated_lut2_1) | (LUT4_1 & cout_0); -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 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_01 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_02 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_03 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_04 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_05 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_06 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_07 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_08 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_09 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_0F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_10 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_11 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_12 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_13 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_14 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_15 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_16 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_17 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_18 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_19 = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1A = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1B = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1C = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1D = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; - parameter INITVAL_1F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; -endmodule - -`ifndef NO_INCLUDES - -`include "cells_io.vh" - -`endif diff --git a/techlibs/machxo2/synth_machxo2.cc b/techlibs/machxo2/synth_machxo2.cc deleted file mode 100644 index 2b684a7d8fd..00000000000 --- a/techlibs/machxo2/synth_machxo2.cc +++ /dev/null @@ -1,297 +0,0 @@ -/* - * yosys -- Yosys Open SYnthesis Suite - * - * Copyright (C) 2020 William D. Jones - * - * 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/celltypes.h" -#include "kernel/rtlil.h" -#include "kernel/log.h" - -USING_YOSYS_NAMESPACE -PRIVATE_NAMESPACE_BEGIN - -struct SynthMachXO2Pass : public ScriptPass -{ - SynthMachXO2Pass() : ScriptPass("synth_machxo2", "synthesis for MachXO2 FPGAs. This work is experimental.") { } - - void help() override - { - // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| - log("\n"); - log(" synth_machxo2 [options]\n"); - log("\n"); - log("This command runs synthesis for MachXO2 FPGAs.\n"); - log("\n"); - log(" -top \n"); - log(" use the specified module as top module\n"); - log("\n"); - log(" -blif \n"); - log(" write the design to the specified BLIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -edif \n"); - log(" write the design to the specified EDIF file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -json \n"); - log(" write the design to the specified JSON file. writing of an output file\n"); - log(" is omitted if this parameter is not specified.\n"); - log("\n"); - log(" -run :\n"); - log(" only run the commands between the labels (see below). an empty\n"); - 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"); - log(" -noiopad\n"); - log(" do not insert IO buffers\n"); - log("\n"); - log(" -ccu2\n"); - log(" use CCU2 cells in output netlist\n"); - log("\n"); - log(" -vpr\n"); - log(" generate an output netlist (and BLIF file) suitable for VPR\n"); - log(" (this feature is experimental and incomplete)\n"); - log("\n"); - log("\n"); - log("The following commands are executed by this synthesis command:\n"); - help_script(); - log("\n"); - } - - string top_opt, blif_file, edif_file, json_file; - bool ccu2, nobram, nolutram, flatten, vpr, noiopad; - - void clear_flags() override - { - top_opt = "-auto-top"; - blif_file = ""; - edif_file = ""; - json_file = ""; - ccu2 = false; - nobram = false; - nolutram = false; - flatten = true; - vpr = false; - noiopad = false; - } - - void execute(std::vector args, RTLIL::Design *design) override - { - string run_from, run_to; - clear_flags(); - - size_t argidx; - for (argidx = 1; argidx < args.size(); argidx++) - { - if (args[argidx] == "-top" && argidx+1 < args.size()) { - top_opt = "-top " + args[++argidx]; - continue; - } - if (args[argidx] == "-blif" && argidx+1 < args.size()) { - blif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-edif" && argidx+1 < args.size()) { - edif_file = args[++argidx]; - continue; - } - if (args[argidx] == "-json" && argidx+1 < args.size()) { - json_file = args[++argidx]; - continue; - } - if (args[argidx] == "-run" && argidx+1 < args.size()) { - size_t pos = args[argidx+1].find(':'); - if (pos == std::string::npos) - break; - run_from = args[++argidx].substr(0, pos); - run_to = args[argidx].substr(pos+1); - continue; - } - if (args[argidx] == "-flatten") { - flatten = true; - continue; - } - if (args[argidx] == "-noflatten") { - flatten = false; - continue; - } - if (args[argidx] == "-nobram") { - nobram = true; - continue; - } - if (args[argidx] == "-nolutram") { - nolutram = true; - continue; - } - if (args[argidx] == "-noiopad") { - noiopad = true; - continue; - } - if (args[argidx] == "-ccu2") { - ccu2 = true; - continue; - } - if (args[argidx] == "-vpr") { - vpr = true; - continue; - } - break; - } - extra_args(args, argidx, design); - - if (!design->full_selection()) - log_cmd_error("This command only operates on fully selected designs!\n"); - - log_header(design, "Executing SYNTH_MACHXO2 pass.\n"); - log_push(); - - run_script(design, run_from, run_to); - - log_pop(); - } - - void script() override - { - if (check_label("begin")) - { - run("read_verilog -lib -icells +/machxo2/cells_sim.v +/machxo2/cells_bb.v"); - run(stringf("hierarchy -check %s", help_mode ? "-top " : top_opt.c_str())); - } - - if (check_label("flatten", "(unless -noflatten)")) - { - if (flatten || help_mode) { - run("proc"); - run("flatten"); - run("tribuf -logic"); - run("deminout"); - } - } - - if (check_label("coarse")) - { - 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("opt -fast -mux_undef -undriven -fine"); - run("memory_map"); - run("opt -undriven -fine"); - } - - if (check_label("map_gates", "(unless -noiopad)")) - { - if (!ccu2) - run("techmap"); - else - run("techmap -map +/techmap.v -map +/machxo2/arith_map.v"); - if (!noiopad || help_mode) - { - run("iopadmap -bits -outpad OB I:O -inpad IB O:I -toutpad OBZ ~T:I:O -tinoutpad BB ~T:O:I:B A:top", "(only if '-iopad')"); - run("attrmvcp -attr src -attr LOC t:OB %x:+[O] t:OBZ %x:+[O] t:BB %x:+[B]"); - run("attrmvcp -attr src -attr LOC -driven t:IB %x:+[I]"); - } - } - - if (check_label("map_ffs")) - { - run("opt_clean"); - std::string dfflegalize_args = " -cell $_DFF_?_ 01 -cell $_DFF_?P?_ r -cell $_SDFF_?P?_ r"; - run("dfflegalize" + dfflegalize_args); - run("techmap -D NO_LUT -map +/machxo2/cells_map.v"); - run("opt_expr -undriven -mux_undef"); - run("simplemap"); - run("ecp5_gsr"); - run("attrmvcp -copy -attr syn_useioff"); - run("opt_clean"); - } - - if (check_label("map_luts")) - { - run("abc -lut 4 -dress"); - run("clean"); - } - - if (check_label("map_cells")) - { - run("techmap -map +/machxo2/cells_map.v"); - run("clean"); - } - - if (check_label("check")) - { - run("hierarchy -check"); - run("stat"); - run("blackbox =A:whitebox"); - } - - if (check_label("blif")) - { - if (!blif_file.empty() || help_mode) { - if (vpr || help_mode) { - run(stringf("opt_clean -purge"), - " (vpr mode)"); - run(stringf("write_blif -attr -cname -conn -param %s", - help_mode ? "" : blif_file.c_str()), - " (vpr mode)"); - } - if (!vpr) - run(stringf("write_blif -gates -attr -param %s", - help_mode ? "" : blif_file.c_str()), - " (non-vpr mode)"); - } - } - - if (check_label("edif")) - { - if (!edif_file.empty() || help_mode) - run(stringf("write_edif %s", help_mode ? "" : edif_file.c_str())); - } - - if (check_label("json")) - { - if (!json_file.empty() || help_mode) - run(stringf("write_json %s", help_mode ? "" : json_file.c_str())); - } - } -} SynthMachXO2Pass; - -PRIVATE_NAMESPACE_END diff --git a/tests/arch/machxo2/add_sub.ys b/tests/arch/machxo2/add_sub.ys index 97ee90fbbe2..cc6ffb41a29 100644 --- a/tests/arch/machxo2/add_sub.ys +++ b/tests/arch/machxo2/add_sub.ys @@ -1,7 +1,7 @@ read_verilog ../common/add_sub.v hierarchy -top top proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module select -assert-count 10 t:LUT4 diff --git a/tests/arch/machxo2/adffs.ys b/tests/arch/machxo2/adffs.ys index a9f8980c6e4..49e93f9ac30 100644 --- a/tests/arch/machxo2/adffs.ys +++ b/tests/arch/machxo2/adffs.ys @@ -3,7 +3,7 @@ design -save read hierarchy -top adff proc -equiv_opt -async2sync -assert -map +/machxo2/cells_sim.v synth_machxo2 -noiopad # equivalency check +equiv_opt -async2sync -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd adff # Constrain all select calls below inside the top module select -assert-count 1 t:TRELLIS_FF @@ -12,7 +12,7 @@ select -assert-none t:TRELLIS_FF %% t:* %D design -load read hierarchy -top adffn proc -equiv_opt -async2sync -assert -map +/machxo2/cells_sim.v synth_machxo2 -noiopad # equivalency check +equiv_opt -async2sync -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd adffn # Constrain all select calls below inside the top module select -assert-count 1 t:TRELLIS_FF @@ -22,7 +22,7 @@ select -assert-none t:TRELLIS_FF t:LUT4 %% t:* %D design -load read hierarchy -top dffs proc -equiv_opt -async2sync -assert -map +/machxo2/cells_sim.v synth_machxo2 -noiopad # equivalency check +equiv_opt -async2sync -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd dffs # Constrain all select calls below inside the top module select -assert-count 1 t:TRELLIS_FF @@ -32,7 +32,7 @@ select -assert-none t:TRELLIS_FF t:LUT4 %% t:* %D design -load read hierarchy -top ndffnr proc -equiv_opt -async2sync -assert -map +/machxo2/cells_sim.v synth_machxo2 -noiopad # equivalency check +equiv_opt -async2sync -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd ndffnr # Constrain all select calls below inside the top module select -assert-count 1 t:TRELLIS_FF diff --git a/tests/arch/machxo2/counter.ys b/tests/arch/machxo2/counter.ys index 54ee80066ff..3d68c9900fa 100644 --- a/tests/arch/machxo2/counter.ys +++ b/tests/arch/machxo2/counter.ys @@ -2,7 +2,7 @@ read_verilog ../common/counter.v hierarchy -top top proc flatten -equiv_opt -assert -multiclock -map +/machxo2/cells_sim.v synth_machxo2 -ccu2 -noiopad # equivalency check +equiv_opt -assert -multiclock -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module select -assert-count 4 t:CCU2D diff --git a/tests/arch/machxo2/dffs.ys b/tests/arch/machxo2/dffs.ys index 29dcafe2383..531d5ca5a27 100644 --- a/tests/arch/machxo2/dffs.ys +++ b/tests/arch/machxo2/dffs.ys @@ -3,7 +3,7 @@ design -save read hierarchy -top dff proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd dff # Constrain all select calls below inside the top module select -assert-count 1 t:TRELLIS_FF @@ -12,8 +12,8 @@ select -assert-none t:TRELLIS_FF t:TRELLIS_IO %% t:* %D design -load read hierarchy -top dffe proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd dffe # Constrain all select calls below inside the top module -select -assert-count 2 t:TRELLIS_FF t:LUT4 +select -assert-count 1 t:TRELLIS_FF t:LUT4 select -assert-none t:TRELLIS_FF t:LUT4 t:TRELLIS_IO %% t:* %D diff --git a/tests/arch/machxo2/fsm.ys b/tests/arch/machxo2/fsm.ys index a61357fcdd2..3e10a069a74 100644 --- a/tests/arch/machxo2/fsm.ys +++ b/tests/arch/machxo2/fsm.ys @@ -3,7 +3,7 @@ hierarchy -top fsm proc flatten -equiv_opt -run :prove -map +/machxo2/cells_sim.v synth_machxo2 +equiv_opt -run :prove -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 miter -equiv -make_assert -flatten gold gate miter sat -verify -prove-asserts -show-public -set-at 1 in_reset 1 -seq 20 -prove-skip 1 miter diff --git a/tests/arch/machxo2/logic.ys b/tests/arch/machxo2/logic.ys index 0cf57310c81..dbd702f905e 100644 --- a/tests/arch/machxo2/logic.ys +++ b/tests/arch/machxo2/logic.ys @@ -1,7 +1,7 @@ read_verilog ../common/logic.v hierarchy -top top proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module select -assert-count 9 t:LUT4 diff --git a/tests/arch/machxo2/lutram.ys b/tests/arch/machxo2/lutram.ys index dc6b86fd349..65af7b2c267 100644 --- a/tests/arch/machxo2/lutram.ys +++ b/tests/arch/machxo2/lutram.ys @@ -2,7 +2,7 @@ read_verilog ../common/lutram.v hierarchy -top lutram_1w1r proc memory -nomap -equiv_opt -run :prove -map +/machxo2/cells_sim.v synth_machxo2 -noiopad +equiv_opt -run :prove -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 memory opt -full diff --git a/tests/arch/machxo2/mux.ys b/tests/arch/machxo2/mux.ys index 27bffbe63aa..6d4e10dc7e7 100644 --- a/tests/arch/machxo2/mux.ys +++ b/tests/arch/machxo2/mux.ys @@ -3,7 +3,7 @@ design -save read hierarchy -top mux2 proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux2 # Constrain all select calls below inside the top module select -assert-count 1 t:LUT4 @@ -12,7 +12,7 @@ select -assert-none t:LUT4 t:TRELLIS_IO %% t:* %D design -load read hierarchy -top mux4 proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux4 # Constrain all select calls below inside the top module select -assert-count 2 t:LUT4 @@ -22,7 +22,7 @@ select -assert-none t:LUT4 t:TRELLIS_IO %% t:* %D design -load read hierarchy -top mux8 proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux8 # Constrain all select calls below inside the top module select -assert-count 5 t:LUT4 @@ -32,7 +32,7 @@ select -assert-none t:LUT4 t:TRELLIS_IO %% t:* %D design -load read hierarchy -top mux16 proc -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd mux16 # Constrain all select calls below inside the top module select -assert-max 12 t:LUT4 diff --git a/tests/arch/machxo2/shifter.ys b/tests/arch/machxo2/shifter.ys index bff881fb734..ca7abb8098b 100644 --- a/tests/arch/machxo2/shifter.ys +++ b/tests/arch/machxo2/shifter.ys @@ -2,7 +2,7 @@ read_verilog ../common/shifter.v hierarchy -top top proc flatten -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd top # Constrain all select calls below inside the top module diff --git a/tests/arch/machxo2/tribuf.ys b/tests/arch/machxo2/tribuf.ys index 840979439f8..00c7012d748 100644 --- a/tests/arch/machxo2/tribuf.ys +++ b/tests/arch/machxo2/tribuf.ys @@ -2,9 +2,8 @@ read_verilog ../common/tribuf.v hierarchy -top tristate proc flatten -equiv_opt -assert -map +/machxo2/cells_sim.v synth_machxo2 # equivalency check +equiv_opt -assert -map +/lattice/cells_sim_xo2.v -map +/simcells.v synth_lattice -family xo2 # equivalency check design -load postopt # load the post-opt design (otherwise equiv_opt loads the pre-opt design) cd tristate # Constrain all select calls below inside the top module -select -assert-count 3 t:TRELLIS_IO -select -assert-count 1 t:LUT4 -select -assert-none t:TRELLIS_IO t:LUT4 %% t:* %D +select -assert-count 1 t:$_TBUF_ +select -assert-none t:$_TBUF_ %% t:* %D diff --git a/tests/fmt/.gitignore b/tests/fmt/.gitignore new file mode 100644 index 00000000000..a36a15ec464 --- /dev/null +++ b/tests/fmt/.gitignore @@ -0,0 +1,3 @@ +*.log +iverilog-* +yosys-* diff --git a/tests/fmt/always_comb.v b/tests/fmt/always_comb.v new file mode 100644 index 00000000000..7147786bebf --- /dev/null +++ b/tests/fmt/always_comb.v @@ -0,0 +1,24 @@ +module top(input clk); + reg a = 0; + reg b = 0; + wire y; + + sub s (.a(a), .b(b), .y(y)); + + always @(posedge clk) begin + a <= (!a && !b) || (a && !b); + b <= (a && !b) || (a && b); + end +endmodule + +module sub(input a, input b, output wire y); + assign y = a & b; + + // Not fit for our purposes: always @* if (a) $display(a, b, y); + // + // We compare output against iverilog, but async iverilog $display fires + // even before values have propagated -- i.e. combinations of a/b/y will be + // shown where a & b are both 1, but y has not yet taken the value 1. We + // don't, so we specify it in the conditional. + always @* if (y & (y == (a & b))) $display(a, b, y); +endmodule diff --git a/tests/fmt/always_comb_tb.cc b/tests/fmt/always_comb_tb.cc new file mode 100644 index 00000000000..5812500535a --- /dev/null +++ b/tests/fmt/always_comb_tb.cc @@ -0,0 +1,16 @@ +#include "yosys-always_comb.cc" + +int main() +{ + cxxrtl_design::p_top uut1, uut2; + + for (int i = 0; i < 20; ++i) { + uut1.p_clk.set(!uut1.p_clk); + uut1.step(); + + uut2.p_clk.set(!uut2.p_clk); + uut2.step(); + } + + return 0; +} diff --git a/tests/fmt/always_comb_tb.v b/tests/fmt/always_comb_tb.v new file mode 100644 index 00000000000..3cc4496a04f --- /dev/null +++ b/tests/fmt/always_comb_tb.v @@ -0,0 +1,9 @@ +module tb; + reg clk = 0; + + top uut1 (.clk(clk)); + top uut2 (.clk(clk)); + + always #1 clk <= ~clk; + initial #20 $finish; +endmodule diff --git a/tests/fmt/always_display.v b/tests/fmt/always_display.v new file mode 100644 index 00000000000..593c5afc08c --- /dev/null +++ b/tests/fmt/always_display.v @@ -0,0 +1,17 @@ +module m(input clk, rst, en, input [31:0] data); + +`ifdef EVENT_CLK + always @(posedge clk) +`endif +`ifdef EVENT_CLK_RST + always @(posedge clk or negedge rst) +`endif +`ifdef EVENT_STAR + always @(*) +`endif +`ifdef COND_EN + if (en) +`endif + $display("data=%d", data); + +endmodule diff --git a/tests/fmt/always_full.v b/tests/fmt/always_full.v new file mode 100644 index 00000000000..4d3df7a615c --- /dev/null +++ b/tests/fmt/always_full.v @@ -0,0 +1,236 @@ +module always_full(input clk); + + always @(posedge clk) begin + + $display("==> small unsigned %%d"); + $display(":%d:", 16'haa); + $display(":%-d:", 16'haa); + $display(":%+d:", 16'haa); + $display(":%+-d:", 16'haa); + $display(":%0d:", 16'haa); + $display(":%-0d:", 16'haa); + $display(":%+0d:", 16'haa); + $display(":%+-0d:", 16'haa); + $display(":%20d:", 16'haa); + $display(":%-20d:", 16'haa); + $display(":%+20d:", 16'haa); + $display(":%+-20d:", 16'haa); + $display(":%020d:", 16'haa); + $display(":%-020d:", 16'haa); + $display(":%+020d:", 16'haa); + $display(":%+-020d:", 16'haa); + + $display("==> big unsigned %%d"); + $display(":%d:", 16'haaaa); + $display(":%-d:", 16'haaaa); + $display(":%+d:", 16'haaaa); + $display(":%+-d:", 16'haaaa); + $display(":%0d:", 16'haaaa); + $display(":%-0d:", 16'haaaa); + $display(":%+0d:", 16'haaaa); + $display(":%+-0d:", 16'haaaa); + $display(":%20d:", 16'haaaa); + $display(":%-20d:", 16'haaaa); + $display(":%+20d:", 16'haaaa); + $display(":%+-20d:", 16'haaaa); + $display(":%020d:", 16'haaaa); + $display(":%-020d:", 16'haaaa); + $display(":%+020d:", 16'haaaa); + $display(":%+-020d:", 16'haaaa); + + $display("==> small signed %%d"); + $display(":%d:", 16'shaa); + $display(":%-d:", 16'shaa); + $display(":%+d:", 16'shaa); + $display(":%+-d:", 16'shaa); + $display(":%0d:", 16'shaa); + $display(":%-0d:", 16'shaa); + $display(":%+0d:", 16'shaa); + $display(":%+-0d:", 16'shaa); + $display(":%20d:", 16'shaa); + $display(":%-20d:", 16'shaa); + $display(":%+20d:", 16'shaa); + $display(":%+-20d:", 16'shaa); + $display(":%020d:", 16'shaa); + $display(":%-020d:", 16'shaa); + $display(":%+020d:", 16'shaa); + $display(":%+-020d:", 16'shaa); + + $display("==> big signed %%d"); + $display(":%d:", 16'shaaaa); + $display(":%-d:", 16'shaaaa); + $display(":%+d:", 16'shaaaa); + $display(":%+-d:", 16'shaaaa); + $display(":%0d:", 16'shaaaa); + $display(":%-0d:", 16'shaaaa); + $display(":%+0d:", 16'shaaaa); + $display(":%+-0d:", 16'shaaaa); + $display(":%20d:", 16'shaaaa); + $display(":%-20d:", 16'shaaaa); + $display(":%+20d:", 16'shaaaa); + $display(":%+-20d:", 16'shaaaa); + $display(":%020d:", 16'shaaaa); + $display(":%-020d:", 16'shaaaa); + $display(":%+020d:", 16'shaaaa); + $display(":%+-020d:", 16'shaaaa); + + $display("==> small unsigned %%h"); + $display(":%h:", 16'haa); + $display(":%-h:", 16'haa); + $display(":%0h:", 16'haa); + $display(":%-0h:", 16'haa); + $display(":%20h:", 16'haa); + $display(":%-20h:", 16'haa); + $display(":%020h:", 16'haa); + $display(":%-020h:", 16'haa); + + $display("==> big unsigned %%h"); + $display(":%h:", 16'haaaa); + $display(":%-h:", 16'haaaa); + $display(":%0h:", 16'haaaa); + $display(":%-0h:", 16'haaaa); + $display(":%20h:", 16'haaaa); + $display(":%-20h:", 16'haaaa); + $display(":%020h:", 16'haaaa); + $display(":%-020h:", 16'haaaa); + + $display("==> small signed %%h"); + $display(":%h:", 16'shaa); + $display(":%-h:", 16'shaa); + $display(":%0h:", 16'shaa); + $display(":%-0h:", 16'shaa); + $display(":%20h:", 16'shaa); + $display(":%-20h:", 16'shaa); + $display(":%020h:", 16'shaa); + $display(":%-020h:", 16'shaa); + + $display("==> big signed %%h"); + $display(":%h:", 16'shaaaa); + $display(":%-h:", 16'shaaaa); + $display(":%0h:", 16'shaaaa); + $display(":%-0h:", 16'shaaaa); + $display(":%20h:", 16'shaaaa); + $display(":%-20h:", 16'shaaaa); + $display(":%020h:", 16'shaaaa); + $display(":%-020h:", 16'shaaaa); + + $display("==> small unsigned %%o"); + $display(":%o:", 16'haa); + $display(":%-o:", 16'haa); + $display(":%0o:", 16'haa); + $display(":%-0o:", 16'haa); + $display(":%20o:", 16'haa); + $display(":%-20o:", 16'haa); + $display(":%020o:", 16'haa); + $display(":%-020o:", 16'haa); + + $display("==> big unsigned %%o"); + $display(":%o:", 16'haaaa); + $display(":%-o:", 16'haaaa); + $display(":%0o:", 16'haaaa); + $display(":%-0o:", 16'haaaa); + $display(":%20o:", 16'haaaa); + $display(":%-20o:", 16'haaaa); + $display(":%020o:", 16'haaaa); + $display(":%-020o:", 16'haaaa); + + $display("==> small signed %%o"); + $display(":%o:", 16'shaa); + $display(":%-o:", 16'shaa); + $display(":%0o:", 16'shaa); + $display(":%-0o:", 16'shaa); + $display(":%20o:", 16'shaa); + $display(":%-20o:", 16'shaa); + $display(":%020o:", 16'shaa); + $display(":%-020o:", 16'shaa); + + $display("==> big signed %%o"); + $display(":%o:", 16'shaaaa); + $display(":%-o:", 16'shaaaa); + $display(":%0o:", 16'shaaaa); + $display(":%-0o:", 16'shaaaa); + $display(":%20o:", 16'shaaaa); + $display(":%-20o:", 16'shaaaa); + $display(":%020o:", 16'shaaaa); + $display(":%-020o:", 16'shaaaa); + + $display("==> small unsigned %%b"); + $display(":%b:", 16'haa); + $display(":%-b:", 16'haa); + $display(":%0b:", 16'haa); + $display(":%-0b:", 16'haa); + $display(":%20b:", 16'haa); + $display(":%-20b:", 16'haa); + $display(":%020b:", 16'haa); + $display(":%-020b:", 16'haa); + + $display("==> big unsigned %%b"); + $display(":%b:", 16'haaaa); + $display(":%-b:", 16'haaaa); + $display(":%0b:", 16'haaaa); + $display(":%-0b:", 16'haaaa); + $display(":%20b:", 16'haaaa); + $display(":%-20b:", 16'haaaa); + $display(":%020b:", 16'haaaa); + $display(":%-020b:", 16'haaaa); + + $display("==> small signed %%b"); + $display(":%b:", 16'shaa); + $display(":%-b:", 16'shaa); + $display(":%0b:", 16'shaa); + $display(":%-0b:", 16'shaa); + $display(":%20b:", 16'shaa); + $display(":%-20b:", 16'shaa); + $display(":%020b:", 16'shaa); + $display(":%-020b:", 16'shaa); + + $display("==> big signed %%b"); + $display(":%b:", 16'shaaaa); + $display(":%-b:", 16'shaaaa); + $display(":%0b:", 16'shaaaa); + $display(":%-0b:", 16'shaaaa); + $display(":%20b:", 16'shaaaa); + $display(":%-20b:", 16'shaaaa); + $display(":%020b:", 16'shaaaa); + $display(":%-020b:", 16'shaaaa); + + $display("==> time %%t"); + $display(":%t:", $time); + $display(":%-t:", $time); + $display(":%0t:", $time); + $display(":%-0t:", $time); + $display(":%10t:", $time); + $display(":%-10t:", $time); + $display(":%015t:", $time); + $display(":%-015t:", $time); + + $display("===> %%s"); + $display(":%10s:", "foo"); + $display(":%010s:", "foo"); + $display(":%-10s:", "foo"); + $display(":%-010s:", "foo"); + + $display("===> %%c"); + $display(":%10c:", "foo"); + $display(":%010c:", "foo"); + $display(":%-10c:", "foo"); + $display(":%-010c:", "foo"); + + $display("==> aliases"); + $display(":%x:", 16'shaa); + $display(":%X:", 16'shaa); + $display(":%H:", 16'shaa); + $display(":%O:", 16'shaa); + $display(":%B:", 16'shaa); + + $display("==> default base"); + $displayh(16'haa); + $displayo(16'haa); + $displayb(16'haa); + + $display("==> write/format"); + $display("%d", 1, "%d", 1); + + end + +endmodule diff --git a/tests/fmt/always_full_tb.cc b/tests/fmt/always_full_tb.cc new file mode 100644 index 00000000000..229f78aebe1 --- /dev/null +++ b/tests/fmt/always_full_tb.cc @@ -0,0 +1,9 @@ +#include "yosys-always_full.cc" + +int main() +{ + cxxrtl_design::p_always__full uut; + uut.p_clk.set(!uut.p_clk); + uut.step(); + return 0; +} diff --git a/tests/fmt/always_full_tb.v b/tests/fmt/always_full_tb.v new file mode 100644 index 00000000000..0c2599cc263 --- /dev/null +++ b/tests/fmt/always_full_tb.v @@ -0,0 +1,12 @@ +module always_full_tb; + + reg clk = 0; + + always_full uut (.clk(clk)); + + always begin + #1 clk <= ~clk; + #1 $finish; + end + +endmodule diff --git a/tests/fmt/display_lm.v b/tests/fmt/display_lm.v new file mode 100644 index 00000000000..d96f233f064 --- /dev/null +++ b/tests/fmt/display_lm.v @@ -0,0 +1,12 @@ +module top; + mid mid_uut (); +endmodule + +module mid (); + bot bot_uut (); +endmodule + +module bot (); + initial $display("%%l: %l\n%%m: %m"); + always $display("%%l: %l\n%%m: %m"); +endmodule diff --git a/tests/fmt/display_lm_tb.cc b/tests/fmt/display_lm_tb.cc new file mode 100644 index 00000000000..7a593d72919 --- /dev/null +++ b/tests/fmt/display_lm_tb.cc @@ -0,0 +1,9 @@ +#include "yosys-display_lm.cc" + +int main() +{ + cxxrtl_design::p_top uut; + + uut.step(); + return 0; +} diff --git a/tests/fmt/fuzz/.gitignore b/tests/fmt/fuzz/.gitignore new file mode 100644 index 00000000000..88ea7e2ef91 --- /dev/null +++ b/tests/fmt/fuzz/.gitignore @@ -0,0 +1,2 @@ +fuzztest +build diff --git a/tests/fmt/fuzz/CMakeLists.txt b/tests/fmt/fuzz/CMakeLists.txt new file mode 100644 index 00000000000..6f7c43da888 --- /dev/null +++ b/tests/fmt/fuzz/CMakeLists.txt @@ -0,0 +1,23 @@ +cmake_minimum_required(VERSION 3.14) +project(cxxrtl_division_fuzz) + +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(fuzztest) + +enable_testing() + +include(GoogleTest) + +fuzztest_setup_fuzzing_flags() + +include_directories(../../..) + +add_executable( + x_test + x_test.cc + ../../../libs/bigint/BigUnsigned.cc +) + +link_fuzztest(x_test) +gtest_discover_tests(x_test) diff --git a/tests/fmt/fuzz/x_test.cc b/tests/fmt/fuzz/x_test.cc new file mode 100644 index 00000000000..ee061861f90 --- /dev/null +++ b/tests/fmt/fuzz/x_test.cc @@ -0,0 +1,44 @@ +#include "fuzztest/fuzztest.h" +#include "gtest/gtest.h" + +#include +#include "backends/cxxrtl/cxxrtl.h" +#include "libs/bigint/BigUnsigned.hh" + +using namespace cxxrtl_yosys; + +void Formats128BitIntegers(chunk_t x0, chunk_t x1, chunk_t x2, chunk_t x3, bool signed_) +{ + // Compare output to BigUnsigned. + value<128> v; + v = v.blit<127, 64>(value<64>{x1, x0}); + v = v.blit<63, 0>(value<64>{x3, x2}); + + std::ostringstream oss; + oss << value_formatted<128>(v, false, false, ' ', 0, 10, signed_, false, false); + auto actual = oss.str(); + + BigUnsigned u; + bool negative = signed_ && v.is_neg(); + if (negative) + v = v.neg(); + u.bitShiftLeft(v.slice<127, 64>().val().get(), 64); + u.bitOr(u, v.slice<63, 0>().val().get()); + + std::string expected; + + if (u.isZero()) { + expected = "0"; + } else { + while (!u.isZero()) { + expected += '0' + (u % 10).toInt(); + u /= 10; + } + if (negative) + expected += '-'; + std::reverse(expected.begin(), expected.end()); + } + + EXPECT_EQ(actual, expected); +} +FUZZ_TEST(CxxrtlDivisionFuzz, Formats128BitIntegers); diff --git a/tests/fmt/initial_display.v b/tests/fmt/initial_display.v new file mode 100644 index 00000000000..d3ef9ed7691 --- /dev/null +++ b/tests/fmt/initial_display.v @@ -0,0 +1,255 @@ +module m; + initial $display("<<>>"); + + initial $display("==> small unsigned %%d"); + initial $display(":%d:", 16'haa); + initial $display(":%-d:", 16'haa); + initial $display(":%+d:", 16'haa); + initial $display(":%+-d:", 16'haa); + initial $display(":%0d:", 16'haa); + initial $display(":%-0d:", 16'haa); + initial $display(":%+0d:", 16'haa); + initial $display(":%+-0d:", 16'haa); + initial $display(":%20d:", 16'haa); + initial $display(":%-20d:", 16'haa); + initial $display(":%+20d:", 16'haa); + initial $display(":%+-20d:", 16'haa); + initial $display(":%020d:", 16'haa); + initial $display(":%-020d:", 16'haa); + initial $display(":%+020d:", 16'haa); + initial $display(":%+-020d:", 16'haa); + + initial $display("==> big unsigned %%d"); + initial $display(":%d:", 16'haaaa); + initial $display(":%-d:", 16'haaaa); + initial $display(":%+d:", 16'haaaa); + initial $display(":%+-d:", 16'haaaa); + initial $display(":%0d:", 16'haaaa); + initial $display(":%-0d:", 16'haaaa); + initial $display(":%+0d:", 16'haaaa); + initial $display(":%+-0d:", 16'haaaa); + initial $display(":%20d:", 16'haaaa); + initial $display(":%-20d:", 16'haaaa); + initial $display(":%+20d:", 16'haaaa); + initial $display(":%+-20d:", 16'haaaa); + initial $display(":%020d:", 16'haaaa); + initial $display(":%-020d:", 16'haaaa); + initial $display(":%+020d:", 16'haaaa); + initial $display(":%+-020d:", 16'haaaa); + + initial $display("==> small signed %%d"); + initial $display(":%d:", 16'shaa); + initial $display(":%-d:", 16'shaa); + initial $display(":%+d:", 16'shaa); + initial $display(":%+-d:", 16'shaa); + initial $display(":%0d:", 16'shaa); + initial $display(":%-0d:", 16'shaa); + initial $display(":%+0d:", 16'shaa); + initial $display(":%+-0d:", 16'shaa); + initial $display(":%20d:", 16'shaa); + initial $display(":%-20d:", 16'shaa); + initial $display(":%+20d:", 16'shaa); + initial $display(":%+-20d:", 16'shaa); + initial $display(":%020d:", 16'shaa); + initial $display(":%-020d:", 16'shaa); + initial $display(":%+020d:", 16'shaa); + initial $display(":%+-020d:", 16'shaa); + + initial $display("==> big signed %%d"); + initial $display(":%d:", 16'shaaaa); + initial $display(":%-d:", 16'shaaaa); + initial $display(":%+d:", 16'shaaaa); + initial $display(":%+-d:", 16'shaaaa); + initial $display(":%0d:", 16'shaaaa); + initial $display(":%-0d:", 16'shaaaa); + initial $display(":%+0d:", 16'shaaaa); + initial $display(":%+-0d:", 16'shaaaa); + initial $display(":%20d:", 16'shaaaa); + initial $display(":%-20d:", 16'shaaaa); + initial $display(":%+20d:", 16'shaaaa); + initial $display(":%+-20d:", 16'shaaaa); + initial $display(":%020d:", 16'shaaaa); + initial $display(":%-020d:", 16'shaaaa); + initial $display(":%+020d:", 16'shaaaa); + initial $display(":%+-020d:", 16'shaaaa); + + initial $display("==> small unsigned %%h"); + initial $display(":%h:", 16'haa); + initial $display(":%-h:", 16'haa); + initial $display(":%0h:", 16'haa); + initial $display(":%-0h:", 16'haa); + initial $display(":%20h:", 16'haa); + initial $display(":%-20h:", 16'haa); + initial $display(":%020h:", 16'haa); + initial $display(":%-020h:", 16'haa); + + initial $display("==> big unsigned %%h"); + initial $display(":%h:", 16'haaaa); + initial $display(":%-h:", 16'haaaa); + initial $display(":%0h:", 16'haaaa); + initial $display(":%-0h:", 16'haaaa); + initial $display(":%20h:", 16'haaaa); + initial $display(":%-20h:", 16'haaaa); + initial $display(":%020h:", 16'haaaa); + initial $display(":%-020h:", 16'haaaa); + + initial $display("==> small signed %%h"); + initial $display(":%h:", 16'shaa); + initial $display(":%-h:", 16'shaa); + initial $display(":%0h:", 16'shaa); + initial $display(":%-0h:", 16'shaa); + initial $display(":%20h:", 16'shaa); + initial $display(":%-20h:", 16'shaa); + initial $display(":%020h:", 16'shaa); + initial $display(":%-020h:", 16'shaa); + + initial $display("==> big signed %%h"); + initial $display(":%h:", 16'shaaaa); + initial $display(":%-h:", 16'shaaaa); + initial $display(":%0h:", 16'shaaaa); + initial $display(":%-0h:", 16'shaaaa); + initial $display(":%20h:", 16'shaaaa); + initial $display(":%-20h:", 16'shaaaa); + initial $display(":%020h:", 16'shaaaa); + initial $display(":%-020h:", 16'shaaaa); + + initial $display("==> small unsigned %%o"); + initial $display(":%o:", 16'haa); + initial $display(":%-o:", 16'haa); + initial $display(":%0o:", 16'haa); + initial $display(":%-0o:", 16'haa); + initial $display(":%20o:", 16'haa); + initial $display(":%-20o:", 16'haa); + initial $display(":%020o:", 16'haa); + initial $display(":%-020o:", 16'haa); + + initial $display("==> big unsigned %%o"); + initial $display(":%o:", 16'haaaa); + initial $display(":%-o:", 16'haaaa); + initial $display(":%0o:", 16'haaaa); + initial $display(":%-0o:", 16'haaaa); + initial $display(":%20o:", 16'haaaa); + initial $display(":%-20o:", 16'haaaa); + initial $display(":%020o:", 16'haaaa); + initial $display(":%-020o:", 16'haaaa); + + initial $display("==> small signed %%o"); + initial $display(":%o:", 16'shaa); + initial $display(":%-o:", 16'shaa); + initial $display(":%0o:", 16'shaa); + initial $display(":%-0o:", 16'shaa); + initial $display(":%20o:", 16'shaa); + initial $display(":%-20o:", 16'shaa); + initial $display(":%020o:", 16'shaa); + initial $display(":%-020o:", 16'shaa); + + initial $display("==> big signed %%o"); + initial $display(":%o:", 16'shaaaa); + initial $display(":%-o:", 16'shaaaa); + initial $display(":%0o:", 16'shaaaa); + initial $display(":%-0o:", 16'shaaaa); + initial $display(":%20o:", 16'shaaaa); + initial $display(":%-20o:", 16'shaaaa); + initial $display(":%020o:", 16'shaaaa); + initial $display(":%-020o:", 16'shaaaa); + + initial $display("==> small unsigned %%b"); + initial $display(":%b:", 16'haa); + initial $display(":%-b:", 16'haa); + initial $display(":%0b:", 16'haa); + initial $display(":%-0b:", 16'haa); + initial $display(":%20b:", 16'haa); + initial $display(":%-20b:", 16'haa); + initial $display(":%020b:", 16'haa); + initial $display(":%-020b:", 16'haa); + + initial $display("==> big unsigned %%b"); + initial $display(":%b:", 16'haaaa); + initial $display(":%-b:", 16'haaaa); + initial $display(":%0b:", 16'haaaa); + initial $display(":%-0b:", 16'haaaa); + initial $display(":%20b:", 16'haaaa); + initial $display(":%-20b:", 16'haaaa); + initial $display(":%020b:", 16'haaaa); + initial $display(":%-020b:", 16'haaaa); + + initial $display("==> small signed %%b"); + initial $display(":%b:", 16'shaa); + initial $display(":%-b:", 16'shaa); + initial $display(":%0b:", 16'shaa); + initial $display(":%-0b:", 16'shaa); + initial $display(":%20b:", 16'shaa); + initial $display(":%-20b:", 16'shaa); + initial $display(":%020b:", 16'shaa); + initial $display(":%-020b:", 16'shaa); + + initial $display("==> big signed %%b"); + initial $display(":%b:", 16'shaaaa); + initial $display(":%-b:", 16'shaaaa); + initial $display(":%0b:", 16'shaaaa); + initial $display(":%-0b:", 16'shaaaa); + initial $display(":%20b:", 16'shaaaa); + initial $display(":%-20b:", 16'shaaaa); + initial $display(":%020b:", 16'shaaaa); + initial $display(":%-020b:", 16'shaaaa); + + initial $display("==> time %%t"); + initial $display(":%t:", $time); + initial $display(":%-t:", $time); + initial $display(":%0t:", $time); + initial $display(":%-0t:", $time); + initial $display(":%10t:", $time); + initial $display(":%-10t:", $time); + initial $display(":%015t:", $time); + initial $display(":%-015t:", $time); + + initial $display("===> %%s"); + initial $display(":%10s:", "foo"); + initial $display(":%010s:", "foo"); + initial $display(":%-10s:", "foo"); + initial $display(":%-010s:", "foo"); + + initial $display("===> %%c"); + initial $display(":%10c:", "foo"); + initial $display(":%010c:", "foo"); + initial $display(":%-10c:", "foo"); + initial $display(":%-010c:", "foo"); + + initial $display("==> aliases"); + initial $display(":%x:", 16'shaa); + initial $display(":%X:", 16'shaa); + initial $display(":%H:", 16'shaa); + initial $display(":%O:", 16'shaa); + initial $display(":%B:", 16'shaa); + + initial $display("==> x/z"); + initial $display(":%d:", 16'b1010101010101010); + initial $display(":%d:", 16'b101010101010101x); + initial $display(":%d:", 16'b101010101010101z); + initial $display(":%x:", 16'b1010101010101010); + initial $display(":%x:", 16'b101010101010101x); + initial $display(":%x:", 16'b101010101010101z); + initial $display(":%x:", 16'b101010101010xxxx); + initial $display(":%x:", 16'b101010101010zzzz); + initial $display(":%o:", 16'b1010101010101010); + initial $display(":%o:", 16'b101010101010101x); + initial $display(":%o:", 16'b101010101010101z); + initial $display(":%o:", 16'b1010101010101xxx); + initial $display(":%o:", 16'b1010101010101zzz); + initial $display(":%b:", 16'b1010101010101010); + initial $display(":%b:", 16'b101010101010101x); + initial $display(":%b:", 16'b101010101010101z); + + initial $display("==> default base"); + initial $displayh(16'haa); + initial $displayo(16'haa); + initial $displayb(16'haa); + + initial $display("==> write/format"); + initial $display("%d", 1, "%d", 1); + // this one hits a bug in iverilog: + // initial $display("%s", $sformatf("%d", 1, "%d", 1)); + + initial $display("<<>>"); + +endmodule diff --git a/tests/fmt/roundtrip.v b/tests/fmt/roundtrip.v new file mode 100644 index 00000000000..7b50039cd26 --- /dev/null +++ b/tests/fmt/roundtrip.v @@ -0,0 +1,22 @@ +module m(input clk, input `SIGN [31:0] data); + + always @(posedge clk) + // All on a single line to avoid order effects. +`ifdef BASE_DEC + $display(":%d:%-d:%+d:%+-d:%0d:%-0d:%+0d:%+-0d:%20d:%-20d:%+20d:%+-20d:%020d:%-020d:%+020d:%+-020d:", + data, data, data, data, data, data, data, data, data, data, data, data, data, data, data, data); +`endif +`ifdef BASE_HEX + $display(":%h:%-h:%0h:%-0h:%20h:%-20h:%020h:%-020h:", + data, data, data, data, data, data, data, data); +`endif +`ifdef BASE_OCT + $display(":%o:%-o:%0o:%-0o:%20o:%-20o:%020o:%-020o:", + data, data, data, data, data, data, data, data); +`endif +`ifdef BASE_BIN + $display(":%b:%-b:%0b:%-0b:%20b:%-20b:%020b:%-020b:", + data, data, data, data, data, data, data, data); +`endif + +endmodule diff --git a/tests/fmt/roundtrip_tb.v b/tests/fmt/roundtrip_tb.v new file mode 100644 index 00000000000..988b8d8c2c0 --- /dev/null +++ b/tests/fmt/roundtrip_tb.v @@ -0,0 +1,13 @@ +module tb; + reg clk = 1'b0; + reg [31:0] data; + + m dut(.clk(clk), .data(data)); + + initial begin + data = 32'haa; + #10; clk = 1; #10; clk = 0; + data = 32'haaaa; + #10; clk = 1; #10; clk = 0; + end +endmodule diff --git a/tests/fmt/run-test.sh b/tests/fmt/run-test.sh new file mode 100644 index 00000000000..914a7234747 --- /dev/null +++ b/tests/fmt/run-test.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +set -ex + +../../yosys -p 'read_verilog initial_display.v' | awk '/<<>>/,/<<>>/ {print $0}' >yosys-initial_display.log +iverilog -o iverilog-initial_display initial_display.v +./iverilog-initial_display >iverilog-initial_display.log +diff yosys-initial_display.log iverilog-initial_display.log + +test_always_display () { + local subtest=$1; shift + ../../yosys -p "read_verilog $* always_display.v; proc; opt_expr -mux_bool; clean" -o yosys-always_display-${subtest}-1.v + ../../yosys -p "read_verilog yosys-always_display-${subtest}-1.v; proc; opt_expr -mux_bool; clean" -o yosys-always_display-${subtest}-2.v + diff yosys-always_display-${subtest}-1.v yosys-always_display-${subtest}-2.v +} + +test_always_display clk -DEVENT_CLK +test_always_display clk_rst -DEVENT_CLK_RST +test_always_display star -DEVENT_STAR + +test_always_display clk_en -DEVENT_CLK -DCOND_EN +test_always_display clk_rst_en -DEVENT_CLK_RST -DCOND_EN +test_always_display star_en -DEVENT_STAR -DCOND_EN + +test_roundtrip () { + local subtest=$1; shift + ../../yosys -p "read_verilog $* roundtrip.v; proc; clean" -o yosys-roundtrip-${subtest}-1.v + ../../yosys -p "read_verilog yosys-roundtrip-${subtest}-1.v; proc; clean" -o yosys-roundtrip-${subtest}-2.v + diff yosys-roundtrip-${subtest}-1.v yosys-roundtrip-${subtest}-2.v + + iverilog $* -o iverilog-roundtrip-${subtest} roundtrip.v roundtrip_tb.v + ./iverilog-roundtrip-${subtest} >iverilog-roundtrip-${subtest}.log + iverilog $* -o iverilog-roundtrip-${subtest}-1 yosys-roundtrip-${subtest}-1.v roundtrip_tb.v + ./iverilog-roundtrip-${subtest}-1 >iverilog-roundtrip-${subtest}-1.log + iverilog $* -o iverilog-roundtrip-${subtest}-2 yosys-roundtrip-${subtest}-2.v roundtrip_tb.v + ./iverilog-roundtrip-${subtest}-1 >iverilog-roundtrip-${subtest}-2.log + diff iverilog-roundtrip-${subtest}.log iverilog-roundtrip-${subtest}-1.log + diff iverilog-roundtrip-${subtest}-1.log iverilog-roundtrip-${subtest}-2.log +} + +test_roundtrip dec_unsigned -DBASE_DEC -DSIGN="" +test_roundtrip dec_signed -DBASE_DEC -DSIGN="signed" +test_roundtrip hex_unsigned -DBASE_HEX -DSIGN="" +test_roundtrip hex_signed -DBASE_HEX -DSIGN="signed" +test_roundtrip oct_unsigned -DBASE_HEX -DSIGN="" +test_roundtrip oct_signed -DBASE_HEX -DSIGN="signed" +test_roundtrip bin_unsigned -DBASE_HEX -DSIGN="" +test_roundtrip bin_signed -DBASE_HEX -DSIGN="signed" + +test_cxxrtl () { + local subtest=$1; shift + + ../../yosys -p "read_verilog ${subtest}.v; proc; clean; write_cxxrtl -print-output std::cerr yosys-${subtest}.cc" + ${CC:-gcc} -std=c++11 -o yosys-${subtest} -I../.. ${subtest}_tb.cc -lstdc++ + ./yosys-${subtest} 2>yosys-${subtest}.log + iverilog -o iverilog-${subtest} ${subtest}.v ${subtest}_tb.v + ./iverilog-${subtest} |grep -v '\$finish called' >iverilog-${subtest}.log + diff iverilog-${subtest}.log yosys-${subtest}.log +} + +test_cxxrtl always_full +test_cxxrtl always_comb + +# Ensure Verilog backend preserves behaviour of always block with multiple $displays. +../../yosys -p "read_verilog always_full.v; prep; clean" -o yosys-always_full-1.v +iverilog -o iverilog-always_full-1 yosys-always_full-1.v always_full_tb.v +./iverilog-always_full-1 |grep -v '\$finish called' >iverilog-always_full-1.log +diff iverilog-always_full.log iverilog-always_full-1.log + +../../yosys -p "read_verilog display_lm.v" >yosys-display_lm.log +../../yosys -p "read_verilog display_lm.v; write_cxxrtl yosys-display_lm.cc" +${CC:-gcc} -std=c++11 -o yosys-display_lm_cc -I../.. display_lm_tb.cc -lstdc++ +./yosys-display_lm_cc >yosys-display_lm_cc.log +for log in yosys-display_lm.log yosys-display_lm_cc.log; do + grep "^%l: \\\\bot\$" "$log" + grep "^%m: \\\\bot\$" "$log" +done diff --git a/tests/proc/clean_undef_case.ys b/tests/proc/clean_undef_case.ys new file mode 100644 index 00000000000..c874b08c017 --- /dev/null +++ b/tests/proc/clean_undef_case.ys @@ -0,0 +1,37 @@ +read_rtlil <