diff options
author | Eddie Hung <eddieh@ece.ubc.ca> | 2019-03-14 08:59:19 -0700 |
---|---|---|
committer | Eddie Hung <eddieh@ece.ubc.ca> | 2019-03-14 08:59:19 -0700 |
commit | f1a8e8a480a7a88835b02abafd27c03e90de7041 (patch) | |
tree | 49679db03662de0b029d814354f01f972179e453 | |
parent | 26ecbc1aee1dca1c186ab2b51835d74f67bc3e75 (diff) | |
parent | f0b2d8e467998876ad2cc14232d30ff7892982a3 (diff) | |
download | yosys-f1a8e8a480a7a88835b02abafd27c03e90de7041.tar.gz yosys-f1a8e8a480a7a88835b02abafd27c03e90de7041.tar.bz2 yosys-f1a8e8a480a7a88835b02abafd27c03e90de7041.zip |
Merge remote-tracking branch 'origin/master' into xc7srl
82 files changed, 2483 insertions, 584 deletions
diff --git a/.travis.yml b/.travis.yml index 8aacbb8b1..7c6e4e43c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -132,11 +132,11 @@ matrix: env: - MATRIX_EVAL="CONFIG=clang && CC=clang-5.0 && CXX=clang++-5.0" - # Latest clang on Mac OS X - - os: osx - osx_image: xcode9.4 - env: - - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" +# # Latest clang on Mac OS X +# - os: osx +# osx_image: xcode9.4 +# env: +# - MATRIX_EVAL="CONFIG=clang && CC=clang && CXX=clang++" before_install: - ./.travis/setup.sh @@ -10,6 +10,7 @@ CONFIG := clang # features (the more the better) ENABLE_TCL := 1 ENABLE_ABC := 1 +ENABLE_GLOB := 1 ENABLE_PLUGINS := 1 ENABLE_READLINE := 1 ENABLE_EDITLINE := 0 @@ -298,6 +299,10 @@ LDLIBS += -ldl endif endif +ifeq ($(ENABLE_GLOB),1) +CXXFLAGS += -DYOSYS_ENABLE_GLOB +endif + ifeq ($(ENABLE_TCL),1) TCL_VERSION ?= tcl$(shell bash -c "tclsh <(echo 'puts [info tclversion]')") ifeq ($(OS), FreeBSD) @@ -34,11 +34,24 @@ compatible license that is similar in terms to the MIT license or the 2-clause BSD license). -Web Site -======== +Web Site and Other Resources +============================ More information and documentation can be found on the Yosys web site: -http://www.clifford.at/yosys/ +- http://www.clifford.at/yosys/ + +The "Documentation" page on the web site contains links to more resources, +including a manual that even describes some of the Yosys internals: +- http://www.clifford.at/yosys/documentation.html + +The file `CodingReadme` in this directory contains additional information +for people interested in using the Yosys C++ APIs. + +Users interested in formal verification might want to use the formal verification +front-end for Yosys, SymbiYosys: +- https://symbiyosys.readthedocs.io/en/latest/ +- https://github.com/YosysHQ/SymbiYosys + Setup ====== @@ -296,6 +309,9 @@ Verilog Attributes and non-standard features passes to identify input and output ports of cells. The Verilog backend also does not output blackbox modules on default. +- The ``dynports'' attribute is used by the Verilog front-end to mark modules + that have ports with a width that depends on a parameter. + - The ``keep`` attribute on cells and wires is used to mark objects that should never be removed by the optimizer. This is used for example for cells that have hidden connections that are not part of the netlist, such as IO pads. diff --git a/backends/edif/edif.cc b/backends/edif/edif.cc index 2d25f879d..7e30b67af 100644 --- a/backends/edif/edif.cc +++ b/backends/edif/edif.cc @@ -130,7 +130,7 @@ struct EdifBackend : public Backend { bool port_rename = false; bool attr_properties = false; std::map<RTLIL::IdString, std::map<RTLIL::IdString, int>> lib_cell_ports; - bool nogndvcc = false, gndvccy = true; + bool nogndvcc = false, gndvccy = false; CellTypes ct(design); EdifNames edif_names; diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 0917ecba6..eef6401b2 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -165,11 +165,9 @@ struct FirrtlWorker std::string fid(RTLIL::IdString internal_id) { - const char *str = internal_id.c_str(); - return *str == '\\' ? str + 1 : str; + return make_id(internal_id); } - std::string cellname(RTLIL::Cell *cell) { return fid(cell->name).c_str(); @@ -219,29 +217,42 @@ struct FirrtlWorker if (it->second.size() > 0) { const SigSpec &secondSig = it->second; const std::string firstName = cell_name + "." + make_id(it->first); - const std::string secondName = make_expr(secondSig); + const std::string secondExpr = make_expr(secondSig); // Find the direction for this port. FDirection dir = getPortFDirection(it->first, instModule); - std::string source, sink; + std::string sourceExpr, sinkExpr; + const SigSpec *sinkSig = nullptr; switch (dir) { case FD_INOUT: log_warning("Instance port connection %s.%s is INOUT; treating as OUT\n", cell_type.c_str(), log_signal(it->second)); case FD_OUT: - source = firstName; - sink = secondName; + sourceExpr = firstName; + sinkExpr = secondExpr; + sinkSig = &secondSig; break; case FD_NODIRECTION: log_warning("Instance port connection %s.%s is NODIRECTION; treating as IN\n", cell_type.c_str(), log_signal(it->second)); /* FALL_THROUGH */ case FD_IN: - source = secondName; - sink = firstName; + sourceExpr = secondExpr; + sinkExpr = firstName; break; default: log_error("Instance port %s.%s unrecognized connection direction 0x%x !\n", cell_type.c_str(), log_signal(it->second), dir); break; } - wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sink.c_str(), source.c_str())); + // Check for subfield assignment. + std::string bitsString = "bits("; + if (sinkExpr.substr(0, bitsString.length()) == bitsString ) { + if (sinkSig == nullptr) + log_error("Unknown subfield %s.%s\n", cell_type.c_str(), sinkExpr.c_str()); + // Don't generate the assignment here. + // Add the source and sink to the "reverse_wire_map" and we'll output the assignment + // as part of the coalesced subfield assignments for this wire. + register_reverse_wire_map(sourceExpr, *sinkSig); + } else { + wire_exprs.push_back(stringf("\n%s%s <= %s", indent.c_str(), sinkExpr.c_str(), sourceExpr.c_str())); + } } } wire_exprs.push_back(stringf("\n")); diff --git a/backends/protobuf/protobuf.cc b/backends/protobuf/protobuf.cc index f56147cef..549fc73ae 100644 --- a/backends/protobuf/protobuf.cc +++ b/backends/protobuf/protobuf.cc @@ -48,7 +48,7 @@ struct ProtobufDesignSerializer ProtobufDesignSerializer(bool use_selection, bool aig_mode) : aig_mode_(aig_mode), use_selection_(use_selection) { } - + string get_name(IdString name) { return RTLIL::unescape_id(name); @@ -60,7 +60,7 @@ struct ProtobufDesignSerializer { for (auto ¶m : parameters) { std::string key = get_name(param.first); - + yosys::pb::Parameter pb_param; @@ -207,7 +207,7 @@ struct ProtobufDesignSerializer (*models)[aig.name] = pb_model; } } - + void serialize_design(yosys::pb::Design *pb, Design *design) { GOOGLE_PROTOBUF_VERIFY_VERSION; diff --git a/backends/smt2/smt2.cc b/backends/smt2/smt2.cc index 418f8d766..688535f33 100644 --- a/backends/smt2/smt2.cc +++ b/backends/smt2/smt2.cc @@ -416,6 +416,7 @@ struct Smt2Worker for (char ch : expr) { if (ch == 'A') processed_expr += get_bv(sig_a); else if (ch == 'B') processed_expr += get_bv(sig_b); + else if (ch == 'P') processed_expr += get_bv(cell->getPort("\\B")); else if (ch == 'L') processed_expr += is_signed ? "a" : "l"; else if (ch == 'U') processed_expr += is_signed ? "s" : "u"; else processed_expr += ch; @@ -554,7 +555,7 @@ struct Smt2Worker if (cell->type.in("$shift", "$shiftx")) { if (cell->getParam("\\B_SIGNED").as_bool()) { - return export_bvop(cell, stringf("(ite (bvsge B #b%0*d) " + return export_bvop(cell, stringf("(ite (bvsge P #b%0*d) " "(bvlshr A B) (bvlshr A (bvneg B)))", GetSize(cell->getPort("\\B")), 0), 's'); } else { @@ -887,8 +888,8 @@ struct Smt2Worker string name_a = get_bool(cell->getPort("\\A")); string name_en = get_bool(cell->getPort("\\EN")); - decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, - cell->attributes.count("\\src") ? cell->attributes.at("\\src").decode_string().c_str() : get_id(cell))); + string infostr = (cell->name[0] == '$' && cell->attributes.count("\\src")) ? cell->attributes.at("\\src").decode_string() : get_id(cell); + decls.push_back(stringf("; yosys-smt2-%s %d %s\n", cell->type.c_str() + 1, id, infostr.c_str())); if (cell->type == "$cover") decls.push_back(stringf("(define-fun |%s_%c %d| ((state |%s_s|)) Bool (and %s %s)) ; %s\n", @@ -1103,20 +1104,27 @@ struct Smt2Worker break; Const initword = init_data.extract(i*width, width, State::Sx); + Const initmask = initword; bool gen_init_constr = false; - for (auto bit : initword.bits) - if (bit == State::S0 || bit == State::S1) + for (int k = 0; k < GetSize(initword); k++) { + if (initword[k] == State::S0 || initword[k] == State::S1) { gen_init_constr = true; + initmask[k] = State::S1; + } else { + initmask[k] = State::S0; + initword[k] = State::S0; + } + } if (gen_init_constr) { if (statebv) /* FIXME */; else - init_list.push_back(stringf("(= (select (|%s#%d#0| state) #b%s) #b%s) ; %s[%d]", + init_list.push_back(stringf("(= (bvand (select (|%s#%d#0| state) #b%s) #b%s) #b%s) ; %s[%d]", get_id(module), arrayid, Const(i, abits).as_string().c_str(), - initword.as_string().c_str(), get_id(cell), i)); + initmask.as_string().c_str(), initword.as_string().c_str(), get_id(cell), i)); } } } diff --git a/backends/verilog/verilog_backend.cc b/backends/verilog/verilog_backend.cc index d351a6266..83d83f488 100644 --- a/backends/verilog/verilog_backend.cc +++ b/backends/verilog/verilog_backend.cc @@ -33,7 +33,7 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN -bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal; +bool verbose, norename, noattr, attr2comment, noexpr, nodec, nohex, nostr, defparam, decimal, siminit; int auto_name_counter, auto_name_offset, auto_name_digits; std::map<RTLIL::IdString, int> auto_name_map; std::set<RTLIL::IdString> reg_wires, reg_ct; @@ -1310,7 +1310,7 @@ void dump_cell(std::ostream &f, std::string indent, RTLIL::Cell *cell) } } - if (reg_ct.count(cell->type) && cell->hasPort("\\Q")) { + if (siminit && reg_ct.count(cell->type) && cell->hasPort("\\Q")) { std::stringstream ss; dump_reg_init(ss, cell->getPort("\\Q")); if (!ss.str().empty()) { @@ -1607,6 +1607,10 @@ struct VerilogBackend : public Backend { log(" without this option all internal cells are converted to Verilog\n"); log(" expressions.\n"); log("\n"); + log(" -siminit\n"); + log(" add initial statements with hierarchical refs to initialize FFs when\n"); + log(" in -noexpr mode.\n"); + log("\n"); log(" -nodec\n"); log(" 32-bit constant values are by default dumped as decimal numbers,\n"); log(" not bit pattern. This option deactivates this feature and instead\n"); @@ -1663,11 +1667,14 @@ struct VerilogBackend : public Backend { nostr = false; defparam = false; decimal = false; + siminit = false; auto_prefix = ""; bool blackboxes = false; bool selected = false; + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); reg_ct.insert("$dff"); @@ -1739,6 +1746,10 @@ struct VerilogBackend : public Backend { decimal = true; continue; } + if (arg == "-siminit") { + siminit = true; + continue; + } if (arg == "-blackboxes") { blackboxes = true; continue; @@ -1770,6 +1781,8 @@ struct VerilogBackend : public Backend { dump_module(*f, "", it->second); } + auto_name_map.clear(); + reg_wires.clear(); reg_ct.clear(); } } VerilogBackend; diff --git a/examples/anlogic/.gitignore b/examples/anlogic/.gitignore new file mode 100644 index 000000000..97c978a15 --- /dev/null +++ b/examples/anlogic/.gitignore @@ -0,0 +1,7 @@ +demo.bit +demo_phy.area +full.v +*.log +*.h +*.tde +*.svf diff --git a/examples/anlogic/README b/examples/anlogic/README new file mode 100644 index 000000000..35d8e9cb1 --- /dev/null +++ b/examples/anlogic/README @@ -0,0 +1,12 @@ +LED Blink project for Anlogic Lichee Tang board. + +Follow the install instructions for the Tang Dynasty IDE from given link below. + +https://tang.sipeed.com/en/getting-started/installing-td-ide/linux/ + + +set TD_HOME env variable to the full path to the TD <TD Install Directory> as follow. + +export TD_HOME=<TD Install Directory> + +then run "bash build.sh" in this directory. diff --git a/examples/anlogic/build.sh b/examples/anlogic/build.sh new file mode 100755 index 000000000..e0f6b4cfe --- /dev/null +++ b/examples/anlogic/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -ex +yosys demo.ys +$TD_HOME/bin/td build.tcl diff --git a/examples/anlogic/build.tcl b/examples/anlogic/build.tcl new file mode 100644 index 000000000..06db525c9 --- /dev/null +++ b/examples/anlogic/build.tcl @@ -0,0 +1,11 @@ +import_device eagle_s20.db -package BG256 +read_verilog full.v -top demo +read_adc demo.adc +optimize_rtl +map_macro +map +pack +place +route +report_area -io_info -file demo_phy.area +bitgen -bit demo.bit -version 0X0000 -svf demo.svf -svf_comment_on -g ucode:00000000000000000000000000000000 diff --git a/examples/anlogic/demo.adc b/examples/anlogic/demo.adc new file mode 100644 index 000000000..ec802502e --- /dev/null +++ b/examples/anlogic/demo.adc @@ -0,0 +1,2 @@ +set_pin_assignment {CLK_IN} { LOCATION = K14; } ##24MHZ +set_pin_assignment {R_LED} { LOCATION = R3; } ##R_LED diff --git a/examples/anlogic/demo.v b/examples/anlogic/demo.v new file mode 100644 index 000000000..e17db771e --- /dev/null +++ b/examples/anlogic/demo.v @@ -0,0 +1,18 @@ +module demo ( + input wire CLK_IN, + output wire R_LED +); + parameter time1 = 30'd12_000_000; + reg led_state; + reg [29:0] count; + + always @(posedge CLK_IN)begin + if(count == time1)begin + count<= 30'd0; + led_state <= ~led_state; + end + else + count <= count + 1'b1; + end + assign R_LED = led_state; +endmodule diff --git a/examples/anlogic/demo.ys b/examples/anlogic/demo.ys new file mode 100644 index 000000000..cb396cc2b --- /dev/null +++ b/examples/anlogic/demo.ys @@ -0,0 +1,3 @@ +read_verilog demo.v +synth_anlogic -top demo +write_verilog full.v diff --git a/examples/igloo2/.gitignore b/examples/igloo2/.gitignore index ea58efc9f..33b7182d3 100644 --- a/examples/igloo2/.gitignore +++ b/examples/igloo2/.gitignore @@ -1,3 +1,4 @@ /netlist.edn /netlist.vm +/example.stp /proj diff --git a/examples/igloo2/example.pdc b/examples/igloo2/example.pdc index e6ffd53db..298d9e934 100644 --- a/examples/igloo2/example.pdc +++ b/examples/igloo2/example.pdc @@ -1 +1,20 @@ # Add placement constraints here + +set_io clk -pinname H16 -fixed yes -DIRECTION INPUT + +set_io SW1 -pinname H12 -fixed yes -DIRECTION INPUT +set_io SW2 -pinname H13 -fixed yes -DIRECTION INPUT + +set_io LED1 -pinname J16 -fixed yes -DIRECTION OUTPUT +set_io LED2 -pinname M16 -fixed yes -DIRECTION OUTPUT +set_io LED3 -pinname K16 -fixed yes -DIRECTION OUTPUT +set_io LED4 -pinname N16 -fixed yes -DIRECTION OUTPUT + +set_io AA -pinname L12 -fixed yes -DIRECTION OUTPUT +set_io AB -pinname L13 -fixed yes -DIRECTION OUTPUT +set_io AC -pinname M13 -fixed yes -DIRECTION OUTPUT +set_io AD -pinname N15 -fixed yes -DIRECTION OUTPUT +set_io AE -pinname L11 -fixed yes -DIRECTION OUTPUT +set_io AF -pinname L14 -fixed yes -DIRECTION OUTPUT +set_io AG -pinname N14 -fixed yes -DIRECTION OUTPUT +set_io CA -pinname M15 -fixed yes -DIRECTION OUTPUT diff --git a/examples/igloo2/example.sdc b/examples/igloo2/example.sdc index c6ff94161..f8b487316 100644 --- a/examples/igloo2/example.sdc +++ b/examples/igloo2/example.sdc @@ -1 +1,2 @@ # Add timing constraints here +create_clock -period 10.000 -waveform {0.000 5.000} [get_ports {clk}] diff --git a/examples/igloo2/example.v b/examples/igloo2/example.v index 1a1967d5a..4a9486e50 100644 --- a/examples/igloo2/example.v +++ b/examples/igloo2/example.v @@ -1,23 +1,64 @@ module example ( input clk, - input EN, + input SW1, + input SW2, output LED1, output LED2, output LED3, output LED4, - output LED5 + + output AA, AB, AC, AD, + output AE, AF, AG, CA ); - localparam BITS = 5; + localparam BITS = 8; localparam LOG2DELAY = 22; reg [BITS+LOG2DELAY-1:0] counter = 0; reg [BITS-1:0] outcnt; always @(posedge clk) begin - counter <= counter + EN; + counter <= counter + SW1 + SW2 + 1; outcnt <= counter >> LOG2DELAY; end - assign {LED1, LED2, LED3, LED4, LED5} = outcnt ^ (outcnt >> 1); + assign {LED1, LED2, LED3, LED4} = outcnt ^ (outcnt >> 1); + + // assign CA = counter[10]; + // seg7enc seg7encinst ( + // .seg({AA, AB, AC, AD, AE, AF, AG}), + // .dat(CA ? outcnt[3:0] : outcnt[7:4]) + // ); + + assign {AA, AB, AC, AD, AE, AF, AG} = ~(7'b 100_0000 >> outcnt[6:4]); + assign CA = outcnt[7]; +endmodule + +module seg7enc ( + input [3:0] dat, + output [6:0] seg +); + reg [6:0] seg_inv; + always @* begin + seg_inv = 0; + case (dat) + 4'h0: seg_inv = 7'b 0111111; + 4'h1: seg_inv = 7'b 0000110; + 4'h2: seg_inv = 7'b 1011011; + 4'h3: seg_inv = 7'b 1001111; + 4'h4: seg_inv = 7'b 1100110; + 4'h5: seg_inv = 7'b 1101101; + 4'h6: seg_inv = 7'b 1111101; + 4'h7: seg_inv = 7'b 0000111; + 4'h8: seg_inv = 7'b 1111111; + 4'h9: seg_inv = 7'b 1101111; + 4'hA: seg_inv = 7'b 1110111; + 4'hB: seg_inv = 7'b 1111100; + 4'hC: seg_inv = 7'b 0111001; + 4'hD: seg_inv = 7'b 1011110; + 4'hE: seg_inv = 7'b 1111001; + 4'hF: seg_inv = 7'b 1110001; + endcase + end + assign seg = ~seg_inv; endmodule diff --git a/examples/igloo2/libero.tcl b/examples/igloo2/libero.tcl index 1f3476316..abc94e479 100644 --- a/examples/igloo2/libero.tcl +++ b/examples/igloo2/libero.tcl @@ -8,13 +8,14 @@ new_project \ -block_mode 0 \ -hdl "VERILOG" \ -family IGLOO2 \ - -die PA4MGL500 \ - -package tq144 \ + -die PA4MGL2500 \ + -package vf256 \ -speed -1 import_files -hdl_source {netlist.vm} import_files -sdc {example.sdc} import_files -io_pdc {example.pdc} +build_design_hierarchy set_option -synth 0 organize_tool_files -tool PLACEROUTE \ @@ -32,22 +33,25 @@ configure_tool -name PLACEROUTE \ -params EFFORT_LEVEL:false \ -params REPAIR_MIN_DELAY:false +puts "" puts "**> COMPILE" run_tool -name {COMPILE} puts "<** COMPILE" +puts "" puts "**> PLACEROUTE" run_tool -name {PLACEROUTE} puts "<** PLACEROUTE" +puts "" puts "**> VERIFYTIMING" run_tool -name {VERIFYTIMING} puts "<** VERIFYTIMING" -save_project - -# puts "**> export_bitstream" -# export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} -# puts "<** export_bitstream" +puts "" +puts "**> BITSTREAM" +export_bitstream_file -trusted_facility_file 1 -trusted_facility_file_components {FABRIC} +puts "<** BITSTREAM" +puts "" exit 0 diff --git a/examples/igloo2/runme.sh b/examples/igloo2/runme.sh index 54247759f..a08894e0a 100644 --- a/examples/igloo2/runme.sh +++ b/examples/igloo2/runme.sh @@ -1,4 +1,6 @@ #!/bin/bash set -ex yosys -p 'synth_sf2 -top example -edif netlist.edn -vlog netlist.vm' example.v -LM_LICENSE_FILE=1702@`hostname` /opt/microsemi/Libero_SoC_v11.9/Libero/bin/libero SCRIPT:libero.tcl +export LM_LICENSE_FILE=${LM_LICENSE_FILE:-1702@localhost} +/opt/microsemi/Libero_SoC_v12.0/Libero/bin/libero SCRIPT:libero.tcl +cp proj/designer/example/export/example.stp . diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 08f91c9c3..8b185ff51 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -214,6 +214,8 @@ namespace AST MEM2REG_FL_SET_ASYNC = 0x00000800, MEM2REG_FL_EQ2 = 0x00001000, MEM2REG_FL_CMPLX_LHS = 0x00002000, + MEM2REG_FL_CONST_LHS = 0x00004000, + MEM2REG_FL_VAR_LHS = 0x00008000, /* proc flags */ MEM2REG_FL_EQ1 = 0x01000000, @@ -237,6 +239,7 @@ namespace AST bool has_const_only_constructs(bool &recommend_const_eval); void replace_variables(std::map<std::string, varinfo_t> &variables, AstNode *fcall); AstNode *eval_const_function(AstNode *fcall); + bool is_simple_const_expr(); // create a human-readable text representation of the AST (for debugging) void dumpAst(FILE *f, std::string indent) const; diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 2d591b29d..d7da6fb40 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -544,7 +544,11 @@ struct AST_INTERNAL::ProcessGenerator break; case AST_WIRE: - log_file_error(ast->filename, ast->linenum, "Found wire declaration in block without label!\n"); + log_file_error(ast->filename, ast->linenum, "Found reg declaration in block without label!\n"); + break; + + case AST_ASSIGN: + log_file_error(ast->filename, ast->linenum, "Found continous assignment in always/initial block!\n"); break; case AST_PARAMETER: @@ -1409,10 +1413,16 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(en) != 1) en = current_module->ReduceBool(NEW_ID, en); - std::stringstream sstr; - sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); + IdString cellname; + if (str.empty()) { + std::stringstream sstr; + sstr << celltype << "$" << filename << ":" << linenum << "$" << (autoidx++); + cellname = sstr.str(); + } else { + cellname = str; + } - RTLIL::Cell *cell = current_module->addCell(sstr.str(), celltype); + RTLIL::Cell *cell = current_module->addCell(cellname, celltype); cell->attributes["\\src"] = stringf("%s:%d", filename.c_str(), linenum); for (auto &attr : attributes) { diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 46013544b..1c9932ee0 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -50,7 +50,6 @@ using namespace AST_INTERNAL; bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, int width_hint, bool sign_hint, bool in_param) { static int recursion_counter = 0; - static pair<string, int> last_blocking_assignment_warn; static bool deep_recursion_warning = false; if (recursion_counter++ == 1000 && deep_recursion_warning) { @@ -72,7 +71,6 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (stage == 0) { log_assert(type == AST_MODULE || type == AST_INTERFACE); - last_blocking_assignment_warn = pair<string, int>(); deep_recursion_warning = true; while (simplify(const_fold, at_zero, in_lvalue, 1, width_hint, sign_hint, in_param)) { } @@ -113,6 +111,9 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, if (memflags & AstNode::MEM2REG_FL_CMPLX_LHS) goto verbose_activate; + if ((memflags & AstNode::MEM2REG_FL_CONST_LHS) && !(memflags & AstNode::MEM2REG_FL_VAR_LHS)) + goto verbose_activate; + // log("Note: Not replacing memory %s with list of registers (flags=0x%08lx).\n", mem->str.c_str(), long(memflags)); continue; @@ -325,6 +326,15 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, for (size_t i = 0; i < children.size(); i++) { AstNode *node = children[i]; if (node->type == AST_WIRE) { + if (node->children.size() == 1 && node->children[0]->type == AST_RANGE) { + for (auto c : node->children[0]->children) { + if (!c->is_simple_const_expr()) { + if (attributes.count("\\dynports")) + delete attributes.at("\\dynports"); + attributes["\\dynports"] = AstNode::mkconst_int(1, true); + } + } + } if (this_wire_scope.count(node->str) > 0) { AstNode *first_node = this_wire_scope[node->str]; if (first_node->is_input && node->is_reg) @@ -938,7 +948,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, } } if (current_scope.count(str) == 0) { - if (flag_autowire) { + if (flag_autowire || str == "\\$global_clock") { AstNode *auto_wire = new AstNode(AST_AUTOWIRE); auto_wire->str = str; current_ast_mod->children.push_back(auto_wire); @@ -1499,6 +1509,7 @@ skip_dynamic_range_lvalue_expansion:; newNode->children.push_back(assign_en); AstNode *assertnode = new AstNode(type); + assertnode->str = str; assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children.push_back(new AstNode(AST_IDENTIFIER)); assertnode->children[0]->str = id_check; @@ -1579,14 +1590,6 @@ skip_dynamic_range_lvalue_expansion:; sstr << "$memwr$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (autoidx++); std::string id_addr = sstr.str() + "_ADDR", id_data = sstr.str() + "_DATA", id_en = sstr.str() + "_EN"; - if (type == AST_ASSIGN_EQ) { - pair<string, int> this_blocking_assignment_warn(filename, linenum); - if (this_blocking_assignment_warn != last_blocking_assignment_warn) - log_warning("Blocking assignment to memory in line %s:%d is handled like a non-blocking assignment.\n", - filename.c_str(), linenum); - last_blocking_assignment_warn = this_blocking_assignment_warn; - } - int mem_width, mem_size, addr_bits; bool mem_signed = children[0]->id2ast->is_signed; children[0]->id2ast->meminfo(mem_width, mem_size, addr_bits); @@ -2169,6 +2172,8 @@ skip_dynamic_range_lvalue_expansion:; } newNode = readmem(str == "\\$readmemh", node_filename->bitsAsConst().decode_string(), node_memory->id2ast, start_addr, finish_addr, unconditional_init); + delete node_filename; + delete node_memory; goto apply_newNode; } @@ -2210,6 +2215,8 @@ skip_dynamic_range_lvalue_expansion:; std::map<std::string, std::string> replace_rules; vector<AstNode*> added_mod_children; dict<std::string, AstNode*> wire_cache; + vector<AstNode*> new_stmts; + vector<AstNode*> output_assignments; if (current_block == NULL) { @@ -2334,8 +2341,8 @@ skip_dynamic_range_lvalue_expansion:; wire->port_id = 0; wire->is_input = false; wire->is_output = false; - if (!child->is_output) - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->is_reg = true; + wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); wire_cache[child->str] = wire; current_ast_mod->children.push_back(wire); @@ -2357,13 +2364,10 @@ skip_dynamic_range_lvalue_expansion:; new AstNode(AST_ASSIGN_EQ, wire_id, arg) : new AstNode(AST_ASSIGN_EQ, arg, wire_id); assign->children[0]->was_checked = true; - - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, assign); - break; - } + if (child->is_input) + new_stmts.push_back(assign); + else + output_assignments.push_back(assign); } } @@ -2377,14 +2381,18 @@ skip_dynamic_range_lvalue_expansion:; { AstNode *stmt = child->clone(); stmt->replace_ids(prefix, replace_rules); + new_stmts.push_back(stmt); + } - for (auto it = current_block->children.begin(); it != current_block->children.end(); it++) { - if (*it != current_block_child) - continue; - current_block->children.insert(it, stmt); - break; - } + new_stmts.insert(new_stmts.end(), output_assignments.begin(), output_assignments.end()); + + for (auto it = current_block->children.begin(); ; it++) { + log_assert(it != current_block->children.end()); + if (*it == current_block_child) { + current_block->children.insert(it, new_stmts.begin(), new_stmts.end()); + break; } + } replace_fcall_with_id: if (type == AST_FCALL) { @@ -2910,7 +2918,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg dict<AstNode*, uint32_t> &mem2reg_candidates, dict<AstNode*, uint32_t> &proc_flags, uint32_t &flags) { uint32_t children_flags = 0; - int ignore_children_counter = 0; + int lhs_children_counter = 0; if (type == AST_ASSIGN || type == AST_ASSIGN_LE || type == AST_ASSIGN_EQ) { @@ -2936,6 +2944,16 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg proc_flags[mem] |= AstNode::MEM2REG_FL_EQ1; } + // for proper (non-init) writes: remember if this is a constant index or not + if ((flags & MEM2REG_FL_INIT) == 0) { + if (children[0]->children.size() && children[0]->children[0]->type == AST_RANGE && children[0]->children[0]->children.size()) { + if (children[0]->children[0]->children[0]->type == AST_CONSTANT) + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_CONST_LHS; + else + mem2reg_candidates[mem] |= AstNode::MEM2REG_FL_VAR_LHS; + } + } + // remember where this is if (flags & MEM2REG_FL_INIT) { if (!(mem2reg_candidates[mem] & AstNode::MEM2REG_FL_SET_INIT)) @@ -2948,7 +2966,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg } } - ignore_children_counter = 1; + lhs_children_counter = 1; } if (type == AST_IDENTIFIER && id2ast && id2ast->type == AST_MEMORY) @@ -2991,12 +3009,23 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg log_assert((flags & ~0x000000ff) == 0); for (auto child : children) - if (ignore_children_counter > 0) - ignore_children_counter--; - else if (proc_flags_p) + { + if (lhs_children_counter > 0) { + lhs_children_counter--; + if (child->children.size() && child->children[0]->type == AST_RANGE && child->children[0]->children.size()) { + for (auto c : child->children[0]->children) { + if (proc_flags_p) + c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); + else + c->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); + } + } + } else + if (proc_flags_p) child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, *proc_flags_p, flags); else child->mem2reg_as_needed_pass1(mem2reg_places, mem2reg_candidates, proc_flags, flags); + } flags &= ~children_flags | backup_flags; @@ -3048,6 +3077,39 @@ bool AstNode::mem2reg_as_needed_pass2(pool<AstNode*> &mem2reg_set, AstNode *mod, if (type == AST_FUNCTION || type == AST_TASK) return false; + if (type == AST_MEMINIT && id2ast && mem2reg_set.count(id2ast)) + { + log_assert(children[0]->type == AST_CONSTANT); + log_assert(children[1]->type == AST_CONSTANT); + log_assert(children[2]->type == AST_CONSTANT); + + int cursor = children[0]->asInt(false); + Const data = children[1]->bitsAsConst(); + int length = children[2]->asInt(false); + + if (length != 0) + { + AstNode *block = new AstNode(AST_INITIAL, new AstNode(AST_BLOCK)); + mod->children.push_back(block); + block = block->children[0]; + + int wordsz = GetSize(data) / length; + + for (int i = 0; i < length; i++) { + block->children.push_back(new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER, new AstNode(AST_RANGE, AstNode::mkconst_int(cursor+i, false))), mkconst_bits(data.extract(i*wordsz, wordsz).bits, false))); + block->children.back()->children[0]->str = str; + block->children.back()->children[0]->id2ast = id2ast; + block->children.back()->children[0]->was_checked = true; + } + } + + AstNode *newNode = new AstNode(AST_NONE); + newNode->cloneInto(this); + delete newNode; + + did_something = true; + } + if (type == AST_ASSIGN && block == NULL && children[0]->mem2reg_check(mem2reg_set)) { if (async_block == NULL) { @@ -3277,6 +3339,16 @@ bool AstNode::has_const_only_constructs(bool &recommend_const_eval) return false; } +bool AstNode::is_simple_const_expr() +{ + if (type == AST_IDENTIFIER) + return false; + for (auto child : children) + if (!child->is_simple_const_expr()) + return false; + return true; +} + // helper function for AstNode::eval_const_function() void AstNode::replace_variables(std::map<std::string, AstNode::varinfo_t> &variables, AstNode *fcall) { diff --git a/frontends/verific/README b/frontends/verific/README index c76cdd637..89584f2e8 100644 --- a/frontends/verific/README +++ b/frontends/verific/README @@ -21,7 +21,7 @@ Then run in the following command in this directory: sby -f example.sby -This will generate approximately one page of text outpout. The last lines +This will generate approximately one page of text output. The last lines should be something like this: SBY [example] summary: Elapsed clock time [H:MM:SS (secs)]: 0:00:00 (0) diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 8ee951d20..c412cd3a3 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -1855,6 +1855,13 @@ struct VerificPass : public Pass { log(" -autocover\n"); log(" Generate automatic cover statements for all asserts\n"); log("\n"); + log(" -chparam name value \n"); + log(" Elaborate the specified top modules (all modules when -all given) using\n"); + log(" this parameter value. Modules on which this parameter does not exist will\n"); + log(" cause Verific to produce a VERI-1928 or VHDL-1676 message. This option\n"); + log(" can be specified multiple times to override multiple parameters.\n"); + log(" String values must be passed in double quotes (\").\n"); + log("\n"); log(" -v, -vv\n"); log(" Verbose log messages. (-vv is even more verbose than -v.)\n"); log("\n"); @@ -2109,6 +2116,7 @@ struct VerificPass : public Pass { bool mode_autocover = false; bool flatten = false, extnets = false; string dumpfile; + Map parameters(STRING_HASH); for (argidx++; argidx < GetSize(args); argidx++) { if (args[argidx] == "-all") { @@ -2147,6 +2155,15 @@ struct VerificPass : public Pass { mode_autocover = true; continue; } + if (args[argidx] == "-chparam" && argidx+2 < GetSize(args)) { + const std::string &key = args[++argidx]; + const std::string &value = args[++argidx]; + unsigned new_insertion = parameters.Insert(key.c_str(), value.c_str(), + 1 /* force_overwrite */); + if (!new_insertion) + log_warning_noprefix("-chparam %s already specified: overwriting.\n", key.c_str()); + continue; + } if (args[argidx] == "-V") { mode_verific = true; continue; @@ -2180,7 +2197,7 @@ struct VerificPass : public Pass { if (vhdl_lib) vhdl_libs.InsertLast(vhdl_lib); if (veri_lib) veri_libs.InsertLast(veri_lib); - Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs); + Array *netlists = hier_tree::ElaborateAll(&veri_libs, &vhdl_libs, ¶meters); Netlist *nl; int i; @@ -2217,7 +2234,7 @@ struct VerificPass : public Pass { } log("Running hier_tree::Elaborate().\n"); - Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units); + Array *netlists = hier_tree::Elaborate(&veri_modules, &vhdl_units, ¶meters); Netlist *nl; int i; @@ -2316,7 +2333,7 @@ struct ReadPass : public Pass { } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { - if (args.size() < 2) + if (args.size() < 2 || args[1][0] != '-') log_cmd_error("Missing mode parameter.\n"); if (args.size() < 3) diff --git a/frontends/verific/verificsva.cc b/frontends/verific/verificsva.cc index 6681115df..8ea8372d3 100644 --- a/frontends/verific/verificsva.cc +++ b/frontends/verific/verificsva.cc @@ -1666,7 +1666,20 @@ struct VerificSvaImporter log(" importing SVA property at root cell %s (%s) at %s:%d.\n", root->Name(), root->View()->Owner()->Name(), LineFile::GetFileName(root->Linefile()), LineFile::GetLineNo(root->Linefile())); - RTLIL::IdString root_name = module->uniquify(importer->mode_names || root->IsUserDeclared() ? RTLIL::escape_id(root->Name()) : NEW_ID); + bool is_user_declared = root->IsUserDeclared(); + + // FIXME + if (!is_user_declared) { + const char *name = root->Name(); + for (int i = 0; name[i]; i++) { + if (i ? (name[i] < '0' || name[i] > '9') : (name[i] != 'i')) { + is_user_declared = true; + break; + } + } + } + + RTLIL::IdString root_name = module->uniquify(importer->mode_names || is_user_declared ? RTLIL::escape_id(root->Name()) : NEW_ID); // parse SVA sequence into trigger signal diff --git a/frontends/verilog/verilog_lexer.l b/frontends/verilog/verilog_lexer.l index 1b1873e24..6ef38252a 100644 --- a/frontends/verilog/verilog_lexer.l +++ b/frontends/verilog/verilog_lexer.l @@ -189,6 +189,14 @@ YOSYS_NAMESPACE_END "always_ff" { SV_KEYWORD(TOK_ALWAYS); } "always_latch" { SV_KEYWORD(TOK_ALWAYS); } + /* use special token for labels on assert, assume, cover, and restrict because it's insanley complex + to fix parsing of cells otherwise. (the current cell parser forces a reduce very early to update some + global state.. its a mess) */ +[a-zA-Z_$][a-zA-Z0-9_$]*/[ \t\r\n]*:[ \t\r\n]*(assert|assume|cover|restrict)[^a-zA-Z0-9_$\.] { + frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); + return TOK_SVA_LABEL; +} + "assert" { if (formal_mode) return TOK_ASSERT; SV_KEYWORD(TOK_ASSERT); } "assume" { if (formal_mode) return TOK_ASSUME; SV_KEYWORD(TOK_ASSUME); } "cover" { if (formal_mode) return TOK_COVER; SV_KEYWORD(TOK_COVER); } @@ -303,7 +311,7 @@ supply1 { return TOK_SUPPLY1; } [a-zA-Z_$][a-zA-Z0-9_$\.]* { frontend_verilog_yylval.string = new std::string(std::string("\\") + yytext); - return TOK_ID; + return TOK_ID; } "/*"[ \t]*(synopsys|synthesis)[ \t]*translate_off[ \t]*"*/" { diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index a6718b020..52685f637 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -105,7 +105,8 @@ static void free_attr(std::map<std::string, AstNode*> *al) bool boolean; } -%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE +%token <string> TOK_STRING TOK_ID TOK_CONSTVAL TOK_REALVAL TOK_PRIMITIVE TOK_SVA_LABEL +%token TOK_ASSERT TOK_ASSUME TOK_RESTRICT TOK_COVER %token ATTR_BEGIN ATTR_END DEFATTR_BEGIN DEFATTR_END %token TOK_MODULE TOK_ENDMODULE TOK_PARAMETER TOK_LOCALPARAM TOK_DEFPARAM %token TOK_PACKAGE TOK_ENDPACKAGE TOK_PACKAGESEP @@ -119,14 +120,13 @@ static void free_attr(std::map<std::string, AstNode*> *al) %token TOK_GENERATE TOK_ENDGENERATE TOK_GENVAR TOK_REAL %token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE %token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED -%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_ASSERT TOK_ASSUME -%token TOK_RESTRICT TOK_COVER TOK_PROPERTY TOK_ENUM TOK_TYPEDEF +%token TOK_POS_INDEXED TOK_NEG_INDEXED TOK_PROPERTY TOK_ENUM TOK_TYPEDEF %token TOK_RAND TOK_CONST TOK_CHECKER TOK_ENDCHECKER TOK_EVENTUALLY %token TOK_INCREMENT TOK_DECREMENT TOK_UNIQUE TOK_PRIORITY %type <ast> range range_or_multirange non_opt_range non_opt_multirange range_or_signed_int %type <ast> wire_type expr basic_expr concat_list rvalue lvalue lvalue_concat_list -%type <string> opt_label tok_prim_wrapper hierarchical_id +%type <string> opt_label opt_sva_label tok_prim_wrapper hierarchical_id %type <boolean> opt_signed opt_property unique_case_attr %type <al> attr case_attr @@ -1329,6 +1329,14 @@ opt_label: $$ = NULL; }; +opt_sva_label: + TOK_SVA_LABEL ':' { + $$ = $1; + } | + /* empty */ { + $$ = NULL; + }; + opt_property: TOK_PROPERTY { $$ = true; @@ -1337,9 +1345,6 @@ opt_property: $$ = false; }; -opt_stmt_label: - TOK_ID ':' | /* empty */; - modport_stmt: TOK_MODPORT TOK_ID { AstNode *modport = new AstNode(AST_MODPORT); @@ -1376,83 +1381,164 @@ modport_type_token: TOK_INPUT {current_modport_input = 1; current_modport_output = 0;} | TOK_OUTPUT {current_modport_input = 0; current_modport_output = 1;} assert: - opt_stmt_label TOK_ASSERT opt_property '(' expr ')' ';' { - if (noassert_mode) + opt_sva_label TOK_ASSERT opt_property '(' expr ')' ';' { + if (noassert_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' expr ')' ';' { - if (noassume_mode) + opt_sva_label TOK_ASSUME opt_property '(' expr ')' ';' { + if (noassume_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5)); + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_ASSERT : AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassert_mode) + opt_sva_label TOK_ASSERT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassert_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + } else { + AstNode *node = new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (noassume_mode) + opt_sva_label TOK_ASSUME opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (noassume_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6)); + } else { + AstNode *node = new AstNode(assert_assumes_mode ? AST_LIVE : AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_COVER opt_property '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + opt_sva_label TOK_COVER opt_property '(' expr ')' ';' { + AstNode *node = new AstNode(AST_COVER, $5); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER opt_property '(' ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER opt_property '(' ')' ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_COVER ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, AstNode::mkconst_int(1, false))); + opt_sva_label TOK_COVER ';' { + AstNode *node = new AstNode(AST_COVER, AstNode::mkconst_int(1, false)); + if ($1 != nullptr) { + node->str = *$1; + delete $1; + } + ast_stack.back()->children.push_back(node); } | - opt_stmt_label TOK_RESTRICT opt_property '(' expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + } else { + AstNode *node = new AstNode(AST_ASSUME, $5); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } if (!$3) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; } | - opt_stmt_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT opt_property '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { delete $6; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + } else { + AstNode *node = new AstNode(AST_FAIR, $6); + if ($1 != nullptr) + node->str = *$1; + ast_stack.back()->children.push_back(node); + } if (!$3) log_file_warning(current_filename, get_line_num(), "SystemVerilog does not allow \"restrict\" without \"property\".\n"); + if ($1 != nullptr) + delete $1; }; assert_property: - TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $4)); - } | - TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_ASSUME : AST_ASSERT, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $5)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + opt_sva_label TOK_ASSERT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(assume_asserts_mode ? AST_FAIR : AST_LIVE, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_COVER TOK_PROPERTY '(' expr ')' ';' { - ast_stack.back()->children.push_back(new AstNode(AST_COVER, $4)); + opt_sva_label TOK_ASSUME TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { - if (norestrict_mode) - delete $4; - else - ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $4)); + opt_sva_label TOK_COVER TOK_PROPERTY '(' expr ')' ';' { + ast_stack.back()->children.push_back(new AstNode(AST_COVER, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } } | - TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { - if (norestrict_mode) + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' expr ')' ';' { + if (norestrict_mode) { delete $5; - else - ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $5)); + } else { + ast_stack.back()->children.push_back(new AstNode(AST_ASSUME, $5)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } + } | + opt_sva_label TOK_RESTRICT TOK_PROPERTY '(' TOK_EVENTUALLY expr ')' ';' { + if (norestrict_mode) { + delete $6; + } else { + ast_stack.back()->children.push_back(new AstNode(AST_FAIR, $6)); + if ($1 != nullptr) { + ast_stack.back()->children.back()->str = *$1; + delete $1; + } + } }; simple_behavioral_stmt: @@ -1670,6 +1756,11 @@ case_expr_list: TOK_DEFAULT { ast_stack.back()->children.push_back(new AstNode(AST_DEFAULT)); } | + TOK_SVA_LABEL { + ast_stack.back()->children.push_back(new AstNode(AST_IDENTIFIER)); + ast_stack.back()->children.back()->str = *$1; + delete $1; + } | expr { ast_stack.back()->children.push_back($1); } | diff --git a/kernel/log.cc b/kernel/log.cc index 0ee2170a0..400a549dd 100644 --- a/kernel/log.cc +++ b/kernel/log.cc @@ -196,7 +196,11 @@ void logv_header(RTLIL::Design *design, const char *format, va_list ap) if (log_hdump.count(header_id) && design != nullptr) for (auto &filename : log_hdump.at(header_id)) { log("Dumping current design to '%s'.\n", filename.c_str()); + if (yosys_xtrace) + IdString::xtrace_db_dump(); Pass::call(design, {"dump", "-o", filename}); + if (yosys_xtrace) + log("#X# -- end of dump --\n"); } if (pop_errfile) diff --git a/kernel/register.cc b/kernel/register.cc index 402a5b3ea..64956401f 100644 --- a/kernel/register.cc +++ b/kernel/register.cc @@ -86,6 +86,8 @@ Pass::pre_post_exec_state_t Pass::pre_execute() void Pass::post_execute(Pass::pre_post_exec_state_t state) { + IdString::checkpoint(); + int64_t time_ns = PerformanceTimer::query() - state.begin_ns; runtime_ns += time_ns; current_pass = state.parent_pass; diff --git a/kernel/rtlil.cc b/kernel/rtlil.cc index d4aebcda9..7f1816190 100644 --- a/kernel/rtlil.cc +++ b/kernel/rtlil.cc @@ -33,6 +33,8 @@ std::vector<int> RTLIL::IdString::global_refcount_storage_; std::vector<char*> RTLIL::IdString::global_id_storage_; dict<char*, int, hash_cstr_ops> RTLIL::IdString::global_id_index_; std::vector<int> RTLIL::IdString::global_free_idx_list_; +int RTLIL::IdString::last_created_idx_[8]; +int RTLIL::IdString::last_created_idx_ptr_; RTLIL::Const::Const() { diff --git a/kernel/rtlil.h b/kernel/rtlil.h index f877622aa..01323d112 100644 --- a/kernel/rtlil.h +++ b/kernel/rtlil.h @@ -76,6 +76,9 @@ namespace RTLIL struct IdString { + #undef YOSYS_XTRACE_GET_PUT + #undef YOSYS_SORT_ID_FREE_LIST + // the global id string cache static struct destruct_guard_t { @@ -89,9 +92,43 @@ namespace RTLIL static dict<char*, int, hash_cstr_ops> global_id_index_; static std::vector<int> global_free_idx_list_; + static int last_created_idx_ptr_; + static int last_created_idx_[8]; + + static inline void xtrace_db_dump() + { + #ifdef YOSYS_XTRACE_GET_PUT + for (int idx = 0; idx < GetSize(global_id_storage_); idx++) + { + if (global_id_storage_.at(idx) == nullptr) + log("#X# DB-DUMP index %d: FREE\n", idx); + else + log("#X# DB-DUMP index %d: '%s' (ref %d)\n", idx, global_id_storage_.at(idx), global_refcount_storage_.at(idx)); + } + #endif + } + + static inline void checkpoint() + { + last_created_idx_ptr_ = 0; + for (int i = 0; i < 8; i++) { + if (last_created_idx_[i]) + put_reference(last_created_idx_[i]); + last_created_idx_[i] = 0; + } + #ifdef YOSYS_SORT_ID_FREE_LIST + std::sort(global_free_idx_list_.begin(), global_free_idx_list_.end(), std::greater<int>()); + #endif + } + static inline int get_reference(int idx) { global_refcount_storage_.at(idx)++; + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# GET-BY-INDEX '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + } + #endif return idx; } @@ -107,6 +144,11 @@ namespace RTLIL auto it = global_id_index_.find((char*)p); if (it != global_id_index_.end()) { global_refcount_storage_.at(it->second)++; + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(it->second), it->second, global_refcount_storage_.at(it->second)); + } + #endif return it->second; } @@ -124,16 +166,22 @@ namespace RTLIL global_refcount_storage_.at(idx)++; // Avoid Create->Delete->Create pattern - static IdString last_created_id; - put_reference(last_created_id.index_); - last_created_id.index_ = idx; - get_reference(last_created_id.index_); + if (last_created_idx_[last_created_idx_ptr_]) + put_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_[last_created_idx_ptr_] = idx; + get_reference(last_created_idx_[last_created_idx_ptr_]); + last_created_idx_ptr_ = (last_created_idx_ptr_ + 1) & 7; if (yosys_xtrace) { log("#X# New IdString '%s' with index %d.\n", p, idx); log_backtrace("-X- ", yosys_xtrace-1); } + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# GET-BY-NAME '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + } + #endif return idx; } @@ -144,6 +192,12 @@ namespace RTLIL if (!destruct_guard.ok) return; + #ifdef YOSYS_XTRACE_GET_PUT + if (yosys_xtrace) { + log("#X# PUT '%s' (index %d, refcount %d)\n", global_id_storage_.at(idx), idx, global_refcount_storage_.at(idx)); + } + #endif + log_assert(global_refcount_storage_.at(idx) > 0); if (--global_refcount_storage_.at(idx) != 0) @@ -1282,7 +1336,7 @@ inline bool RTLIL::SigBit::operator<(const RTLIL::SigBit &other) const { return wire ? (offset < other.offset) : (data < other.data); if (wire != nullptr && other.wire != nullptr) return wire->name < other.wire->name; - return wire < other.wire; + return (wire != nullptr) < (other.wire != nullptr); } inline bool RTLIL::SigBit::operator==(const RTLIL::SigBit &other) const { diff --git a/kernel/yosys.cc b/kernel/yosys.cc index 2ed0f4db4..450e4e4cf 100644 --- a/kernel/yosys.cc +++ b/kernel/yosys.cc @@ -33,7 +33,7 @@ # include <dlfcn.h> #endif -#ifdef _WIN32 +#if defined(_WIN32) # include <windows.h> # include <io.h> #elif defined(__APPLE__) @@ -41,13 +41,15 @@ # include <unistd.h> # include <dirent.h> # include <sys/stat.h> -# include <glob.h> #else # include <unistd.h> # include <dirent.h> # include <sys/types.h> # include <sys/wait.h> # include <sys/stat.h> +#endif + +#if !defined(_WIN32) && defined(YOSYS_ENABLE_GLOB) # include <glob.h> #endif @@ -216,12 +218,18 @@ std::string next_token(std::string &text, const char *sep, bool long_strings) if (long_strings && pos_begin != text.size() && text[pos_begin] == '"') { string sep_string = sep; - for (size_t i = pos_begin+1; i < text.size(); i++) + for (size_t i = pos_begin+1; i < text.size(); i++) { if (text[i] == '"' && (i+1 == text.size() || sep_string.find(text[i+1]) != std::string::npos)) { std::string token = text.substr(pos_begin, i-pos_begin+1); text = text.substr(i+1); return token; } + if (i+1 < text.size() && text[i] == '"' && text[i+1] == ';' && (i+2 == text.size() || sep_string.find(text[i+2]) != std::string::npos)) { + std::string token = text.substr(pos_begin, i-pos_begin+1); + text = text.substr(i+2); + return token + ";"; + } + } } size_t pos_end = text.find_first_of(sep, pos_begin); @@ -564,7 +572,7 @@ std::vector<std::string> glob_filename(const std::string &filename_pattern) { std::vector<std::string> results; -#ifdef _WIN32 +#if defined(_WIN32) || !defined(YOSYS_ENABLE_GLOB) results.push_back(filename_pattern); #else glob_t globbuf; diff --git a/misc/yosys.proto b/misc/yosys.proto index 2870176cb..a583e6265 100644 --- a/misc/yosys.proto +++ b/misc/yosys.proto @@ -1,12 +1,12 @@ // // yosys -- Yosys Open SYnthesis Suite -// +// // Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> -// +// // 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 @@ -73,7 +73,7 @@ message Module { BitVector bits = 2; } map<string, Port> port = 2; - + // Named cells in this module. message Cell { // Set to true when the name of this cell is automatically created and @@ -129,7 +129,7 @@ message Model { TYPE_FALSE = 6; }; Type type = 1; - + message Port { // Name of port. string portname = 1; @@ -148,7 +148,7 @@ message Model { // Set for AND, NAND. Gate gate = 3; } - + // Set when the node drives given output port(s). message OutPort { // Name of port. diff --git a/passes/hierarchy/hierarchy.cc b/passes/hierarchy/hierarchy.cc index 2d8edebb5..88c339e8c 100644 --- a/passes/hierarchy/hierarchy.cc +++ b/passes/hierarchy/hierarchy.cc @@ -910,7 +910,7 @@ struct HierarchyPass : public Pass { if (m == nullptr) continue; - if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty()) { + if (m->get_bool_attribute("\\blackbox") && !cell->parameters.empty() && m->get_bool_attribute("\\dynports")) { IdString new_m_name = m->derive(design, cell->parameters, true); if (new_m_name.empty()) continue; diff --git a/passes/opt/wreduce.cc b/passes/opt/wreduce.cc index 09983bc67..1f7222e49 100644 --- a/passes/opt/wreduce.cc +++ b/passes/opt/wreduce.cc @@ -53,6 +53,7 @@ struct WreduceWorker std::set<Cell*, IdString::compare_ptr_by_name<Cell>> work_queue_cells; std::set<SigBit> work_queue_bits; pool<SigBit> keep_bits; + dict<SigBit, State> init_bits; WreduceWorker(WreduceConfig *config, Module *module) : config(config), module(module), mi(module) { } @@ -141,6 +142,7 @@ struct WreduceWorker SigSpec sig_d = mi.sigmap(cell->getPort("\\D")); SigSpec sig_q = mi.sigmap(cell->getPort("\\Q")); + Const initval; int width_before = GetSize(sig_q); @@ -150,16 +152,24 @@ struct WreduceWorker bool zero_ext = sig_d[GetSize(sig_d)-1] == State::S0; bool sign_ext = !zero_ext; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sig_q[i]; + if (init_bits.count(bit)) + initval.bits.push_back(init_bits.at(bit)); + else + initval.bits.push_back(State::Sx); + } + for (int i = GetSize(sig_q)-1; i >= 0; i--) { - if (zero_ext && sig_d[i] == State::S0) { + if (zero_ext && sig_d[i] == State::S0 && (initval[i] == State::S0 || initval[i] == State::Sx)) { module->connect(sig_q[i], State::S0); sig_d.remove(i); sig_q.remove(i); continue; } - if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1]) { + if (sign_ext && i > 0 && sig_d[i] == sig_d[i-1] && initval[i] == initval[i-1]) { module->connect(sig_q[i], sig_q[i-1]); sig_d.remove(i); sig_q.remove(i); @@ -167,7 +177,7 @@ struct WreduceWorker } auto info = mi.query(sig_q[i]); - if (!info->is_output && GetSize(info->ports) <= 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { + if (!info->is_output && GetSize(info->ports) == 1 && !keep_bits.count(mi.sigmap(sig_q[i]))) { sig_d.remove(i); sig_q.remove(i); zero_ext = false; @@ -183,10 +193,11 @@ struct WreduceWorker if (GetSize(sig_q) == 0) { log("Removed cell %s.%s (%s).\n", log_id(module), log_id(cell), log_id(cell->type)); + module->remove(cell); return; } - log("Removed top %d bits (of %d) from mux cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, + log("Removed top %d bits (of %d) from FF cell %s.%s (%s).\n", width_before - GetSize(sig_q), width_before, log_id(module), log_id(cell), log_id(cell->type)); for (auto bit : sig_d) @@ -376,10 +387,18 @@ struct WreduceWorker void run() { - for (auto w : module->wires()) + for (auto w : module->wires()) { if (w->get_bool_attribute("\\keep")) for (auto bit : mi.sigmap(w)) keep_bits.insert(bit); + if (w->attributes.count("\\init")) { + Const initval = w->attributes.at("\\init"); + SigSpec initsig = mi.sigmap(w); + int width = std::min(GetSize(initval), GetSize(initsig)); + for (int i = 0; i < width; i++) + init_bits[initsig[i]] = initval[i]; + } + } for (auto c : module->selected_cells()) work_queue_cells.insert(c); diff --git a/passes/pmgen/Makefile.inc b/passes/pmgen/Makefile.inc index 33baaca30..e0609d9ba 100644 --- a/passes/pmgen/Makefile.inc +++ b/passes/pmgen/Makefile.inc @@ -4,5 +4,5 @@ passes/pmgen/ice40_dsp.o: passes/pmgen/ice40_dsp_pm.h EXTRA_OBJS += passes/pmgen/ice40_dsp_pm.h .SECONDARY: passes/pmgen/ice40_dsp_pm.h -passes/pmgen/ice40_dsp_pm.h: passes/pmgen/ice40_dsp.pmg passes/pmgen/pmgen.py - $(P) cd passes/pmgen && python3 pmgen.py ice40_dsp +passes/pmgen/ice40_dsp_pm.h: passes/pmgen/pmgen.py passes/pmgen/ice40_dsp.pmg + $(P) mkdir -p passes/pmgen && python3 $^ $@ diff --git a/passes/pmgen/README.md b/passes/pmgen/README.md index a1007dc62..223b43059 100644 --- a/passes/pmgen/README.md +++ b/passes/pmgen/README.md @@ -16,7 +16,7 @@ API of Generated Matcher ======================== When `pmgen.py` reads a `foobar.pmg` file, it writes `foobar_pm.h` containing -a class `foobar_pm`. That class is instanciated with an RTLIL module and a +a class `foobar_pm`. That class is instantiated with an RTLIL module and a list of cells from that module: foobar_pm pm(module, module->selected_cells()); @@ -142,7 +142,7 @@ The `select` lines are evaluated once for each cell when the matcher is initialized. A `match` block will only consider cells for which all `select` expressions evaluated to `true`. Note that the state variable corresponding to the match (in the example `mul`) is the only state variable that may be used -`select` lines. +in `select` lines. Index lines are using the `index <type> expr1 === expr2` syntax. `expr1` is evaluated during matcher initialization and the same restrictions apply as for diff --git a/passes/pmgen/pmgen.py b/passes/pmgen/pmgen.py index e688a4567..d9747b065 100644 --- a/passes/pmgen/pmgen.py +++ b/passes/pmgen/pmgen.py @@ -6,7 +6,11 @@ import pprint pp = pprint.PrettyPrinter(indent=4) -prefix = sys.argv[1] +pmgfile = sys.argv[1] +assert pmgfile.endswith(".pmg") +prefix = pmgfile[0:-4] +prefix = prefix.split('/')[-1] +outfile = sys.argv[2] state_types = dict() udata_types = dict() @@ -73,7 +77,7 @@ def rewrite_cpp(s): return "".join(t) -with open("%s.pmg" % prefix, "r") as f: +with open(pmgfile, "r") as f: while True: line = f.readline() if line == "": break @@ -82,7 +86,7 @@ with open("%s.pmg" % prefix, "r") as f: cmd = line.split() if len(cmd) == 0 or cmd[0].startswith("//"): continue cmd = cmd[0] - + if cmd == "state": m = re.match(r"^state\s+<(.*?)>\s+(([A-Za-z_][A-Za-z_0-9]*\s+)*[A-Za-z_][A-Za-z_0-9]*)\s*$", line) assert m @@ -176,7 +180,7 @@ with open("%s.pmg" % prefix, "r") as f: blocks.append(block) -with open("%s_pm.h" % prefix, "w") as f: +with open(outfile, "w") as f: print("// Generated by pmgen.py from {}.pgm".format(prefix), file=f) print("", file=f) diff --git a/passes/sat/Makefile.inc b/passes/sat/Makefile.inc index 8ab0280c0..6cb1ea644 100644 --- a/passes/sat/Makefile.inc +++ b/passes/sat/Makefile.inc @@ -8,4 +8,5 @@ OBJS += passes/sat/expose.o OBJS += passes/sat/assertpmux.o OBJS += passes/sat/clk2fflogic.o OBJS += passes/sat/async2sync.o +OBJS += passes/sat/supercover.o diff --git a/passes/sat/async2sync.cc b/passes/sat/async2sync.cc index c92db7118..d045d0dcb 100644 --- a/passes/sat/async2sync.cc +++ b/passes/sat/async2sync.cc @@ -39,7 +39,7 @@ struct Async2syncPass : public Pass { log("reset value in the next cycle regardless of the data-in value at the time of\n"); log("the clock edge.\n"); log("\n"); - log("Currently only $adff cells are supported by this pass.\n"); + log("Currently only $adff and $dffsr cells are supported by this pass.\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -84,7 +84,7 @@ struct Async2syncPass : public Pass { bool arst_pol = cell->parameters["\\ARST_POLARITY"].as_bool(); Const arst_val = cell->parameters["\\ARST_VALUE"]; - SigSpec sig_clk = cell->getPort("\\CLK"); + // SigSpec sig_clk = cell->getPort("\\CLK"); SigSpec sig_arst = cell->getPort("\\ARST"); SigSpec sig_d = cell->getPort("\\D"); SigSpec sig_q = cell->getPort("\\Q"); @@ -120,6 +120,55 @@ struct Async2syncPass : public Pass { cell->type = "$dff"; continue; } + + if (cell->type.in("$dffsr")) + { + // bool clk_pol = cell->parameters["\\CLK_POLARITY"].as_bool(); + bool set_pol = cell->parameters["\\SET_POLARITY"].as_bool(); + bool clr_pol = cell->parameters["\\CLR_POLARITY"].as_bool(); + + // SigSpec sig_clk = cell->getPort("\\CLK"); + SigSpec sig_set = cell->getPort("\\SET"); + SigSpec sig_clr = cell->getPort("\\CLR"); + SigSpec sig_d = cell->getPort("\\D"); + SigSpec sig_q = cell->getPort("\\Q"); + + log("Replacing %s.%s (%s): SET=%s, CLR=%s, D=%s, Q=%s\n", + log_id(module), log_id(cell), log_id(cell->type), + log_signal(sig_set), log_signal(sig_clr), log_signal(sig_d), log_signal(sig_q)); + + Const init_val; + for (int i = 0; i < GetSize(sig_q); i++) { + SigBit bit = sigmap(sig_q[i]); + init_val.bits.push_back(initbits.count(bit) ? initbits.at(bit) : State::Sx); + del_initbits.insert(bit); + } + + Wire *new_d = module->addWire(NEW_ID, GetSize(sig_d)); + Wire *new_q = module->addWire(NEW_ID, GetSize(sig_q)); + new_q->attributes["\\init"] = init_val; + + if (!set_pol) + sig_set = module->Not(NEW_ID, sig_set); + + if (clr_pol) + sig_clr = module->Not(NEW_ID, sig_clr); + + SigSpec tmp = module->Or(NEW_ID, sig_d, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, new_d); + + tmp = module->Or(NEW_ID, new_q, sig_set); + module->addAnd(NEW_ID, tmp, sig_clr, sig_q); + + cell->setPort("\\D", new_d); + cell->setPort("\\Q", new_q); + cell->unsetPort("\\SET"); + cell->unsetPort("\\CLR"); + cell->unsetParam("\\SET_POLARITY"); + cell->unsetParam("\\CLR_POLARITY"); + cell->type = "$dff"; + continue; + } } for (auto wire : module->wires()) diff --git a/passes/sat/supercover.cc b/passes/sat/supercover.cc new file mode 100644 index 000000000..ba44f02d8 --- /dev/null +++ b/passes/sat/supercover.cc @@ -0,0 +1,92 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct SupercoverPass : public Pass { + SupercoverPass() : Pass("supercover", "add hi/lo cover cells for each wire bit") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" supercover [options] [selection]\n"); + log("\n"); + log("This command adds two cover cells for each bit of each selected wire, one\n"); + log("checking for a hi signal level and one checking for lo level.\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + // bool flag_noinit = false; + + log_header(design, "Executing SUPERCOVER pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-noinit") { + // flag_noinit = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + SigMap sigmap(module); + pool<SigBit> handled_bits; + + int cnt_wire = 0, cnt_bits = 0; + log("Adding cover cells to module %s.\n", log_id(module)); + for (auto wire : module->selected_wires()) + { + bool counted_wire = false; + std::string src = wire->get_src_attribute(); + + for (auto bit : sigmap(SigSpec(wire))) + { + if (bit.wire == nullptr) + continue; + + if (handled_bits.count(bit)) + continue; + + SigSpec inv = module->Not(NEW_ID, bit); + module->addCover(NEW_ID, bit, State::S1, src); + module->addCover(NEW_ID, inv, State::S1, src); + + handled_bits.insert(bit); + if (!counted_wire) { + counted_wire = false; + cnt_wire++; + } + cnt_bits++; + } + } + log(" added cover cells to %d wires, %d bits.\n", cnt_wire, cnt_bits); + } + } +} SupercoverPass; + +PRIVATE_NAMESPACE_END diff --git a/passes/techmap/dfflibmap.cc b/passes/techmap/dfflibmap.cc index b0528d473..274177a68 100644 --- a/passes/techmap/dfflibmap.cc +++ b/passes/techmap/dfflibmap.cc @@ -660,8 +660,8 @@ struct DfflibmapPass : public Pass { map_adff_to_dff("$_DFF_PP0_", "$_DFF_P_"); map_adff_to_dff("$_DFF_PP1_", "$_DFF_P_"); - log(" final dff cell mappings:\n"); - logmap_all(); + log(" final dff cell mappings:\n"); + logmap_all(); for (auto &it : design->modules_) if (design->selected(it.second) && !it.second->get_bool_attribute("\\blackbox")) diff --git a/passes/techmap/flowmap.cc b/passes/techmap/flowmap.cc index ddbd7bf5d..0b7931e48 100644 --- a/passes/techmap/flowmap.cc +++ b/passes/techmap/flowmap.cc @@ -132,9 +132,9 @@ static void dump_dot_graph(string filename, pool<RTLIL::SigBit> nodes, dict<RTLIL::SigBit, pool<RTLIL::SigBit>> edges, pool<RTLIL::SigBit> inputs, pool<RTLIL::SigBit> outputs, std::function<GraphStyle(RTLIL::SigBit)> node_style = - [](RTLIL::SigBit) { return GraphStyle{}; }, + [](RTLIL::SigBit) { return GraphStyle{}; }, std::function<GraphStyle(RTLIL::SigBit, RTLIL::SigBit)> edge_style = - [](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; }, + [](RTLIL::SigBit, RTLIL::SigBit) { return GraphStyle{}; }, string name = "") { FILE *f = fopen(filename.c_str(), "w"); diff --git a/techlibs/achronix/speedster22i/cells_sim.v b/techlibs/achronix/speedster22i/cells_sim.v index a94dce9b1..a0c60b4be 100755 --- a/techlibs/achronix/speedster22i/cells_sim.v +++ b/techlibs/achronix/speedster22i/cells_sim.v @@ -30,7 +30,7 @@ endmodule module PADOUT (output padout, input padin, input oe); assign padout = padin; assign oe = oe; -endmodule +endmodule module LUT4 (output dout, input din0, din1, din2, din3); @@ -66,14 +66,14 @@ always @(dataa_w or datab_w or datac_w or datad_w) begin datac_w, datad_w); end assign dout = combout_rt & 1'b1; -endmodule +endmodule module DFF (output q, input d, ck); reg q; always @(posedge ck) q <= d; - + endmodule diff --git a/techlibs/anlogic/anlogic_eqn.cc b/techlibs/anlogic/anlogic_eqn.cc index c025c65c4..741bf04cc 100644 --- a/techlibs/anlogic/anlogic_eqn.cc +++ b/techlibs/anlogic/anlogic_eqn.cc @@ -52,13 +52,13 @@ struct AnlogicEqnPass : public Pass { eqn += names[j]; else eqn += std::string("~") + names[j]; - + if (j!=(inputs-1)) eqn += "*"; } eqn += ")+"; } } - if (eqn.empty()) return Const("0"); + if (eqn.empty()) return Const("0"); eqn = eqn.substr(0, eqn.length()-1); return Const(eqn); } diff --git a/techlibs/ecp5/Makefile.inc b/techlibs/ecp5/Makefile.inc index 8df02be5f..4db087e87 100644 --- a/techlibs/ecp5/Makefile.inc +++ b/techlibs/ecp5/Makefile.inc @@ -1,5 +1,5 @@ -OBJS += techlibs/ecp5/synth_ecp5.o +OBJS += techlibs/ecp5/synth_ecp5.o techlibs/ecp5/ecp5_ffinit.o $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_map.v)) $(eval $(call add_share_file,share/ecp5,techlibs/ecp5/cells_sim.v)) diff --git a/techlibs/ecp5/arith_map.v b/techlibs/ecp5/arith_map.v index 1094c5f8a..eb7947601 100644 --- a/techlibs/ecp5/arith_map.v +++ b/techlibs/ecp5/arith_map.v @@ -33,7 +33,7 @@ module _80_ecp5_alu (A, B, CI, BI, X, Y, CO); input CI, BI; output [Y_WIDTH-1:0] CO; - wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; + wire _TECHMAP_FAIL_ = Y_WIDTH <= 4; 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)); diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index 425d62d24..223e19b9e 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -156,6 +156,41 @@ module OSCG( parameter DIV = 128; endmodule +(* blackbox *) (* keep *) +module USRMCLK( + input USRMCLKI, USRMCLKTS, + output USRMCLKO +); +endmodule + +(* blackbox *) (* keep *) +module JTAGG( + input TCK, TMS, TDI, JTDO2, JTDO1, + output TDO, JTDI, JTCK, JRTI2, JRTI1, + output JSHIFT, JUPDATE, JRSTN, JCE2, JCE1 +); +parameter ER1 = "ENABLED"; +parameter ER2 = "ENABLED"; +endmodule + +(* blackbox *) +module DELAYF( + input A, LOADN, MOVE, DIRECTION, + output Z, CFLAG +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + +(* blackbox *) +module DELAYG( + input A, + output Z +); + parameter DEL_MODE = "USER_DEFINED"; + parameter DEL_VALUE = 0; +endmodule + (* blackbox *) module IDDRX1F( input D, SCLK, RST, @@ -165,6 +200,31 @@ module IDDRX1F( endmodule (* blackbox *) +module IDDRX2F( + input D, SCLK, ECLK, RST, + output Q0, Q1, Q2, Q3 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDR71B( + input D, SCLK, ECLK, RST, ALIGNWD, + output Q0, Q1, Q2, Q3, Q4, Q5, Q6 +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module IDDRX2DQA( + input D, DQSR90, ECLK, SCLK, RST, + input RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output Q0, Q1, Q2, Q3, QWL +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) module ODDRX1F( input SCLK, RST, D0, D1, output Q @@ -173,6 +233,91 @@ module ODDRX1F( endmodule (* blackbox *) +module ODDRX2F( + input SCLK, ECLK, RST, D0, D1, D2, D3, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDR71B( + input SCLK, ECLK, RST, D0, D1, D2, D3, D4, D5, D6, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module OSHX2A( + input D0, D1, RST, ECLK, SCLK, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQA( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW270, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module ODDRX2DQSB( + input D0, D1, D2, D3, RST, ECLK, SCLK, DQSW, + output Q +); + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module TSHX2DQA( + input T0, T1, SCLK, ECLK, DQSW270, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module TSHX2DQSA( + input T0, T1, SCLK, ECLK, DQSW, RST, + output Q +); + parameter GSR = "ENABLED"; + parameter REGSET = "SET"; +endmodule + +(* blackbox *) +module DQSBUFM( + input DQSI, READ1, READ0, READCLKSEL2, READCLKSEL1, READCLKSEL0, DDRDEL, + input ECLK, SCLK, + input DYNDELAY7, DYNDELAY6, DYNDELAY5, DYNDELAY4, + input DYNDELAY3, DYNDELAY2, DYNDELAY1, DYNDELAY0, + input RST, RDLOADN, RDMOVE, RDDIRECTION, WRLOADN, WRMOVE, WRDIRECTION, PAUSE, + output DQSR90, DQSW, DQSW270, + output RDPNTR2, RDPNTR1, RDPNTR0, WRPNTR2, WRPNTR1, WRPNTR0, + output DATAVALID, BURSTDET, RDCFLAG, WRCFLAG +); + parameter DQS_LI_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LI_DEL_VAL = 0; + parameter DQS_LO_DEL_ADJ = "FACTORYONLY"; + parameter DQS_LO_DEL_VAL = 0; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) +module DDRDLLA( + input CLK, RST, UDDCNTLN, FREEZE, + output LOCK, DDRDEL, DCNTL7, DCNTL6, DCNTL5, DCNTL4, DCNTL3, DCNTL2, DCNTL1, DCNTL0 +); + parameter FORCE_MAX_DELAY = "NO"; + parameter GSR = "ENABLED"; +endmodule + +(* blackbox *) module CLKDIVF( input CLKI, RST, ALIGNWD, output CDIVX @@ -182,6 +327,13 @@ module CLKDIVF( endmodule (* blackbox *) +module ECLKSYNCB( + input ECLKI, STOP, + output ECLKO +); +endmodule + +(* blackbox *) module DCCA( input CLKI, CE, output CLKO diff --git a/techlibs/ecp5/cells_map.v b/techlibs/ecp5/cells_map.v index 23182bdeb..6ab4b69f2 100644 --- a/techlibs/ecp5/cells_map.v +++ b/techlibs/ecp5/cells_map.v @@ -47,6 +47,9 @@ module \$__DFFSE_NP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED" module \$__DFFSE_PP0 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("RESET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule module \$__DFFSE_PP1 (input D, C, E, R, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("CE"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("LSR_OVER_CE")) _TECHMAP_REPLACE_ (.CLK(C), .CE(E), .LSR(R), .DI(D), .Q(Q)); endmodule +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); TRELLIS_FF #(.GSR("DISABLED"), .CEMUX("1"), .CLKMUX("CLK"), .LSRMUX("LSR"), .REGSET("SET"), .SRMODE("ASYNC")) _TECHMAP_REPLACE_ (.CLK(CK), .LSR(PD), .DI(D), .Q(Q)); endmodule + `ifndef NO_LUT module \$lut (A, Y); parameter WIDTH = 0; diff --git a/techlibs/ecp5/cells_sim.v b/techlibs/ecp5/cells_sim.v index 507ab1beb..1e4002ee0 100644 --- a/techlibs/ecp5/cells_sim.v +++ b/techlibs/ecp5/cells_sim.v @@ -57,7 +57,7 @@ module TRELLIS_RAM16X2 ( input RAD0, RAD1, RAD2, RAD3, output DO0, DO1 ); - parameter WCKMUX = "WCK"; + parameter WCKMUX = "WCK"; parameter WREMUX = "WRE"; parameter INITVAL_0 = 16'h0000; parameter INITVAL_1 = 16'h0000; @@ -104,7 +104,7 @@ module TRELLIS_DPR16X4 ( input [3:0] RAD, output [3:0] DO ); - parameter WCKMUX = "WCK"; + parameter WCKMUX = "WCK"; parameter WREMUX = "WRE"; parameter [63:0] INITVAL = 64'h0000000000000000; @@ -203,13 +203,14 @@ endmodule // --------------------------------------- -module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); +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"; reg muxce; always @(*) @@ -222,8 +223,13 @@ module TRELLIS_FF(input CLK, LSR, CE, DI, output reg Q); wire muxlsr = (LSRMUX == "INV") ? ~LSR : LSR; wire muxclk = (CLKMUX == "INV") ? ~CLK : CLK; - - localparam srval = (REGSET == "SET") ? 1'b1 : 1'b0; + wire srval; + generate + if (LSRMODE == "PRLD") + assign srval = M; + else + assign srval = (REGSET == "SET") ? 1'b1 : 1'b0; + endgenerate initial Q = srval; @@ -339,6 +345,8 @@ module TRELLIS_SLICE( parameter REG1_SD = "0"; parameter REG0_REGSET = "RESET"; parameter REG1_REGSET = "RESET"; + parameter REG0_LSRMODE = "LSR"; + parameter REG1_LSRMODE = "LSR"; parameter [127:0] CCU2_INJECT1_0 = "NO"; parameter [127:0] CCU2_INJECT1_1 = "NO"; parameter WREMUX = "WRE"; @@ -428,10 +436,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG0_REGSET) + .REGSET(REG0_REGSET), + .LSRMODE(REG0_LSRMODE) ) ff_0 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi0), + .DI(muxdi0), .M(M0), .Q(Q0) ); TRELLIS_FF #( @@ -440,10 +449,11 @@ module TRELLIS_SLICE( .CLKMUX(CLKMUX), .LSRMUX(LSRMUX), .SRMODE(SRMODE), - .REGSET(REG1_REGSET) + .REGSET(REG1_REGSET), + .LSRMODE(REG1_LSRMODE) ) ff_1 ( .CLK(CLK), .LSR(LSR), .CE(CE), - .DI(muxdi1), + .DI(muxdi1), .M(M1), .Q(Q1) ); endmodule @@ -547,3 +557,20 @@ module DP16KD( parameter INITVAL_3E = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; parameter INITVAL_3F = 320'h00000000000000000000000000000000000000000000000000000000000000000000000000000000; endmodule + +// For Diamond compatibility, FIXME: add all Diamond flipflop mappings +module FD1S3BX(input PD, D, CK, output Q); + TRELLIS_FF #( + .GSR("DISABLED"), + .CEMUX("1"), + .CLKMUX("CLK"), + .LSRMUX("LSR"), + .REGSET("SET"), + .SRMODE("ASYNC") + ) tff_i ( + .CLK(CK), + .LSR(PD), + .DI(D), + .Q(Q) + ); +endmodule diff --git a/techlibs/ecp5/ecp5_ffinit.cc b/techlibs/ecp5/ecp5_ffinit.cc new file mode 100644 index 000000000..dbd16cac9 --- /dev/null +++ b/techlibs/ecp5/ecp5_ffinit.cc @@ -0,0 +1,203 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018-19 David Shah <david@symbioticeda.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +struct Ecp5FfinitPass : public Pass { + Ecp5FfinitPass() : Pass("ecp5_ffinit", "ECP5: handle FF init values") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ecp5_ffinit [options] [selection]\n"); + log("\n"); + log("Remove init values for FF output signals when equal to reset value.\n"); + log("If reset is not used, set the reset value to the init value, otherwise\n"); + log("unmap out the reset (if not an async reset).\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ECP5_FFINIT pass (implement FF init values).\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) + { + // if (args[argidx] == "-singleton") { + // singleton_mode = true; + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + { + log("Handling FF init values in %s.\n", log_id(module)); + + SigMap sigmap(module); + pool<Wire*> init_wires; + dict<SigBit, State> initbits; + dict<SigBit, SigBit> initbit_to_wire; + pool<SigBit> handled_initbits; + + for (auto wire : module->selected_wires()) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const initval = wire->attributes.at("\\init"); + init_wires.insert(wire); + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) + { + SigBit bit = wirebits[i]; + State val = initval[i]; + + if (val != State::S0 && val != State::S1) + continue; + + if (initbits.count(bit)) { + if (initbits.at(bit) != val) { + log_warning("Conflicting init values for signal %s (%s = %s, %s = %s).\n", + log_signal(bit), log_signal(SigBit(wire, i)), log_signal(val), + log_signal(initbit_to_wire[bit]), log_signal(initbits.at(bit))); + initbits.at(bit) = State::Sx; + } + continue; + } + + initbits[bit] = val; + initbit_to_wire[bit] = SigBit(wire, i); + } + } + for (auto cell : module->selected_cells()) + { + if (cell->type != "\\TRELLIS_FF") + continue; + SigSpec sig_d = cell->getPort("\\DI"); + SigSpec sig_q = cell->getPort("\\Q"); + SigSpec sig_lsr = cell->getPort("\\LSR"); + + if (GetSize(sig_d) < 1 || GetSize(sig_q) < 1) + continue; + + SigBit bit_d = sigmap(sig_d[0]); + SigBit bit_q = sigmap(sig_q[0]); + + std::string regset = "RESET"; + if (cell->hasParam("\\REGSET")) + regset = cell->getParam("\\REGSET").decode_string(); + State resetState; + if (regset == "SET") + resetState = State::S1; + else if (regset == "RESET") + resetState = State::S0; + else + log_error("FF cell %s has illegal REGSET value %s.\n", + log_id(cell), regset.c_str()); + + if (!initbits.count(bit_q)) + continue; + + State val = initbits.at(bit_q); + + if (val == State::Sx) + continue; + + log("FF init value for cell %s (%s): %s = %c\n", log_id(cell), log_id(cell->type), + log_signal(bit_q), val != State::S0 ? '1' : '0'); + // Initval is the same as the reset state. Matches hardware, nowt more to do + if (val == resetState) { + handled_initbits.insert(bit_q); + continue; + } + + if (GetSize(sig_lsr) >= 1 && sig_lsr[0] != State::S0) { + std::string srmode = "LSR_OVER_CE"; + if (cell->hasParam("\\SRMODE")) + srmode = cell->getParam("\\SRMODE").decode_string(); + if (srmode == "ASYNC") { + log("Async reset value %c for FF cell %s inconsistent with init value %c.\n", + resetState != State::S0 ? '1' : '0', log_id(cell), val != State::S0 ? '1' : '0'); + } else { + SigBit bit_lsr = sigmap(sig_lsr[0]); + Wire *new_bit_d = module->addWire(NEW_ID); + if (resetState == State::S0) { + module->addAndnotGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } else { + module->addOrGate(NEW_ID, bit_d, bit_lsr, new_bit_d); + } + + cell->setPort("\\DI", new_bit_d); + cell->setPort("\\LSR", State::S0); + + if(cell->hasPort("\\CE")) { + std::string cemux = "CE"; + if (cell->hasParam("\\CEMUX")) + cemux = cell->getParam("\\CEMUX").decode_string(); + SigSpec sig_ce = cell->getPort("\\CE"); + if (GetSize(sig_ce) >= 1) { + SigBit bit_ce = sigmap(sig_ce[0]); + Wire *new_bit_ce = module->addWire(NEW_ID); + if (cemux == "INV") + module->addAndnotGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + else + module->addOrGate(NEW_ID, bit_ce, bit_lsr, new_bit_ce); + cell->setPort("\\CE", new_bit_ce); + } + } + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } else { + cell->setParam("\\REGSET", val != State::S0 ? Const("SET") : Const("RESET")); + handled_initbits.insert(bit_q); + } + } + + for (auto wire : init_wires) + { + if (wire->attributes.count("\\init") == 0) + continue; + + SigSpec wirebits = sigmap(wire); + Const &initval = wire->attributes.at("\\init"); + bool remove_attribute = true; + + for (int i = 0; i < GetSize(wirebits) && i < GetSize(initval); i++) { + if (handled_initbits.count(wirebits[i])) + initval[i] = State::Sx; + else if (initval[i] != State::Sx) + remove_attribute = false; + } + + if (remove_attribute) + wire->attributes.erase("\\init"); + } + } + } +} Ecp5FfinitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index bda03d251..4b889d672 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -255,10 +255,7 @@ struct SynthEcp5Pass : public ScriptPass run("techmap -D NO_LUT -map +/ecp5/cells_map.v"); run("opt_expr -mux_undef"); run("simplemap"); - // TODO -#if 0 run("ecp5_ffinit"); -#endif } if (check_label("map_luts")) diff --git a/techlibs/gowin/arith_map.v b/techlibs/gowin/arith_map.v index 25e789e4a..e15de6423 100644 --- a/techlibs/gowin/arith_map.v +++ b/techlibs/gowin/arith_map.v @@ -25,24 +25,24 @@ module _80_gw1n_alu(A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; - + input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; output [Y_WIDTH-1:0] X, Y; - + input CI, BI; output [Y_WIDTH-1:0] CO; - + wire _TECHMAP_FAIL_ = Y_WIDTH <= 2; - + 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)); - + wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; wire [Y_WIDTH-1:0] C = {CO, CI}; - + genvar i; generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice ALU #(.ALU_MODE(32'b0)) diff --git a/techlibs/gowin/synth_gowin.cc b/techlibs/gowin/synth_gowin.cc index 96128a680..9a3fcdbb6 100644 --- a/techlibs/gowin/synth_gowin.cc +++ b/techlibs/gowin/synth_gowin.cc @@ -111,7 +111,7 @@ struct SynthGowinPass : public ScriptPass if (args[argidx] == "-noflatten") { flatten = false; continue; - } + } break; } extra_args(args, argidx, design); diff --git a/techlibs/greenpak4/cells_map.v b/techlibs/greenpak4/cells_map.v index b971a51fa..51c85183d 100644 --- a/techlibs/greenpak4/cells_map.v +++ b/techlibs/greenpak4/cells_map.v @@ -112,14 +112,14 @@ module GP_OBUFT(input IN, input OE, output OUT); endmodule module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; + parameter WIDTH = 0; + parameter LUT = 0; - input [WIDTH-1:0] A; - output Y; + input [WIDTH-1:0] A; + output Y; - generate - if (WIDTH == 1) begin + generate + if (WIDTH == 1) begin if(LUT == 2'b01) begin GP_INV _TECHMAP_REPLACE_ (.OUT(Y), .IN(A[0]) ); end @@ -127,22 +127,22 @@ module \$lut (A, Y); GP_2LUT #(.INIT({2'b00, LUT})) _TECHMAP_REPLACE_ (.OUT(Y), .IN0(A[0]), .IN1(1'b0)); end - end else - if (WIDTH == 2) begin - GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1])); - end else - if (WIDTH == 3) begin - GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1]), .IN2(A[2])); - end else - if (WIDTH == 4) begin - GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), - .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3])); - end else begin - wire _TECHMAP_FAIL_ = 1; - end - endgenerate + end else + if (WIDTH == 2) begin + GP_2LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1])); + end else + if (WIDTH == 3) begin + GP_3LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1]), .IN2(A[2])); + end else + if (WIDTH == 4) begin + GP_4LUT #(.INIT(LUT)) _TECHMAP_REPLACE_ (.OUT(Y), + .IN0(A[0]), .IN1(A[1]), .IN2(A[2]), .IN3(A[3])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate endmodule module \$__COUNT_ (CE, CLK, OUT, POUT, RST, UP); diff --git a/techlibs/ice40/Makefile.inc b/techlibs/ice40/Makefile.inc index 2750901c8..723b59d6f 100644 --- a/techlibs/ice40/Makefile.inc +++ b/techlibs/ice40/Makefile.inc @@ -1,5 +1,6 @@ OBJS += techlibs/ice40/synth_ice40.o +OBJS += techlibs/ice40/ice40_braminit.o OBJS += techlibs/ice40/ice40_ffssr.o OBJS += techlibs/ice40/ice40_ffinit.o OBJS += techlibs/ice40/ice40_opt.o diff --git a/techlibs/ice40/brams_map.v b/techlibs/ice40/brams_map.v index 19a61d73b..ad3bccd21 100644 --- a/techlibs/ice40/brams_map.v +++ b/techlibs/ice40/brams_map.v @@ -7,8 +7,8 @@ module \$__ICE40_RAM4K ( input [10:0] WADDR, input [15:0] MASK, WDATA ); - parameter integer READ_MODE = 0; - parameter integer WRITE_MODE = 0; + parameter [1:0] READ_MODE = 0; + parameter [1:0] WRITE_MODE = 0; parameter [0:0] NEGCLK_R = 0; parameter [0:0] NEGCLK_W = 0; diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 2041693cc..62a28364b 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -326,6 +326,8 @@ module SB_RAM40_4K ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + `ifndef BLACKBOX wire [15:0] WMASK_I; wire [15:0] RMASK_I; @@ -408,43 +410,27 @@ module SB_RAM40_4K ( reg [15:0] memory [0:255]; initial begin - for (i=0; i<16; i=i+1) begin -`ifdef YOSYS - memory[ 0*16 + i] <= INIT_0[16*i +: 16]; - memory[ 1*16 + i] <= INIT_1[16*i +: 16]; - memory[ 2*16 + i] <= INIT_2[16*i +: 16]; - memory[ 3*16 + i] <= INIT_3[16*i +: 16]; - memory[ 4*16 + i] <= INIT_4[16*i +: 16]; - memory[ 5*16 + i] <= INIT_5[16*i +: 16]; - memory[ 6*16 + i] <= INIT_6[16*i +: 16]; - memory[ 7*16 + i] <= INIT_7[16*i +: 16]; - memory[ 8*16 + i] <= INIT_8[16*i +: 16]; - memory[ 9*16 + i] <= INIT_9[16*i +: 16]; - memory[10*16 + i] <= INIT_A[16*i +: 16]; - memory[11*16 + i] <= INIT_B[16*i +: 16]; - memory[12*16 + i] <= INIT_C[16*i +: 16]; - memory[13*16 + i] <= INIT_D[16*i +: 16]; - memory[14*16 + i] <= INIT_E[16*i +: 16]; - memory[15*16 + i] <= INIT_F[16*i +: 16]; -`else - memory[ 0*16 + i] = INIT_0[16*i +: 16]; - memory[ 1*16 + i] = INIT_1[16*i +: 16]; - memory[ 2*16 + i] = INIT_2[16*i +: 16]; - memory[ 3*16 + i] = INIT_3[16*i +: 16]; - memory[ 4*16 + i] = INIT_4[16*i +: 16]; - memory[ 5*16 + i] = INIT_5[16*i +: 16]; - memory[ 6*16 + i] = INIT_6[16*i +: 16]; - memory[ 7*16 + i] = INIT_7[16*i +: 16]; - memory[ 8*16 + i] = INIT_8[16*i +: 16]; - memory[ 9*16 + i] = INIT_9[16*i +: 16]; - memory[10*16 + i] = INIT_A[16*i +: 16]; - memory[11*16 + i] = INIT_B[16*i +: 16]; - memory[12*16 + i] = INIT_C[16*i +: 16]; - memory[13*16 + i] = INIT_D[16*i +: 16]; - memory[14*16 + i] = INIT_E[16*i +: 16]; - memory[15*16 + i] = INIT_F[16*i +: 16]; -`endif - end + if (INIT_FILE != "") + $readmemh(INIT_FILE, memory); + else + for (i=0; i<16; i=i+1) begin + memory[ 0*16 + i] = INIT_0[16*i +: 16]; + memory[ 1*16 + i] = INIT_1[16*i +: 16]; + memory[ 2*16 + i] = INIT_2[16*i +: 16]; + memory[ 3*16 + i] = INIT_3[16*i +: 16]; + memory[ 4*16 + i] = INIT_4[16*i +: 16]; + memory[ 5*16 + i] = INIT_5[16*i +: 16]; + memory[ 6*16 + i] = INIT_6[16*i +: 16]; + memory[ 7*16 + i] = INIT_7[16*i +: 16]; + memory[ 8*16 + i] = INIT_8[16*i +: 16]; + memory[ 9*16 + i] = INIT_9[16*i +: 16]; + memory[10*16 + i] = INIT_A[16*i +: 16]; + memory[11*16 + i] = INIT_B[16*i +: 16]; + memory[12*16 + i] = INIT_C[16*i +: 16]; + memory[13*16 + i] = INIT_D[16*i +: 16]; + memory[14*16 + i] = INIT_E[16*i +: 16]; + memory[15*16 + i] = INIT_F[16*i +: 16]; + end end always @(posedge WCLK) begin @@ -504,6 +490,8 @@ module SB_RAM40_4KNR ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -522,7 +510,8 @@ module SB_RAM40_4KNR ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), @@ -566,6 +555,8 @@ module SB_RAM40_4KNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -584,7 +575,8 @@ module SB_RAM40_4KNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (RCLK ), @@ -628,6 +620,8 @@ module SB_RAM40_4KNRNW ( parameter INIT_E = 256'h0000000000000000000000000000000000000000000000000000000000000000; parameter INIT_F = 256'h0000000000000000000000000000000000000000000000000000000000000000; + parameter INIT_FILE = ""; + SB_RAM40_4K #( .WRITE_MODE(WRITE_MODE), .READ_MODE (READ_MODE ), @@ -646,7 +640,8 @@ module SB_RAM40_4KNRNW ( .INIT_C (INIT_C ), .INIT_D (INIT_D ), .INIT_E (INIT_E ), - .INIT_F (INIT_F ) + .INIT_F (INIT_F ), + .INIT_FILE (INIT_FILE ) ) RAM ( .RDATA(RDATA), .RCLK (~RCLKN), diff --git a/techlibs/ice40/ice40_braminit.cc b/techlibs/ice40/ice40_braminit.cc new file mode 100644 index 000000000..4fa6b0792 --- /dev/null +++ b/techlibs/ice40/ice40_braminit.cc @@ -0,0 +1,159 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +#include "kernel/yosys.h" +#include "kernel/sigtools.h" +#include <stdlib.h> +#include <stdio.h> +#include <bitset> + +USING_YOSYS_NAMESPACE +PRIVATE_NAMESPACE_BEGIN + +static void run_ice40_braminit(Module *module) +{ + for (auto cell : module->selected_cells()) + { + uint16_t mem[256]; + + /* Only consider cells we're interested in */ + if (cell->type != "\\SB_RAM40_4K" && + cell->type != "\\SB_RAM40_4KNR" && + cell->type != "\\SB_RAM40_4KNW" && + cell->type != "\\SB_RAM40_4KNRNW") + continue; + if (!cell->hasParam("\\INIT_FILE")) + continue; + std::string init_file = cell->getParam("\\INIT_FILE").decode_string(); + cell->unsetParam("\\INIT_FILE"); + if (init_file == "") + continue; + + /* Open file */ + log("Processing %s : %s\n", RTLIL::id2cstr(cell->name), init_file.c_str()); + + std::ifstream f; + f.open(init_file.c_str()); + if (f.fail()) { + log("Can not open file `%s`.\n", init_file.c_str()); + continue; + } + + /* Defaults to 0 */ + memset(mem, 0x00, sizeof(mem)); + + /* Process each line */ + bool in_comment = false; + int cursor = 0; + + while (!f.eof()) + { + std::string line, token; + std::getline(f, line); + + for (int i = 0; i < GetSize(line); i++) + { + if (in_comment && line.substr(i, 2) == "*/") { + line[i] = ' '; + line[i+1] = ' '; + in_comment = false; + continue; + } + if (!in_comment && line.substr(i, 2) == "/*") + in_comment = true; + if (in_comment) + line[i] = ' '; + } + + while (1) + { + bool set_cursor = false; + long value; + + token = next_token(line, " \t\r\n"); + if (token.empty() || token.substr(0, 2) == "//") + break; + + if (token[0] == '@') { + token = token.substr(1); + set_cursor = true; + } + + const char *nptr = token.c_str(); + char *endptr; + value = strtol(nptr, &endptr, 16); + if (!*nptr || *endptr) { + log("Can not parse %s `%s` for %s.\n", + set_cursor ? "address" : "value", + nptr, token.c_str() + ); + continue; + } + + if (set_cursor) + cursor = value; + else if (cursor >= 0 && cursor < 256) + mem[cursor++] = value; + else + log("Attempt to initialize non existent address %d\n", cursor); + } + } + + /* Set attributes */ + const char *hex = "0123456789ABCDEF"; + for (int i=0; i<16; i++) { + std::string val = ""; + for (int j=15; j>=0; j--) + val += std::bitset<16>(mem[i*16+j]).to_string(); + cell->setParam("\\INIT_" + std::string(1, hex[i]), RTLIL::Const::from_string(val)); + } + } +} + +struct Ice40BRAMInitPass : public Pass { + Ice40BRAMInitPass() : Pass("ice40_braminit", "iCE40: perform SB_RAM40_4K initialization from file") { } + void help() YS_OVERRIDE + { + // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| + log("\n"); + log(" ice40_braminit\n"); + log("\n"); + log("This command processes all SB_RAM40_4K blocks with a non-empty INIT_FILE\n"); + log("parameter and converts it into the required INIT_x attributes\n"); + log("\n"); + } + void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE + { + log_header(design, "Executing ICE40_BRAMINIT pass.\n"); + + size_t argidx; + for (argidx = 1; argidx < args.size(); argidx++) { + // if (args[argidx] == "-???") { + // continue; + // } + break; + } + extra_args(args, argidx, design); + + for (auto module : design->selected_modules()) + run_ice40_braminit(module); + } +} Ice40BRAMInitPass; + +PRIVATE_NAMESPACE_END diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 34501b335..8899bfcc4 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -257,6 +257,7 @@ struct SynthIce40Pass : public ScriptPass { run("memory_bram -rules +/ice40/brams.txt"); run("techmap -map +/ice40/brams_map.v"); + run("ice40_braminit"); } if (check_label("map")) diff --git a/techlibs/intel/cycloneive/arith_map.v b/techlibs/intel/cycloneive/arith_map.v index b3a11272b..49e36aa25 100644 --- a/techlibs/intel/cycloneive/arith_map.v +++ b/techlibs/intel/cycloneive/arith_map.v @@ -32,7 +32,7 @@ module fa wire VCC; assign VCC = 1'b1; - + cycloneiv_lcell_comb gen_sum_0 (.combout(sum_x), .dataa(a_c), .datab(b_c), @@ -40,7 +40,7 @@ module fa .datad(VCC)); defparam syn__05_.lut_mask = 16'b1001011010010110; defparam syn__05_.sum_lutc_input = "datac"; - + cycloneiv_lcell_comb gen_cout_0 (.combout(cout_t), .dataa(cin_c), .datab(b_c), @@ -48,11 +48,11 @@ module fa .datad(VCC)); defparam syn__06_.lut_mask = 16'b1110000011100000; defparam syn__06_.sum_lutc_input = "datac"; - + endmodule // fa module f_stage(); - + endmodule // f_stage module f_end(); @@ -88,7 +88,7 @@ module _80_cycloneive_alu (A, B, CI, BI, X, Y, CO); .cin_c(C[0]), .cout_t(C0[1]), .sum_x(Y[0])); - + genvar i; generate for (i = 1; i < Y_WIDTH; i = i + 1) begin:slice cycloneive_lcell_comb #(.lut_mask(16'b0101_1010_0101_0000), .sum_lutc_input("cin")) arith_cell (.combout(Y[i]), .cout(CO[i]), .dataa(BB[i]), .datab(1'b1), .datac(1'b1), .datad(1'b1), .cin(C[i])); diff --git a/techlibs/intel/cyclonev/cells_map.v b/techlibs/intel/cyclonev/cells_map.v index bd60d4e17..f8d142bc9 100644 --- a/techlibs/intel/cyclonev/cells_map.v +++ b/techlibs/intel/cyclonev/cells_map.v @@ -76,7 +76,7 @@ module \$lut (A, Y); wire VCC; wire GND; assign {VCC,GND} = {1'b1,1'b0}; - + generate if (WIDTH == 1) begin assign Y = ~A[0]; // Not need to spend 1 logic cell for such an easy function @@ -151,7 +151,7 @@ module \$lut (A, Y); TODO: There's not a just 7-input function on Cyclone V, see the following note: **Extended LUT Mode** Use extended LUT mode to implement a specific set of 7-input functions. The set must - be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. + be a 2-to-1 multiplexer fed by two arbitrary 5-input functions sharing four inputs. [source](Device Interfaces and Integration Basics for Cyclone V Devices). end*/ else diff --git a/techlibs/sf2/cells_map.v b/techlibs/sf2/cells_map.v index 5b8888294..6ad7807d2 100644 --- a/techlibs/sf2/cells_map.v +++ b/techlibs/sf2/cells_map.v @@ -1,40 +1,54 @@ -// module \$_DFF_N_ (input D, C, output Q); SB_DFFN _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C)); endmodule +module \$_DFF_N_ (input D, C, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule module \$_DFF_P_ (input D, C, output Q); - SLE _TECHMAP_REPLACE_ ( - .D(D), - .CLK(C), - .EN(1'b1), - .ALn(1'b1), - .ADn(1'b1), - .SLn(1'b1), - .SD(1'b0), - .LAT(1'b0), - .Q(Q) - ); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(1'b1), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_NP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(!C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PN1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP0_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b1), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); +endmodule + +module \$_DFF_PP1_ (input D, C, R, output Q); + SLE _TECHMAP_REPLACE_ (.D(D), .CLK(C), .EN(1'b1), .ALn(!R), .ADn(1'b0), .SLn(1'b1), .SD(1'b0), .LAT(1'b0), .Q(Q)); endmodule // module \$_DFFE_NN_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule // module \$_DFFE_PN_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(!E)); endmodule -// +// // module \$_DFFE_NP_ (input D, C, E, output Q); SB_DFFNE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule // module \$_DFFE_PP_ (input D, C, E, output Q); SB_DFFE _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E)); endmodule -// -// module \$_DFF_NN0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -// module \$_DFF_NN1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -// module \$_DFF_PN0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(!R)); endmodule -// module \$_DFF_PN1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(!R)); endmodule -// -// module \$_DFF_NP0_ (input D, C, R, output Q); SB_DFFNR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -// module \$_DFF_NP1_ (input D, C, R, output Q); SB_DFFNS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -// module \$_DFF_PP0_ (input D, C, R, output Q); SB_DFFR _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .R(R)); endmodule -// module \$_DFF_PP1_ (input D, C, R, output Q); SB_DFFS _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .S(R)); endmodule -// +// // module \$__DFFE_NN0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_NN1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule // module \$__DFFE_PN0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(!R)); endmodule // module \$__DFFE_PN1 (input D, C, E, R, output Q); SB_DFFES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(!R)); endmodule -// +// // module \$__DFFE_NP0 (input D, C, E, R, output Q); SB_DFFNER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule // module \$__DFFE_NP1 (input D, C, E, R, output Q); SB_DFFNES _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .S(R)); endmodule // module \$__DFFE_PP0 (input D, C, E, R, output Q); SB_DFFER _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .E(E), .R(R)); endmodule diff --git a/techlibs/sf2/cells_sim.v b/techlibs/sf2/cells_sim.v index f967068af..c62748b11 100644 --- a/techlibs/sf2/cells_sim.v +++ b/techlibs/sf2/cells_sim.v @@ -1,3 +1,114 @@ +// https://coredocs.s3.amazonaws.com/Libero/12_0_0/Tool/sf2_mlg.pdf + +module ADD2 ( + + input A, B, + output Y +); + assign Y = A & B; +endmodule + +module ADD3 ( + input A, B, C, + output Y +); + assign Y = A & B & C; +endmodule + +module ADD4 ( + input A, B, C, D, + output Y +); + assign Y = A & B & C & D; +endmodule + +module CFG1 ( + output Y, + input A +); + parameter [1:0] INIT = 2'h0; + assign Y = INIT >> A; +endmodule + +module CFG2 ( + output Y, + input A, + input B +); + parameter [3:0] INIT = 4'h0; + assign Y = INIT >> {B, A}; +endmodule + +module CFG3 ( + output Y, + input A, + input B, + input C +); + parameter [7:0] INIT = 8'h0; + assign Y = INIT >> {C, B, A}; +endmodule + +module CFG4 ( + output Y, + input A, + input B, + input C, + input D +); + parameter [15:0] INIT = 16'h0; + assign Y = INIT >> {D, C, B, A}; +endmodule + +module BUFF ( + input A, + output Y +); + assign Y = A; +endmodule + +module BUFD ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module CLKINT_PRESERVE ( + input A, + output Y +); + assign Y = A; +endmodule + +module GCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + +module RCLKINT ( + input A, + output Y +); + assign Y = A; +endmodule + +module RGCLKINT ( + input A, EN, + output Y +); + assign Y = A & EN; +endmodule + module SLE ( output Q, input ADn, @@ -36,44 +147,151 @@ module SLE ( assign Q = LAT ? q_latch : q_ff; endmodule -module CFG1 ( - output Y, - input A +// module AR1 +// module FCEND_BUFF +// module FCINIT_BUFF +// module FLASH_FREEZE +// module OSCILLATOR +// module SYSRESET +// module SYSCTRL_RESET_STATUS +// module LIVE_PROBE_FB +// module GCLKBUF +// module GCLKBUF_DIFF +// module GCLKBIBUF +// module DFN1 +// module DFN1C0 +// module DFN1E1 +// module DFN1E1C0 +// module DFN1E1P0 +// module DFN1P0 +// module DLN1 +// module DLN1C0 +// module DLN1P0 + +module INV ( + input A, + output Y ); - parameter [1:0] INIT = 2'h0; - assign Y = INIT >> A; + assign Y = !A; endmodule -module CFG2 ( - output Y, +module INVD ( input A, - input B + output Y ); - parameter [3:0] INIT = 4'h0; - assign Y = INIT >> {B, A}; + assign Y = !A; endmodule -module CFG3 ( - output Y, - input A, - input B, - input C +module MX2 ( + input A, B, S, + output Y ); - parameter [7:0] INIT = 8'h0; - assign Y = INIT >> {C, B, A}; + assign Y = S ? B : A; endmodule -module CFG4 ( - output Y, - input A, - input B, - input C, - input D +module MX4 ( + input D0, D1, D2, D3, S0, S1, + output Y ); - parameter [15:0] INIT = 16'h0; - assign Y = INIT >> {D, C, B, A}; + assign Y = S1 ? (S0 ? D3 : D2) : (S0 ? D1 : D0); +endmodule + +module NAND2 ( + input A, B, + output Y +); + assign Y = !(A & B); +endmodule + +module NAND3 ( + input A, B, C, + output Y +); + assign Y = !(A & B & C); +endmodule + +module NAND4 ( + input A, B, C, D, + output Y +); + assign Y = !(A & B & C & D); +endmodule + +module NOR2 ( + input A, B, + output Y +); + assign Y = !(A | B); +endmodule + +module NOR3 ( + input A, B, C, + output Y +); + assign Y = !(A | B | C); +endmodule + +module NOR4 ( + input A, B, C, D, + output Y +); + assign Y = !(A | B | C | D); endmodule +module OR2 ( + input A, B, + output Y +); + assign Y = A | B; +endmodule + +module OR3 ( + input A, B, C, + output Y +); + assign Y = A | B | C; +endmodule + +module OR4 ( + input A, B, C, D, + output Y +); + assign Y = A | B | C | D; +endmodule + +module XOR2 ( + input A, B, + output Y +); + assign Y = A ^ B; +endmodule + +module XOR3 ( + input A, B, C, + output Y +); + assign Y = A ^ B ^ C; +endmodule + +module XOR4 ( + input A, B, C, D, + output Y +); + assign Y = A ^ B ^ C ^ D; +endmodule + +module XOR8 ( + input A, B, C, D, E, F, G, H, + output Y +); + assign Y = A ^ B ^ C ^ D ^ E ^ F ^ G ^ H; +endmodule + +// module UJTAG +// module BIBUF +// module BIBUF_DIFF +// module CLKBIBUF + module CLKBUF ( input PAD, output Y @@ -81,6 +299,8 @@ module CLKBUF ( assign Y = PAD; endmodule +// module CLKBUF_DIFF + module INBUF ( input PAD, output Y @@ -88,9 +308,20 @@ module INBUF ( assign Y = PAD; endmodule +// module INBUF_DIFF + module OUTBUF ( input D, output PAD ); assign PAD = D; endmodule + +// module OUTBUF_DIFF +// module TRIBUFF +// module TRIBUFF_DIFF +// module DDR_IN +// module DDR_OUT +// module RAM1K18 +// module RAM64x18 +// module MACC diff --git a/techlibs/sf2/sf2_iobs.cc b/techlibs/sf2/sf2_iobs.cc index 27141430c..3d43332e2 100644 --- a/techlibs/sf2/sf2_iobs.cc +++ b/techlibs/sf2/sf2_iobs.cc @@ -23,6 +23,136 @@ USING_YOSYS_NAMESPACE PRIVATE_NAMESPACE_BEGIN +static void handle_iobufs(Module *module, bool clkbuf_mode) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + pool<SigBit> handled_io_bits; + dict<SigBit, SigBit> rewrite_bits; + vector<pair<Cell*, SigBit>> pad_bits; + + for (auto cell : module->cells()) + { + if (clkbuf_mode && cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\INBUF", "\\OUTBUF", "\\TRIBUFF", "\\BIBUF", "\\CLKBUF", "\\CLKBIBUF", + "\\INBUF_DIFF", "\\OUTBUF_DIFF", "\\BIBUFF_DIFF", "\\TRIBUFF_DIFF", "\\CLKBUF_DIFF", + "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF")) { + for (auto bit : sigmap(cell->getPort("\\PAD"))) + handled_io_bits.insert(bit); + } + } + + for (auto wire : vector<Wire*>(module->wires())) + { + if (!wire->port_input && !wire->port_output) + continue; + + for (int index = 0; index < GetSize(wire); index++) + { + SigBit bit(wire, index); + SigBit canonical_bit = sigmap(bit); + + if (handled_io_bits.count(canonical_bit)) + continue; + + if (wire->port_input && wire->port_output) + log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); + + IdString buf_type, buf_port; + + if (wire->port_output) { + buf_type = "\\OUTBUF"; + buf_port = "\\D"; + } else if (clkbuf_mode && clk_bits.count(canonical_bit)) { + buf_type = "\\CLKBUF"; + buf_port = "\\Y"; + } else { + buf_type = "\\INBUF"; + buf_port = "\\Y"; + } + + Cell *c = module->addCell(NEW_ID, buf_type); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort(buf_port, new_bit); + pad_bits.push_back(make_pair(c, bit)); + rewrite_bits[canonical_bit] = new_bit; + + log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + } + } + + auto rewrite_function = [&](SigSpec &s) { + for (auto &bit : s) { + SigBit canonical_bit = sigmap(bit); + if (rewrite_bits.count(canonical_bit)) + bit = rewrite_bits.at(canonical_bit); + } + }; + + module->rewrite_sigspecs(rewrite_function); + + for (auto &it : pad_bits) + it.first->setPort("\\PAD", it.second); +} + +static void handle_clkint(Module *module) +{ + SigMap sigmap(module); + + pool<SigBit> clk_bits; + vector<SigBit> handled_clk_bits; + + for (auto cell : module->cells()) + { + if (cell->type == "\\SLE") { + for (auto bit : sigmap(cell->getPort("\\CLK"))) + clk_bits.insert(bit); + } + if (cell->type.in("\\CLKBUF", "\\CLKBIBUF", "\\CLKBUF_DIFF", "\\GCLKBUF", "\\GCLKBUF_DIFF", "\\GCLKBIBUF", + "\\CLKINT", "\\CLKINT_PRESERVE", "\\GCLKINT", "\\RCLKINT", "\\RGCLKINT")) { + for (auto bit : sigmap(cell->getPort("\\Y"))) + handled_clk_bits.push_back(bit); + } + } + + for (auto bit : handled_clk_bits) + clk_bits.erase(bit); + + for (auto cell : vector<Cell*>(module->cells())) + for (auto &conn : cell->connections()) + { + if (!cell->output(conn.first)) + continue; + + SigSpec sig = conn.second; + bool did_something = false; + + for (auto &bit : sig) { + SigBit canonical_bit = sigmap(bit); + if (clk_bits.count(canonical_bit)) { + Cell *c = module->addCell(NEW_ID, "\\CLKINT"); + SigBit new_bit = module->addWire(NEW_ID); + c->setPort("\\A", new_bit); + c->setPort("\\Y", bit); + log("Added %s cell %s for clock signal %s.\n", log_id(c->type), log_id(c), log_signal(bit)); + clk_bits.erase(canonical_bit); + did_something = true; + bit = new_bit; + } + } + + if (did_something) + cell->setPort(conn.first, sig); + } + + for (auto bit : clk_bits) + log_error("Failed to insert CLKINT for clock signal %s.\n", log_signal(bit)); +} + struct Sf2IobsPass : public Pass { Sf2IobsPass() : Pass("sf2_iobs", "SF2: insert IO buffers") { } void help() YS_OVERRIDE @@ -31,20 +161,25 @@ struct Sf2IobsPass : public Pass { log("\n"); log(" sf2_iobs [options] [selection]\n"); log("\n"); - log("Add SF2 I/O buffers to top module IOs as needed.\n"); + log("Add SF2 I/O buffers and global buffers to top module as needed.\n"); + log("\n"); + log(" -clkbuf\n"); + log(" Insert PAD->global_net clock buffers\n"); log("\n"); } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE { + bool clkbuf_mode = false; + log_header(design, "Executing sf2_iobs pass (insert IO buffers).\n"); size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) { - // if (args[argidx] == "-singleton") { - // singleton_mode = true; - // continue; - // } + if (args[argidx] == "-clkbuf") { + clkbuf_mode = true; + continue; + } break; } extra_args(args, argidx, design); @@ -54,76 +189,8 @@ struct Sf2IobsPass : public Pass { if (module == nullptr) log_cmd_error("No top module found.\n"); - SigMap sigmap(module); - - pool<SigBit> clk_bits; - pool<SigBit> handled_io_bits; - dict<SigBit, SigBit> rewrite_bits; - vector<pair<Cell*, SigBit>> pad_bits; - - for (auto cell : module->cells()) - { - if (cell->type == "\\SLE") { - for (auto bit : sigmap(cell->getPort("\\CLK"))) - clk_bits.insert(bit); - } - if (cell->type.in("\\INBUF", "\\OUTBUF", "\\CLKBUF")) { - for (auto bit : sigmap(cell->getPort("\\PAD"))) - handled_io_bits.insert(bit); - } - } - - for (auto wire : vector<Wire*>(module->wires())) - { - if (!wire->port_input && !wire->port_output) - continue; - - for (int index = 0; index < GetSize(wire); index++) - { - SigBit bit(wire, index); - SigBit canonical_bit = sigmap(bit); - - if (handled_io_bits.count(canonical_bit)) - continue; - - if (wire->port_input && wire->port_output) - log_error("Failed to add buffer for inout port bit %s.\n", log_signal(bit)); - - IdString buf_type, buf_port; - - if (wire->port_output) { - buf_type = "\\OUTBUF"; - buf_port = "\\D"; - } else if (clk_bits.count(canonical_bit)) { - buf_type = "\\CLKBUF"; - buf_port = "\\Y"; - } else { - buf_type = "\\INBUF"; - buf_port = "\\Y"; - } - - Cell *c = module->addCell(NEW_ID, buf_type); - SigBit new_bit = module->addWire(NEW_ID); - c->setPort(buf_port, new_bit); - pad_bits.push_back(make_pair(c, bit)); - rewrite_bits[canonical_bit] = new_bit; - - log("Added %s cell %s for port bit %s.\n", log_id(c->type), log_id(c), log_signal(bit)); - } - } - - auto rewrite_function = [&](SigSpec &s) { - for (auto &bit : s) { - SigBit canonical_bit = sigmap(bit); - if (rewrite_bits.count(canonical_bit)) - bit = rewrite_bits.at(canonical_bit); - } - }; - - module->rewrite_sigspecs(rewrite_function); - - for (auto &it : pad_bits) - it.first->setPort("\\PAD", it.second); + handle_iobufs(module, clkbuf_mode); + handle_clkint(module); } } Sf2IobsPass; diff --git a/techlibs/sf2/synth_sf2.cc b/techlibs/sf2/synth_sf2.cc index bdc20456d..0924df7a6 100644 --- a/techlibs/sf2/synth_sf2.cc +++ b/techlibs/sf2/synth_sf2.cc @@ -63,6 +63,9 @@ struct SynthSf2Pass : public ScriptPass log(" -noiobs\n"); log(" run synthesis in \"block mode\", i.e. do not insert IO buffers\n"); log("\n"); + log(" -clkbuf\n"); + log(" insert direct PAD->global_net buffers\n"); + log("\n"); log(" -retime\n"); log(" run 'abc' with -dff option\n"); log("\n"); @@ -73,7 +76,7 @@ struct SynthSf2Pass : public ScriptPass } string top_opt, edif_file, vlog_file, json_file; - bool flatten, retime, iobs; + bool flatten, retime, iobs, clkbuf; void clear_flags() YS_OVERRIDE { @@ -84,6 +87,7 @@ struct SynthSf2Pass : public ScriptPass flatten = true; retime = false; iobs = true; + clkbuf = false; } void execute(std::vector<std::string> args, RTLIL::Design *design) YS_OVERRIDE @@ -130,6 +134,10 @@ struct SynthSf2Pass : public ScriptPass iobs = false; continue; } + if (args[argidx] == "-clkbuf") { + clkbuf = true; + continue; + } break; } extra_args(args, argidx, design); @@ -201,8 +209,10 @@ struct SynthSf2Pass : public ScriptPass if (check_label("map_iobs")) { - if (iobs || help_mode) - run("sf2_iobs", "(unless -noiobs)"); + if (help_mode) + run("sf2_iobs [-clkbuf]", "(unless -noiobs)"); + else if (iobs) + run(clkbuf ? "sf2_iobs -clkbuf" : "sf2_iobs"); run("clean"); } diff --git a/techlibs/xilinx/Makefile.inc b/techlibs/xilinx/Makefile.inc index 887ea27d9..d68f03bb4 100644 --- a/techlibs/xilinx/Makefile.inc +++ b/techlibs/xilinx/Makefile.inc @@ -28,7 +28,8 @@ $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/brams_bb.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams.txt)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/drams_map.v)) $(eval $(call add_share_file,share/xilinx,techlibs/xilinx/arith_map.v)) -$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut2lut.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/ff_map.v)) +$(eval $(call add_share_file,share/xilinx,techlibs/xilinx/lut_map.v)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_36.vh)) $(eval $(call add_gen_share_file,share/xilinx,techlibs/xilinx/brams_init_32.vh)) diff --git a/techlibs/xilinx/arith_map.v b/techlibs/xilinx/arith_map.v index 03719659b..09a5f07e8 100644 --- a/techlibs/xilinx/arith_map.v +++ b/techlibs/xilinx/arith_map.v @@ -17,6 +17,9 @@ * */ +// ============================================================================ +// LCU + (* techmap_celltype = "$lcu" *) module _80_xilinx_lcu (P, G, CI, CO); parameter WIDTH = 2; @@ -28,10 +31,78 @@ module _80_xilinx_lcu (P, G, CI, CO); wire _TECHMAP_FAIL_ = WIDTH <= 2; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, P & ~G}; + wire [MAX_WIDTH-1:0] C = CO; + + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]), + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (G [((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]), + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + wire [WIDTH-1:0] C = {CO, CI}; wire [WIDTH-1:0] S = P & ~G; - genvar i; generate for (i = 0; i < WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), @@ -40,8 +111,28 @@ module _80_xilinx_lcu (P, G, CI, CO); .O(CO[i]) ); end endgenerate + +`else + + wire [WIDTH-1:0] C = {CO, CI}; + wire [WIDTH-1:0] S = P & ~G; + + generate for (i = 0; i < WIDTH; i = i + 1) begin:slice + MUXCY muxcy ( + .CI(C[i]), + .DI(G[i]), + .S(S[i]), + .O(CO[i]) + ); + end endgenerate +`endif + endmodule + +// ============================================================================ +// ALU + (* techmap_celltype = "$alu" *) module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_SIGNED = 0; @@ -49,6 +140,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); parameter A_WIDTH = 1; parameter B_WIDTH = 1; parameter Y_WIDTH = 1; + parameter _TECHMAP_CONSTVAL_CI_ = 0; + parameter _TECHMAP_CONSTMSK_CI_ = 0; input [A_WIDTH-1:0] A; input [B_WIDTH-1:0] B; @@ -66,16 +159,189 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); wire [Y_WIDTH-1:0] AA = A_buf; wire [Y_WIDTH-1:0] BB = BI ? ~B_buf : B_buf; - wire [Y_WIDTH-1:0] P = AA ^ BB; - wire [Y_WIDTH-1:0] G = AA & BB; - wire [Y_WIDTH-1:0] C = {CO, CI}; - wire [Y_WIDTH-1:0] S = P & ~G; + genvar i; + +`ifdef _CLB_CARRY + + localparam CARRY4_COUNT = (Y_WIDTH + 3) / 4; + localparam MAX_WIDTH = CARRY4_COUNT * 4; + localparam PAD_WIDTH = MAX_WIDTH - Y_WIDTH; + + wire [MAX_WIDTH-1:0] S = {{PAD_WIDTH{1'b0}}, AA ^ BB}; + wire [MAX_WIDTH-1:0] DI = {{PAD_WIDTH{1'b0}}, AA & BB}; + + wire [MAX_WIDTH-1:0] C = CO; genvar i; + generate for (i = 0; i < CARRY4_COUNT; i = i + 1) begin:slice + + // Partially occupied CARRY4 + if ((i+1)*4 > Y_WIDTH) begin + + // First one + if (i == 0) begin + CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_part + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_part + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[(Y_WIDTH - 1):i*4]), + .S (S [(Y_WIDTH - 1):i*4]), + .O (Y [(Y_WIDTH - 1):i*4]), + .CO (CO[(Y_WIDTH - 1):i*4]) + ); + end + + // Fully occupied CARRY4 + end else begin + + // First one + if (i == 0) begin + CARRY4 #(.IS_INITIALIZED(1'd1)) carry4_1st_full + ( + .CYINIT(CI), + .CI (1'd0), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + // Another one + end else begin + CARRY4 carry4_full + ( + .CYINIT(1'd0), + .CI (C [i*4 - 1]), + .DI (DI[((i+1)*4 - 1):i*4]), + .S (S [((i+1)*4 - 1):i*4]), + .O (Y [((i+1)*4 - 1):i*4]), + .CO (CO[((i+1)*4 - 1):i*4]) + ); + end + + end + + end endgenerate + +`elsif _EXPLICIT_CARRY + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire CINIT; + // Carry chain. + // + // VPR requires that the carry chain never hit the fabric. The CO input + // to this techmap is the carry outputs for synthesis, e.g. might hit the + // fabric. + // + // So we maintain two wire sets, CO_CHAIN is the carry that is for VPR, + // e.g. off fabric dedicated chain. CO is the carry outputs that are + // available to the fabric. + wire [Y_WIDTH-1:0] CO_CHAIN; + wire [Y_WIDTH-1:0] C = {CO_CHAIN, CINIT}; + + // If carry chain is being initialized to a constant, techmap the constant + // source. Otherwise techmap the fabric source. + generate for (i = 0; i < 1; i = i + 1) begin:slice + CARRY0 #(.CYINIT_FABRIC(1)) carry( + .CI_INIT(CI), + .DI(DI[0]), + .S(S[0]), + .CO_CHAIN(CO_CHAIN[0]), + .CO_FABRIC(CO[0]), + .O(Y[0]) + ); + end endgenerate + + generate for (i = 1; i < Y_WIDTH-1; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + else + begin + CARRY carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .CO_FABRIC(CO[i]), + .O(Y[i]) + ); + end + end endgenerate + + generate for (i = Y_WIDTH-1; i < Y_WIDTH; i = i + 1) begin:slice + if(i % 4 == 0) begin + CARRY0 top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + else + begin + CARRY top_of_carry ( + .CI(C[i]), + .DI(DI[i]), + .S(S[i]), + .CO_CHAIN(CO_CHAIN[i]), + .O(Y[i]) + ); + end + // Turns out CO_FABRIC and O both use [ABCD]MUX, so provide + // a non-congested path to output the top of the carry chain. + // Registering the output of the CARRY block would solve this, but not + // all designs do that. + if((i+1) % 4 == 0) begin + CARRY0 carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + else + begin + CARRY carry_output ( + .CI(CO_CHAIN[i]), + .DI(0), + .S(0), + .O(CO[i]) + ); + end + end endgenerate + +`else + + wire [Y_WIDTH-1:0] S = AA ^ BB; + wire [Y_WIDTH-1:0] DI = AA & BB; + + wire [Y_WIDTH-1:0] C = {CO, CI}; + generate for (i = 0; i < Y_WIDTH; i = i + 1) begin:slice MUXCY muxcy ( .CI(C[i]), - .DI(G[i]), + .DI(DI[i]), .S(S[i]), .O(CO[i]) ); @@ -86,6 +352,8 @@ module _80_xilinx_alu (A, B, CI, BI, X, Y, CO); ); end endgenerate - assign X = P; +`endif + + assign X = S; endmodule diff --git a/techlibs/xilinx/cells_map.v b/techlibs/xilinx/cells_map.v index 0ace369d1..0c5c5a26f 100644 --- a/techlibs/xilinx/cells_map.v +++ b/techlibs/xilinx/cells_map.v @@ -1,89 +1,21 @@ - -module \$_DFF_N_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule -module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule - -module \$_DFFE_NP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule -module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_R_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule - -module \$_DFF_NN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_NP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule -module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_CLR_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(R)); endmodule - -module \$_DFF_NN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_NP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|1), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|1)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule -module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0), .IS_C_INVERTED(|0), .IS_D_INVERTED(|0), .IS_PRE_INVERTED(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(R)); endmodule - -`ifndef NO_LUT -module \$lut (A, Y); - parameter WIDTH = 0; - parameter LUT = 0; - - input [WIDTH-1:0] A; - output Y; - - generate - if (WIDTH == 1) begin - LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0])); - end else - if (WIDTH == 2) begin - LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1])); - end else - if (WIDTH == 3) begin - LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2])); - end else - if (WIDTH == 4) begin - LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3])); - end else - if (WIDTH == 5) begin - LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4])); - end else - if (WIDTH == 6) begin - LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - end else - if (WIDTH == 7) begin - wire T0, T1; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); - end else - if (WIDTH == 8) begin - wire T0, T1, T2, T3, T4, T5; - LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), - .I0(A[0]), .I1(A[1]), .I2(A[2]), - .I3(A[3]), .I4(A[4]), .I5(A[5])); - MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); - MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); - MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); - end else begin - wire _TECHMAP_FAIL_ = 1; - end - endgenerate -endmodule -`endif +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ module \$__SHREG_ (input C, input D, input E, output Q); parameter DEPTH = 0; diff --git a/techlibs/xilinx/cells_sim.v b/techlibs/xilinx/cells_sim.v index 68f678385..c756115f6 100644 --- a/techlibs/xilinx/cells_sim.v +++ b/techlibs/xilinx/cells_sim.v @@ -1,3 +1,21 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ // See Xilinx UG953 and UG474 for a description of the cell types below. // http://www.xilinx.com/support/documentation/user_guides/ug474_7Series_CLB.pdf @@ -104,6 +122,29 @@ module CARRY4(output [3:0] CO, O, input CI, CYINIT, input [3:0] DI, S); assign CO[3] = S[3] ? CO[2] : DI[3]; endmodule +`ifdef _EXPLICIT_CARRY + +module CARRY0(output CO_CHAIN, CO_FABRIC, O, input CI, CI_INIT, DI, S); + parameter CYINIT_FABRIC = 0; + wire CI_COMBINE; + if(CYINIT_FABRIC) begin + assign CI_COMBINE = CI_INIT; + end else begin + assign CI_COMBINE = CI; + end + assign CO_CHAIN = S ? CI_COMBINE : DI; + assign CO_FABRIC = S ? CI_COMBINE : DI; + assign O = S ^ CI_COMBINE; +endmodule + +module CARRY(output CO_CHAIN, CO_FABRIC, O, input CI, DI, S); + assign CO_CHAIN = S ? CI : DI; + assign CO_FABRIC = S ? CI : DI; + assign O = S ^ CI; +endmodule + +`endif + module FDRE (output reg Q, input C, CE, D, R); parameter [0:0] INIT = 1'b0; parameter [0:0] IS_C_INVERTED = 1'b0; @@ -156,6 +197,30 @@ module FDPE (output reg Q, input C, CE, D, PRE); endcase endgenerate endmodule +module FDRE_1 (output reg Q, input C, CE, D, R); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C) if (R) Q <= 1'b0; else if(CE) Q <= D; +endmodule + +module FDSE_1 (output reg Q, input C, CE, D, S); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C) if (S) Q <= 1'b1; else if(CE) Q <= D; +endmodule + +module FDCE_1 (output reg Q, input C, CE, D, CLR); + parameter [0:0] INIT = 1'b0; + initial Q <= INIT; + always @(negedge C, posedge CLR) if (CLR) Q <= 1'b0; else if (CE) Q <= D; +endmodule + +module FDPE_1 (output reg Q, input C, CE, D, PRE); + parameter [0:0] INIT = 1'b1; + initial Q <= INIT; + always @(negedge C, posedge PRE) if (PRE) Q <= 1'b1; else if (CE) Q <= D; +endmodule + module RAM64X1D ( output DPO, SPO, input D, WCLK, WE, diff --git a/techlibs/xilinx/cells_xtra.sh b/techlibs/xilinx/cells_xtra.sh index 8cc90d1f2..46ababdea 100644 --- a/techlibs/xilinx/cells_xtra.sh +++ b/techlibs/xilinx/cells_xtra.sh @@ -115,7 +115,7 @@ function xtract_cell_decl() xtract_cell_decl PS7 xtract_cell_decl PULLDOWN xtract_cell_decl PULLUP - # xtract_cell_decl RAM128X1D + xtract_cell_decl RAM128X1D xtract_cell_decl RAM128X1S xtract_cell_decl RAM256X1S xtract_cell_decl RAM32M @@ -124,7 +124,7 @@ function xtract_cell_decl() xtract_cell_decl RAM32X1S_1 xtract_cell_decl RAM32X2S xtract_cell_decl RAM64M - # xtract_cell_decl RAM64X1D + xtract_cell_decl RAM64X1D xtract_cell_decl RAM64X1S xtract_cell_decl RAM64X1S_1 xtract_cell_decl RAM64X2S diff --git a/techlibs/xilinx/cells_xtra.v b/techlibs/xilinx/cells_xtra.v index 21db6a6bd..6adad35ae 100644 --- a/techlibs/xilinx/cells_xtra.v +++ b/techlibs/xilinx/cells_xtra.v @@ -3695,6 +3695,25 @@ module RAM128X1S (...); input A0, A1, A2, A3, A4, A5, A6, D, WCLK, WE; endmodule +module RAM128X1D ( + output DPO, SPO, + input D, WCLK, WE, + input [6:0] A, DPRA +); + parameter [127:0] INIT = 128'bx; + parameter IS_WCLK_INVERTED = 0; +endmodule + +module RAM64X1D ( + output DPO, SPO, + input D, WCLK, WE, + input A0, A1, A2, A3, A4, A5, + input DPRA0, DPRA1, DPRA2, DPRA3, DPRA4, DPRA5 +); + parameter [63:0] INIT = 64'bx; + parameter IS_WCLK_INVERTED = 0; +endmodule + module RAM256X1S (...); parameter [255:0] INIT = 256'h0; parameter [0:0] IS_WCLK_INVERTED = 1'b0; diff --git a/techlibs/xilinx/ff_map.v b/techlibs/xilinx/ff_map.v new file mode 100644 index 000000000..13beaa6ae --- /dev/null +++ b/techlibs/xilinx/ff_map.v @@ -0,0 +1,42 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +// ============================================================================ +// FF mapping + +`ifndef _NO_FFS + +module \$_DFF_N_ (input D, C, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule +module \$_DFF_P_ (input D, C, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .R(1'b0)); endmodule + +module \$_DFFE_NP_ (input D, C, E, output Q); FDRE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule +module \$_DFFE_PP_ (input D, C, E, output Q); FDRE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(E), .R(1'b0)); endmodule + +module \$_DFF_NN0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_NP0_ (input D, C, R, output Q); FDCE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule +module \$_DFF_PN0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR(!R)); endmodule +module \$_DFF_PP0_ (input D, C, R, output Q); FDCE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .CLR( R)); endmodule + +module \$_DFF_NN1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_NP1_ (input D, C, R, output Q); FDPE_1 #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule +module \$_DFF_PN1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE(!R)); endmodule +module \$_DFF_PP1_ (input D, C, R, output Q); FDPE #(.INIT(|0)) _TECHMAP_REPLACE_ (.D(D), .Q(Q), .C(C), .CE(1'b1), .PRE( R)); endmodule + +`endif + diff --git a/techlibs/xilinx/lut2lut.v b/techlibs/xilinx/lut2lut.v deleted file mode 100644 index 061ad2041..000000000 --- a/techlibs/xilinx/lut2lut.v +++ /dev/null @@ -1,65 +0,0 @@ -module LUT1(output O, input I0); - parameter [1:0] INIT = 0; - \$lut #( - .WIDTH(1), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A(I0), - .Y(O) - ); -endmodule - -module LUT2(output O, input I0, I1); - parameter [3:0] INIT = 0; - \$lut #( - .WIDTH(2), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I1, I0}), - .Y(O) - ); -endmodule - -module LUT3(output O, input I0, I1, I2); - parameter [7:0] INIT = 0; - \$lut #( - .WIDTH(3), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT4(output O, input I0, I1, I2, I3); - parameter [15:0] INIT = 0; - \$lut #( - .WIDTH(4), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT5(output O, input I0, I1, I2, I3, I4); - parameter [31:0] INIT = 0; - \$lut #( - .WIDTH(5), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule - -module LUT6(output O, input I0, I1, I2, I3, I4, I5); - parameter [63:0] INIT = 0; - \$lut #( - .WIDTH(6), - .LUT(INIT) - ) _TECHMAP_REPLACE_ ( - .A({I5, I4, I3, I2, I1, I0}), - .Y(O) - ); -endmodule diff --git a/techlibs/xilinx/lut_map.v b/techlibs/xilinx/lut_map.v new file mode 100644 index 000000000..d07c59dee --- /dev/null +++ b/techlibs/xilinx/lut_map.v @@ -0,0 +1,94 @@ +/* + * yosys -- Yosys Open SYnthesis Suite + * + * Copyright (C) 2012 Clifford Wolf <clifford@clifford.at> + * + * 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. + * + */ + +// ============================================================================ +// LUT mapping + +`ifndef _NO_LUTS + +module \$lut (A, Y); + parameter WIDTH = 0; + parameter LUT = 0; + + input [WIDTH-1:0] A; + output Y; + + generate + if (WIDTH == 1) begin + LUT1 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0])); + end else + if (WIDTH == 2) begin + LUT2 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1])); + end else + if (WIDTH == 3) begin + LUT3 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2])); + end else + if (WIDTH == 4) begin + LUT4 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3])); + end else + if (WIDTH == 5) begin + LUT5 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4])); + end else + if (WIDTH == 6) begin + LUT6 #(.INIT(LUT)) _TECHMAP_REPLACE_ (.O(Y), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + end else + if (WIDTH == 7) begin + wire T0, T1; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(Y), .I0(T0), .I1(T1), .S(A[6])); + end else + if (WIDTH == 8) begin + wire T0, T1, T2, T3, T4, T5; + LUT6 #(.INIT(LUT[63:0])) fpga_lut_0 (.O(T0), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[127:64])) fpga_lut_1 (.O(T1), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[191:128])) fpga_lut_2 (.O(T2), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + LUT6 #(.INIT(LUT[255:192])) fpga_lut_3 (.O(T3), + .I0(A[0]), .I1(A[1]), .I2(A[2]), + .I3(A[3]), .I4(A[4]), .I5(A[5])); + MUXF7 fpga_mux_0 (.O(T4), .I0(T0), .I1(T1), .S(A[6])); + MUXF7 fpga_mux_1 (.O(T5), .I0(T2), .I1(T3), .S(A[6])); + MUXF8 fpga_mux_2 (.O(Y), .I0(T4), .I1(T5), .S(A[7])); + end else begin + wire _TECHMAP_FAIL_ = 1; + end + endgenerate +endmodule + +`endif + diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 71b468e38..169f3b7ce 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -63,6 +63,12 @@ struct SynthXilinxPass : public Pass log(" generate an output netlist (and BLIF file) suitable for VPR\n"); log(" (this feature is experimental and incomplete)\n"); log("\n"); + log(" -nobram\n"); + log(" disable infering of block rams\n"); + log("\n"); + log(" -nodram\n"); + log(" disable infering of distributed rams\n"); + log("\n"); log(" -run <from_label>:<to_label>\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"); @@ -90,11 +96,11 @@ struct SynthXilinxPass : public Pass log(" coarse:\n"); log(" synth -run coarse\n"); log("\n"); - log(" bram:\n"); + log(" bram: (only executed when '-nobram' is not given)\n"); log(" memory_bram -rules +/xilinx/brams.txt\n"); log(" techmap -map +/xilinx/brams_map.v\n"); log("\n"); - log(" dram:\n"); + log(" dram: (only executed when '-nodram' is not given)\n"); log(" memory_bram -rules +/xilinx/drams.txt\n"); log(" techmap -map +/xilinx/drams_map.v\n"); log("\n"); @@ -106,15 +112,17 @@ struct SynthXilinxPass : public Pass log(" opt -full\n"); log(" techmap -map +/techmap.v -map +/xilinx/arith_map.v\n"); log(" shregmap -init_msb_first -params -enpol any_or_none\n"); + log(" techmap -map +/xilinx/ff_map.v\n"); log(" opt -fast\n"); log("\n"); log(" map_luts:\n"); - log(" abc -luts 2:2,3,6:5,10,20 [-dff]\n"); + log(" abc -luts 2:2,3,6:5,10,20 [-dff] (without '-vpr' only!)\n"); + log(" abc -lut 5 [-dff] (with '-vpr' only!)\n"); log(" clean\n"); log("\n"); log(" map_cells:\n"); - log(" techmap -map +/xilinx/cells_map.v (with -D NO_LUT in vpr mode)\n"); - log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT\n"); + log(" techmap -map +/xilinx/cells_map.v\n"); + log(" dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT\n"); log(" clean\n"); log("\n"); log(" check:\n"); @@ -138,6 +146,8 @@ struct SynthXilinxPass : public Pass bool flatten = false; bool retime = false; bool vpr = false; + bool nobram = false; + bool nodram = false; size_t argidx; for (argidx = 1; argidx < args.size(); argidx++) @@ -174,6 +184,14 @@ struct SynthXilinxPass : public Pass vpr = true; continue; } + if (args[argidx] == "-nobram") { + nobram = true; + continue; + } + if (args[argidx] == "-nodram") { + nodram = true; + continue; + } break; } extra_args(args, argidx, design); @@ -188,9 +206,18 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "begin")) { - Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); + if (vpr) { + Pass::call(design, "read_verilog -lib -D_EXPLICIT_CARRY +/xilinx/cells_sim.v"); + } else { + Pass::call(design, "read_verilog -lib +/xilinx/cells_sim.v"); + } + Pass::call(design, "read_verilog -lib +/xilinx/cells_xtra.v"); - Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); + + if (!nobram) { + Pass::call(design, "read_verilog -lib +/xilinx/brams_bb.v"); + } + Pass::call(design, stringf("hierarchy -check %s", top_opt.c_str())); } @@ -207,14 +234,18 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "bram")) { - Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); - Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + if (!nobram) { + Pass::call(design, "memory_bram -rules +/xilinx/brams.txt"); + Pass::call(design, "techmap -map +/xilinx/brams_map.v"); + } } if (check_label(active, run_from, run_to, "dram")) { - Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); - Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + if (!nodram) { + Pass::call(design, "memory_bram -rules +/xilinx/drams.txt"); + Pass::call(design, "techmap -map +/xilinx/drams_map.v"); + } } if (check_label(active, run_from, run_to, "fine")) @@ -224,8 +255,16 @@ struct SynthXilinxPass : public Pass Pass::call(design, "dffsr2dff"); Pass::call(design, "dff2dffe"); Pass::call(design, "opt -full"); - Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + + if (vpr) { + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v -D _EXPLICIT_CARRY"); + } else { + Pass::call(design, "techmap -map +/techmap.v -map +/xilinx/arith_map.v"); + } + Pass::call(design, "shregmap -init_msb_first -params -enpol any_or_none"); + Pass::call(design, "techmap -map +/xilinx/ff_map.v"); + Pass::call(design, "hierarchy -check"); Pass::call(design, "opt -fast"); } @@ -233,14 +272,13 @@ struct SynthXilinxPass : public Pass { Pass::call(design, "abc -luts 2:2,3,6:5,10,20" + string(retime ? " -dff" : "")); Pass::call(design, "clean"); + Pass::call(design, "techmap -map +/xilinx/lut_map.v"); } if (check_label(active, run_from, run_to, "map_cells")) { Pass::call(design, "techmap -map +/xilinx/cells_map.v"); - if (vpr) - Pass::call(design, "techmap -map +/xilinx/lut2lut.v"); - Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT"); + Pass::call(design, "dffinit -ff FDRE Q INIT -ff FDCE Q INIT -ff FDPE Q INIT -ff FDSE Q INIT"); Pass::call(design, "clean"); } @@ -254,7 +292,7 @@ struct SynthXilinxPass : public Pass if (check_label(active, run_from, run_to, "edif")) { if (!edif_file.empty()) - Pass::call(design, stringf("write_edif %s", edif_file.c_str())); + Pass::call(design, stringf("write_edif -pvector bra %s", edif_file.c_str())); } if (check_label(active, run_from, run_to, "blif")) { diff --git a/tests/asicworld/xfirrtl b/tests/asicworld/xfirrtl index c782a2bd6..08bf4ccd8 100644 --- a/tests/asicworld/xfirrtl +++ b/tests/asicworld/xfirrtl @@ -6,7 +6,6 @@ code_hdl_models_d_latch_gates.v combinational loop code_hdl_models_dff_async_reset.v $adff code_hdl_models_tff_async_reset.v $adff code_hdl_models_uart.v $adff -code_specman_switch_fabric.v subfield assignment (bits() <= ...) code_tidbits_asyn_reset.v $adff code_tidbits_reg_seq_example.v $adff code_verilog_tutorial_always_example.v empty module diff --git a/tests/simple/task_func.v b/tests/simple/task_func.v index fa50c1d5c..f6e902f63 100644 --- a/tests/simple/task_func.v +++ b/tests/simple/task_func.v @@ -120,3 +120,22 @@ module task_func_test04(input [7:0] in, output [7:0] out1, out2, out3, out4); assign out3 = test3(in); assign out4 = test4(in); endmodule + +// ------------------------------------------------------------------- + +// https://github.com/YosysHQ/yosys/issues/857 +module task_func_test05(data_in,data_out,clk); + output reg data_out; + input data_in; + input clk; + + task myTask; + output out; + input in; + out = in; + endtask + + always @(posedge clk) begin + myTask(data_out,data_in); + end +endmodule diff --git a/tests/simple/xfirrtl b/tests/simple/xfirrtl index 00e89b389..50d693513 100644 --- a/tests/simple/xfirrtl +++ b/tests/simple/xfirrtl @@ -1,6 +1,7 @@ # This file contains the names of verilog files to exclude from verilog to FIRRTL regression tests due to known failures. arraycells.v inst id[0] of dff_different_styles.v +dff_init.v Initial value not supported generate.v combinational loop hierdefparam.v inst id[0] of i2c_master_tests.v $adff @@ -12,7 +13,6 @@ multiplier.v inst id[0] of muxtree.v drops modules omsp_dbg_uart.v $adff operators.v $pow -paramods.v subfield assignment (bits() <= ...) partsel.v drops modules process.v drops modules realexpr.v drops modules diff --git a/tests/tools/autotest.sh b/tests/tools/autotest.sh index 218edf931..84e62e011 100755 --- a/tests/tools/autotest.sh +++ b/tests/tools/autotest.sh @@ -8,7 +8,7 @@ verbose=false keeprunning=false makejmode=false frontend="verilog" -backend_opts="-noattr -noexpr" +backend_opts="-noattr -noexpr -siminit" autotb_opts="" include_opts="" xinclude_opts="" @@ -49,7 +49,7 @@ while getopts xmGl:wkjvref:s:p:n:S:I:-: opt; do r) backend_opts="$backend_opts -norename" ;; e) - backend_opts="$( echo " $backend_opts " | sed 's, -noexpr ,,; s,^ ,,; s, $,,;'; )" ;; + backend_opts="$( echo " $backend_opts " | sed 's, -noexpr , ,; s,^ ,,; s, $,,;'; )" ;; f) frontend="$OPTARG" ;; s) @@ -175,7 +175,7 @@ do if [ -n "$firrtl2verilog" ]; then if test -z "$xfirrtl" || ! grep "$fn" "$xfirrtl" ; then "$toolsdir"/../../yosys -b "firrtl" -o ${bn}_ref.fir -f "$frontend $include_opts" -p "prep -nordff; proc; opt; memory; opt; fsm; opt -full -fine; pmuxtree" ${bn}_ref.v - $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v -X verilog + $firrtl2verilog -i ${bn}_ref.fir -o ${bn}_ref.fir.v test_passes -f "$frontend $include_opts" -p "hierarchy; proc; opt; memory; opt; fsm; opt -full -fine" ${bn}_ref.fir.v fi fi |