diff options
34 files changed, 494 insertions, 165 deletions
@@ -82,7 +82,6 @@ YOSYS_SRC := $(dir $(firstword $(MAKEFILE_LIST))) VPATH := $(YOSYS_SRC) CXXFLAGS := $(CXXFLAGS) -Wall -Wextra -ggdb -I. -I"$(YOSYS_SRC)" -MD -D_YOSYS_ -fPIC -I$(PREFIX)/include -LDFLAGS := $(LDFLAGS) -L$(LIBDIR) LDLIBS := $(LDLIBS) -lstdc++ -lm PLUGIN_LDFLAGS := @@ -136,7 +135,7 @@ bumpversion: # is just a symlink to your actual ABC working directory, as 'make mrproper' # will remove the 'abc' directory and you do not want to accidentally # delete your work on ABC.. -ABCREV = d14acd8 +ABCREV = fd2c9b1 ABCPULL = 1 ABCURL ?= https://github.com/YosysHQ/abc ABCMKARGS = CC="$(CXX)" CXX="$(CXX)" ABC_USE_LIBSTDCXX=1 @@ -281,13 +280,13 @@ yosys.html: misc/yosys.html else ifeq ($(CONFIG),wasi) ifeq ($(WASI_SDK),) -CXX = clang++ +CXX = clang LD = clang++ AR = llvm-ar RANLIB = llvm-ranlib WASIFLAGS := -target wasm32-wasi --sysroot $(WASI_SYSROOT) $(WASIFLAGS) else -CXX = $(WASI_SDK)/bin/clang++ +CXX = $(WASI_SDK)/bin/clang LD = $(WASI_SDK)/bin/clang++ AR = $(WASI_SDK)/bin/ar RANLIB = $(WASI_SDK)/bin/ranlib @@ -371,7 +370,7 @@ BOOST_PYTHON_LIB ?= $(shell \ endif ifeq ($(BOOST_PYTHON_LIB),) -$(error BOOST_PYTHON_LIB could not be detected. Please define manualy) +$(error BOOST_PYTHON_LIB could not be detected. Please define manually) endif ifeq ($(OS), Darwin) @@ -722,7 +721,7 @@ ifneq ($(ABCREV),default) test $(ABCPULL) -ne 0 || { echo 'REEBE: NOP abg hc gb qngr naq NOPCHYY frg gb 0 va Znxrsvyr!' | tr 'A-Za-z' 'N-ZA-Mn-za-m'; exit 1; }; \ echo "Pulling ABC from $(ABCURL):"; set -x; \ test -d abc || git clone $(ABCURL) abc; \ - cd abc && $(MAKE) DEP= clean && git fetch origin master && git checkout $(ABCREV); \ + cd abc && $(MAKE) DEP= clean && git fetch $(ABCURL) && git checkout $(ABCREV); \ fi endif $(Q) rm -f abc/abc-[0-9a-f]* @@ -281,6 +281,9 @@ Verilog Attributes and non-standard features temporary variable within an always block. This is mostly used internally by Yosys to synthesize Verilog functions and access arrays. +- The ``nowrshmsk`` attribute on a register prohibits the generation of + shift-and-mask type circuits for writing to bit slices of that register. + - The ``onehot`` attribute on wires mark them as one-hot state register. This is used for example for memory port sharing and set by the fsm_map pass. diff --git a/backends/cxxrtl/cxxrtl.cc b/backends/cxxrtl/cxxrtl.cc index e7711962f..f3ed3f623 100644 --- a/backends/cxxrtl/cxxrtl.cc +++ b/backends/cxxrtl/cxxrtl.cc @@ -1943,13 +1943,13 @@ struct CxxrtlWorker { case RTLIL::STa: break; + case RTLIL::STg: + log_cmd_error("Global clock is not supported.\n"); + // Handling of init-type sync rules is delegated to the `proc_init` pass, so we can use the wire // attribute regardless of input. case RTLIL::STi: log_assert(false); - - case RTLIL::STg: - log_cmd_error("Global clock is not supported.\n"); } } @@ -2346,16 +2346,22 @@ struct CxxrtlBackend : public Backend { case 6: worker.max_opt_level = true; worker.run_proc_flatten = true; + YS_FALLTHROUGH case 5: worker.run_opt_clean_purge = true; + YS_FALLTHROUGH case 4: worker.localize_public = true; + YS_FALLTHROUGH case 3: worker.elide_public = true; + YS_FALLTHROUGH case 2: worker.localize_internal = true; + YS_FALLTHROUGH case 1: worker.elide_internal = true; + YS_FALLTHROUGH case 0: break; default: diff --git a/backends/firrtl/firrtl.cc b/backends/firrtl/firrtl.cc index 40d05a036..f6dae1d8c 100644 --- a/backends/firrtl/firrtl.cc +++ b/backends/firrtl/firrtl.cc @@ -343,7 +343,7 @@ struct FirrtlWorker 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)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_OUT: sourceExpr = firstName; sinkExpr = secondExpr; @@ -351,7 +351,7 @@ struct FirrtlWorker 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)); - /* FALLTHRU */ + YS_FALLTHROUGH case FD_IN: sourceExpr = secondExpr; sinkExpr = firstName; diff --git a/frontends/ast/ast.cc b/frontends/ast/ast.cc index 6a9af3f57..689fa9fb4 100644 --- a/frontends/ast/ast.cc +++ b/frontends/ast/ast.cc @@ -94,6 +94,7 @@ std::string AST::type2str(AstNodeType type) X(AST_TO_BITS) X(AST_TO_SIGNED) X(AST_TO_UNSIGNED) + X(AST_SELFSZ) X(AST_CONCAT) X(AST_REPLICATE) X(AST_BIT_NOT) @@ -110,6 +111,8 @@ std::string AST::type2str(AstNodeType type) X(AST_SHIFT_RIGHT) X(AST_SHIFT_SLEFT) X(AST_SHIFT_SRIGHT) + X(AST_SHIFTX) + X(AST_SHIFT) X(AST_LT) X(AST_LE) X(AST_EQ) @@ -615,6 +618,7 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_POS: txt = "+"; } if (0) { case AST_NEG: txt = "-"; } if (0) { case AST_LOGIC_NOT: txt = "!"; } + if (0) { case AST_SELFSZ: txt = "@selfsz@"; } fprintf(f, "%s(", txt.c_str()); children[0]->dumpVlog(f, ""); fprintf(f, ")"); @@ -628,6 +632,8 @@ void AstNode::dumpVlog(FILE *f, std::string indent) const if (0) { case AST_SHIFT_RIGHT: txt = ">>"; } if (0) { case AST_SHIFT_SLEFT: txt = "<<<"; } if (0) { case AST_SHIFT_SRIGHT: txt = ">>>"; } + if (0) { case AST_SHIFTX: txt = "@shiftx@"; } + if (0) { case AST_SHIFT: txt = "@shift@"; } if (0) { case AST_LT: txt = "<"; } if (0) { case AST_LE: txt = "<="; } if (0) { case AST_EQ: txt = "=="; } diff --git a/frontends/ast/ast.h b/frontends/ast/ast.h index 3f6329112..8932108e3 100644 --- a/frontends/ast/ast.h +++ b/frontends/ast/ast.h @@ -75,6 +75,7 @@ namespace AST AST_TO_BITS, AST_TO_SIGNED, AST_TO_UNSIGNED, + AST_SELFSZ, AST_CONCAT, AST_REPLICATE, AST_BIT_NOT, @@ -91,6 +92,8 @@ namespace AST AST_SHIFT_RIGHT, AST_SHIFT_SLEFT, AST_SHIFT_SRIGHT, + AST_SHIFTX, + AST_SHIFT, AST_LT, AST_LE, AST_EQ, diff --git a/frontends/ast/genrtlil.cc b/frontends/ast/genrtlil.cc index 5894c7b3c..d4e9baa5f 100644 --- a/frontends/ast/genrtlil.cc +++ b/frontends/ast/genrtlil.cc @@ -171,7 +171,7 @@ struct AST_INTERNAL::LookaheadRewriter for (auto c : node->id2ast->children) wire->children.push_back(c->clone()); wire->str = stringf("$lookahead%s$%d", node->str.c_str(), autoidx++); - wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire->is_logic = true; while (wire->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire); @@ -809,6 +809,11 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun sign_hint = false; break; + case AST_SELFSZ: + sub_width_hint = 0; + children.at(0)->detectSignWidthWorker(sub_width_hint, sign_hint); + break; + case AST_CONCAT: for (auto child : children) { sub_width_hint = 0; @@ -856,6 +861,8 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun case AST_SHIFT_RIGHT: case AST_SHIFT_SLEFT: case AST_SHIFT_SRIGHT: + case AST_SHIFTX: + case AST_SHIFT: case AST_POW: children[0]->detectSignWidthWorker(width_hint, sign_hint, found_real); break; @@ -923,7 +930,7 @@ void AstNode::detectSignWidthWorker(int &width_hint, bool &sign_hint, bool *foun } break; } - /* fall through */ + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: @@ -1019,7 +1026,7 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (GetSize(children) >= 1 && children[0]->type == AST_CONSTANT) { current_module->parameter_default_values[str] = children[0]->asParaConst(); } - /* fall through */ + YS_FALLTHROUGH case AST_LOCALPARAM: if (flag_pwires) { @@ -1205,13 +1212,18 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) AstNode *fake_ast = new AstNode(AST_NONE, clone(), children[0]->children.size() >= 2 ? children[0]->children[1]->clone() : children[0]->children[0]->clone()); fake_ast->children[0]->delete_children(); - RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(); + + int fake_ast_width = 0; + bool fake_ast_sign = true; + fake_ast->children[1]->detectSignWidth(fake_ast_width, fake_ast_sign); + RTLIL::SigSpec shift_val = fake_ast->children[1]->genRTLIL(fake_ast_width, fake_ast_sign); + if (id2ast->range_right != 0) { - shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, shift_val, id2ast->range_right, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (id2ast->range_swapped) { - shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast->children[1]->is_signed); + shift_val = current_module->Sub(NEW_ID, RTLIL::SigSpec(source_width - width), shift_val, fake_ast_sign); fake_ast->children[1]->is_signed = true; } if (GetSize(shift_val) >= 32) @@ -1265,7 +1277,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) // just pass thru the signal. the parent will evaluate the is_signed property and interpret the SigSpec accordingly case AST_TO_SIGNED: - case AST_TO_UNSIGNED: { + case AST_TO_UNSIGNED: + case AST_SELFSZ: { RTLIL::SigSpec sig = children[0]->genRTLIL(); if (sig.size() < width_hint) sig.extend_u0(width_hint, sign_hint); @@ -1356,6 +1369,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) if (0) { case AST_SHIFT_RIGHT: type_name = ID($shr); } if (0) { case AST_SHIFT_SLEFT: type_name = ID($sshl); } if (0) { case AST_SHIFT_SRIGHT: type_name = ID($sshr); } + if (0) { case AST_SHIFTX: type_name = ID($shiftx); } + if (0) { case AST_SHIFT: type_name = ID($shift); } { if (width_hint < 0) detectSignWidth(width_hint, sign_hint); @@ -1807,7 +1822,8 @@ RTLIL::SigSpec AstNode::genRTLIL(int width_hint, bool sign_hint) is_signed = sign_hint; return SigSpec(wire); } - } /* fall through */ + } + YS_FALLTHROUGH // everything should have been handled above -> print error if not. default: diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index cdb7e91e0..f629df387 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -91,7 +91,7 @@ std::string AstNode::process_format_str(const std::string &sformat, int next_arg case 'D': if (got_len) goto unsupported_format; - /* fall through */ + YS_FALLTHROUGH case 'x': case 'X': if (next_arg >= GetSize(children)) @@ -608,6 +608,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, case AST_TO_BITS: case AST_TO_SIGNED: case AST_TO_UNSIGNED: + case AST_SELFSZ: case AST_CONCAT: case AST_REPLICATE: case AST_REDUCE_AND: @@ -920,11 +921,11 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; - attributes["\\wiretype"] = mkconst_str(resolved_type->str); + attributes[ID::wiretype] = mkconst_str(resolved_type->str); //check if enum - if (templ->attributes.count("\\enum_type")){ + if (templ->attributes.count(ID::enum_type)){ //get reference to enum node: - std::string enum_type = templ->attributes["\\enum_type"]->str.c_str(); + const std::string &enum_type = templ->attributes[ID::enum_type]->str; // log("enum_type=%s (count=%lu)\n", enum_type.c_str(), current_scope.count(enum_type)); // log("current scope:\n"); // for (auto &it : current_scope) @@ -972,7 +973,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, RTLIL::Const val = enum_item->children[0]->bitsAsConst(width, is_signed); enum_item_str.append(val.as_string()); //set attribute for available val to enum item name mappings - attributes[enum_item_str.c_str()] = mkconst_str(enum_item->str); + attributes[enum_item_str] = mkconst_str(enum_item->str); } } @@ -1021,7 +1022,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, range_swapped = templ->range_swapped; range_left = templ->range_left; range_right = templ->range_right; - attributes["\\wiretype"] = mkconst_str(resolved_type->str); + attributes[ID::wiretype] = mkconst_str(resolved_type->str); for (auto template_child : templ->children) children.push_back(template_child->clone()); did_something = true; @@ -1739,8 +1740,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *node = children_list[1]; if (op_type != AST_POS) - for (size_t i = 2; i < children_list.size(); i++) + for (size_t i = 2; i < children_list.size(); i++) { node = new AstNode(op_type, node, children_list[i]); + node->location = location; + } if (invert_results) node = new AstNode(AST_BIT_NOT, node); @@ -1786,7 +1789,18 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, result_width = abs(int(left_at_zero_ast->integer - right_at_zero_ast->integer)) + 1; } - if (0) + bool use_case_method = false; + + if (children[0]->id2ast->attributes.count(ID::nowrshmsk)) { + AstNode *node = children[0]->id2ast->attributes.at(ID::nowrshmsk); + while (node->simplify(true, false, false, stage, -1, false, false)) { } + if (node->type != AST_CONSTANT) + log_file_error(filename, location.first_line, "Non-constant value for `nowrshmsk' attribute on `%s'!\n", children[0]->id2ast->str.c_str()); + if (node->asAttrConst().as_bool()) + use_case_method = true; + } + + if (use_case_method) { // big case block @@ -1794,10 +1808,10 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, newNode = new AstNode(AST_CASE, shift_expr); for (int i = 0; i < source_width; i++) { int start_bit = children[0]->id2ast->range_right + i; + int end_bit = std::min(start_bit+result_width,source_width) - 1; AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true)); AstNode *lvalue = children[0]->clone(); lvalue->delete_children(); - int end_bit = std::min(start_bit+result_width,source_width) - 1; lvalue->children.push_back(new AstNode(AST_RANGE, mkconst_int(end_bit, true), mkconst_int(start_bit, true))); cond->children.push_back(new AstNode(AST_BLOCK, new AstNode(type, lvalue, children[1]->clone()))); @@ -1810,14 +1824,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); - wire_mask->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_mask->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_mask->is_logic = true; while (wire_mask->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_mask); AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true))); wire_data->str = stringf("$bitselwrite$data$%s:%d$%d", filename.c_str(), location.first_line, autoidx++); - wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false); + wire_data->attributes[ID::nosync] = AstNode::mkconst_int(1, false); wire_data->is_logic = true; while (wire_data->simplify(true, false, false, 1, -1, false, false)) { } current_ast_mod->children.push_back(wire_data); @@ -1844,11 +1858,40 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, AstNode *shamt = shift_expr; - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), - new AstNode(AST_SHIFT_LEFT, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), shamt->clone()))); - newNode->children.push_back(new AstNode(AST_ASSIGN_EQ, ref_data->clone(), - new AstNode(AST_SHIFT_LEFT, new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()), shamt))); - newNode->children.push_back(new AstNode(type, lvalue, new AstNode(AST_BIT_OR, new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)), ref_data))); + int shamt_width_hint = 0; + bool shamt_sign_hint = true; + shamt->detectSignWidth(shamt_width_hint, shamt_sign_hint); + + int start_bit = children[0]->id2ast->range_right; + bool use_shift = shamt_sign_hint; + + if (start_bit != 0) { + shamt = new AstNode(AST_SUB, shamt, mkconst_int(start_bit, true)); + use_shift = true; + } + + AstNode *t; + + t = mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt->clone())); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt->clone()); + t = new AstNode(AST_ASSIGN_EQ, ref_mask->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, mkconst_bits(std::vector<RTLIL::State>(result_width, State::S1), false), children[1]->clone()); + if (use_shift) + t = new AstNode(AST_SHIFT, t, new AstNode(AST_NEG, shamt)); + else + t = new AstNode(AST_SHIFT_LEFT, t, shamt); + t = new AstNode(AST_ASSIGN_EQ, ref_data->clone(), t); + newNode->children.push_back(t); + + t = new AstNode(AST_BIT_AND, old_data, new AstNode(AST_BIT_NOT, ref_mask)); + t = new AstNode(AST_BIT_OR, t, ref_data); + t = new AstNode(type, lvalue, t); + newNode->children.push_back(t); } goto apply_newNode; @@ -2637,7 +2680,7 @@ skip_dynamic_range_lvalue_expansion:; bool recommend_const_eval = false; bool require_const_eval = in_param ? false : has_const_only_constructs(recommend_const_eval); - if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype")) + if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count(ID::via_celltype)) { bool all_args_const = true; for (auto child : children) { @@ -2696,9 +2739,9 @@ skip_dynamic_range_lvalue_expansion:; goto replace_fcall_with_id; } - if (decl->attributes.count("\\via_celltype")) + if (decl->attributes.count(ID::via_celltype)) { - std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string(); + std::string celltype = decl->attributes.at(ID::via_celltype)->asAttrConst().decode_string(); std::string outport = str; if (celltype.find(' ') != std::string::npos) { @@ -2792,7 +2835,7 @@ skip_dynamic_range_lvalue_expansion:; wire->is_reg = true; wire->attributes[ID::nosync] = AstNode::mkconst_int(1, false); if (child->type == AST_ENUM_ITEM) - wire->attributes["\\enum_base_type"] = child->attributes["\\enum_base_type"]; + wire->attributes[ID::enum_base_type] = child->attributes[ID::enum_base_type]; wire_cache[child->str] = wire; @@ -3024,6 +3067,7 @@ replace_fcall_later:; } } break; + if (0) { case AST_SELFSZ: const_func = RTLIL::const_pos; } if (0) { case AST_POS: const_func = RTLIL::const_pos; } if (0) { case AST_NEG: const_func = RTLIL::const_neg; } if (children[0]->type == AST_CONSTANT) { @@ -3032,10 +3076,10 @@ replace_fcall_later:; } else if (children[0]->isConst()) { newNode = new AstNode(AST_REALVALUE); - if (type == AST_POS) - newNode->realvalue = +children[0]->asReal(sign_hint); - else + if (type == AST_NEG) newNode->realvalue = -children[0]->asReal(sign_hint); + else + newNode->realvalue = +children[0]->asReal(sign_hint); } break; case AST_TERNARY: @@ -4092,7 +4136,7 @@ void AstNode::allocateDefaultEnumValues() int last_enum_int = -1; for (auto node : children) { log_assert(node->type==AST_ENUM_ITEM); - node->attributes["\\enum_base_type"] = mkconst_str(str); + node->attributes[ID::enum_base_type] = mkconst_str(str); for (size_t i = 0; i < node->children.size(); i++) { switch (node->children[i]->type) { case AST_NONE: diff --git a/frontends/ilang/ilang_parser.y b/frontends/ilang/ilang_parser.y index 8e21fb176..118f13de9 100644 --- a/frontends/ilang/ilang_parser.y +++ b/frontends/ilang/ilang_parser.y @@ -107,16 +107,16 @@ module: delete_current_module = false; if (current_design->has($2)) { RTLIL::Module *existing_mod = current_design->module($2); - if (!flag_overwrite && (flag_lib || (attrbuf.count("\\blackbox") && attrbuf.at("\\blackbox").as_bool()))) { + if (!flag_overwrite && (flag_lib || (attrbuf.count(ID::blackbox) && attrbuf.at(ID::blackbox).as_bool()))) { log("Ignoring blackbox re-definition of module %s.\n", $2); delete_current_module = true; - } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute("\\blackbox")) { + } else if (!flag_nooverwrite && !flag_overwrite && !existing_mod->get_bool_attribute(ID::blackbox)) { rtlil_frontend_ilang_yyerror(stringf("ilang error: redefinition of module %s.", $2).c_str()); } else if (flag_nooverwrite) { log("Ignoring re-definition of module %s.\n", $2); delete_current_module = true; } else { - log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute("\\blackbox") ? " blackbox" : "", $2); + log("Replacing existing%s module %s.\n", existing_mod->get_bool_attribute(ID::blackbox) ? " blackbox" : "", $2); current_design->remove(existing_mod); } } diff --git a/frontends/verilog/verilog_frontend.cc b/frontends/verilog/verilog_frontend.cc index 6879e0943..26abe49b5 100644 --- a/frontends/verilog/verilog_frontend.cc +++ b/frontends/verilog/verilog_frontend.cc @@ -48,7 +48,7 @@ static void error_on_dpi_function(AST::AstNode *node) error_on_dpi_function(child); } -static void add_package_types(std::map<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) +static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std::vector<AST::AstNode *> &package_list) { // prime the parser's user type lookup table with the package qualified names // of typedefed names in the packages seen so far. diff --git a/frontends/verilog/verilog_frontend.h b/frontends/verilog/verilog_frontend.h index 444cc7297..aa7881038 100644 --- a/frontends/verilog/verilog_frontend.h +++ b/frontends/verilog/verilog_frontend.h @@ -50,7 +50,7 @@ namespace VERILOG_FRONTEND extern std::vector<UserTypeMap *> user_type_stack; // names of package typedef'ed types - extern std::map<std::string, AST::AstNode*> pkg_user_types; + extern dict<std::string, AST::AstNode*> pkg_user_types; // state of `default_nettype extern bool default_nettype_wire; diff --git a/frontends/verilog/verilog_parser.y b/frontends/verilog/verilog_parser.y index 4a5aba79e..db9a130cf 100644 --- a/frontends/verilog/verilog_parser.y +++ b/frontends/verilog/verilog_parser.y @@ -50,12 +50,12 @@ using namespace VERILOG_FRONTEND; YOSYS_NAMESPACE_BEGIN namespace VERILOG_FRONTEND { int port_counter; - std::map<std::string, int> port_stubs; - std::map<std::string, AstNode*> *attr_list, default_attr_list; - std::stack<std::map<std::string, AstNode*> *> attr_list_stack; - std::map<std::string, AstNode*> *albuf; + dict<std::string, int> port_stubs; + dict<IdString, AstNode*> *attr_list, default_attr_list; + std::stack<dict<IdString, AstNode*> *> attr_list_stack; + dict<IdString, AstNode*> *albuf; std::vector<UserTypeMap*> user_type_stack; - std::map<std::string, AstNode*> pkg_user_types; + dict<std::string, AstNode*> pkg_user_types; std::vector<AstNode*> ast_stack; struct AstNode *astbuf1, *astbuf2, *astbuf3; struct AstNode *current_function_or_task; @@ -87,7 +87,7 @@ YOSYS_NAMESPACE_END int frontend_verilog_yylex(YYSTYPE *yylval_param, YYLTYPE *yyloc_param); -static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) +static void append_attr(AstNode *ast, dict<IdString, AstNode*> *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) @@ -97,7 +97,7 @@ static void append_attr(AstNode *ast, std::map<std::string, AstNode*> *al) delete al; } -static void append_attr_clone(AstNode *ast, std::map<std::string, AstNode*> *al) +static void append_attr_clone(AstNode *ast, dict<IdString, AstNode*> *al) { for (auto &it : *al) { if (ast->attributes.count(it.first) > 0) @@ -106,7 +106,7 @@ static void append_attr_clone(AstNode *ast, std::map<std::string, AstNode*> *al) } } -static void free_attr(std::map<std::string, AstNode*> *al) +static void free_attr(dict<IdString, AstNode*> *al) { for (auto &it : *al) delete it.second; @@ -192,7 +192,7 @@ static void addRange(AstNode *parent, int msb = 31, int lsb = 0, bool isSigned = %union { std::string *string; struct YOSYS_NAMESPACE_PREFIX AST::AstNode *ast; - std::map<std::string, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; + YOSYS_NAMESPACE_PREFIX dict<YOSYS_NAMESPACE_PREFIX RTLIL::IdString, YOSYS_NAMESPACE_PREFIX AST::AstNode*> *al; struct specify_target *specify_target_ptr; struct specify_triple *specify_triple_ptr; struct specify_rise_fall *specify_rise_fall_ptr; @@ -289,7 +289,7 @@ attr: { if (attr_list != nullptr) attr_list_stack.push(attr_list); - attr_list = new std::map<std::string, AstNode*>; + attr_list = new dict<IdString, AstNode*>; for (auto &it : default_attr_list) (*attr_list)[it.first] = it.second->clone(); } attr_opt { @@ -311,7 +311,7 @@ defattr: DEFATTR_BEGIN { if (attr_list != nullptr) attr_list_stack.push(attr_list); - attr_list = new std::map<std::string, AstNode*>; + attr_list = new dict<IdString, AstNode*>; for (auto &it : default_attr_list) delete it.second; default_attr_list.clear(); @@ -645,13 +645,13 @@ non_opt_range: } | '[' expr TOK_POS_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), $4), AstNode::mkconst_int(1, true))); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); } | '[' expr TOK_NEG_INDEXED expr ']' { $$ = new AstNode(AST_RANGE); - AstNode *expr = new AstNode(AST_CONCAT, $2); + AstNode *expr = new AstNode(AST_SELFSZ, $2); $$->children.push_back(new AstNode(AST_ADD, expr, AstNode::mkconst_int(0, true))); $$->children.push_back(new AstNode(AST_SUB, new AstNode(AST_ADD, expr->clone(), AstNode::mkconst_int(1, true)), $4)); } | @@ -885,6 +885,7 @@ specify_item: cell->str = stringf("$specify$%d", autoidx++); cell->children.push_back(new AstNode(AST_CELLTYPE)); cell->children.back()->str = target->dat ? "$specify3" : "$specify2"; + SET_AST_NODE_LOC(cell, en_expr ? @1 : @2, @10); char oper_polarity = 0; char oper_type = oper->at(0); @@ -973,6 +974,7 @@ specify_item: cell->str = stringf("$specify$%d", autoidx++); cell->children.push_back(new AstNode(AST_CELLTYPE)); cell->children.back()->str = "$specrule"; + SET_AST_NODE_LOC(cell, @1, @14); cell->children.push_back(new AstNode(AST_PARASET, AstNode::mkconst_str(*$1))); cell->children.back()->str = "\\TYPE"; @@ -1099,8 +1101,8 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { $$ = new specify_rise_fall; @@ -1108,11 +1110,11 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + delete $8; + delete $10; + delete $12; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } | '(' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ',' specify_triple ')' { $$ = new specify_rise_fall; @@ -1120,17 +1122,17 @@ specify_rise_fall: $$->fall = *$4; delete $2; delete $4; - delete $6; - delete $8; - delete $10; - delete $12; - delete $14; - delete $16; - delete $18; - delete $20; - delete $22; - delete $24; - log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); + delete $6; + delete $8; + delete $10; + delete $12; + delete $14; + delete $16; + delete $18; + delete $20; + delete $22; + delete $24; + log_file_warning(current_filename, get_line_num(), "Path delay expressions beyond rise/fall not currently supported. Ignoring.\n"); } specify_triple: @@ -1388,7 +1390,7 @@ enum_type: TOK_ENUM { delete astbuf1; astbuf1 = tnode; tnode->type = AST_WIRE; - tnode->attributes["\\enum_type"] = AstNode::mkconst_str(astbuf2->str); + tnode->attributes[ID::enum_type] = AstNode::mkconst_str(astbuf2->str); // drop constant but keep any range delete tnode->children[0]; tnode->children.erase(tnode->children.begin()); } @@ -1747,7 +1749,9 @@ single_prim: /* no name */ { astbuf2 = astbuf1->clone(); ast_stack.back()->children.push_back(astbuf2); - } '(' cell_port_list ')'; + } '(' cell_port_list ')' { + SET_AST_NODE_LOC(astbuf2, @1, @$); + } cell_parameter_list_opt: '#' '(' cell_parameter_list ')' | /* empty */; @@ -2341,7 +2345,7 @@ unique_case_attr: case_attr: attr unique_case_attr { - if ($2) (*$1)["\\parallel_case"] = AstNode::mkconst_int(1, false); + if ($2) (*$1)[ID::parallel_case] = AstNode::mkconst_int(1, false); $$ = $1; }; @@ -2533,7 +2537,12 @@ gen_stmt: ast_stack.back()->children.push_back(node); ast_stack.push_back(node); ast_stack.back()->children.push_back($3); - } gen_stmt_block opt_gen_else { + AstNode *block = new AstNode(AST_GENBLOCK); + ast_stack.back()->children.push_back(block); + ast_stack.push_back(block); + } gen_stmt_or_null { + ast_stack.pop_back(); + } opt_gen_else { SET_AST_NODE_LOC(ast_stack.back(), @1, @7); ast_stack.pop_back(); } | diff --git a/kernel/constids.inc b/kernel/constids.inc index 27b652e24..6b40a5908 100644 --- a/kernel/constids.inc +++ b/kernel/constids.inc @@ -74,6 +74,8 @@ X(EN) X(EN_DST) X(EN_POLARITY) X(EN_SRC) +X(enum_base_type) +X(enum_type) X(equiv_merged) X(equiv_region) X(extract_order) @@ -123,6 +125,7 @@ X(nomem2init) X(nomem2reg) X(nomeminit) X(nosync) +X(nowrshmsk) X(O) X(OFFSET) X(onehot) @@ -196,6 +199,7 @@ X(U) X(unique) X(unused_bits) X(V) +X(via_celltype) X(wand) X(whitebox) X(WIDTH) diff --git a/kernel/yosys.h b/kernel/yosys.h index af1e376b1..c922faf26 100644 --- a/kernel/yosys.h +++ b/kernel/yosys.h @@ -155,6 +155,16 @@ extern Tcl_Obj *Tcl_ObjSetVar2(Tcl_Interp *interp, Tcl_Obj *part1Ptr, Tcl_Obj *p # define YS_NORETURN #endif +#if __cplusplus >= 201703L +# define YS_FALLTHROUGH [[fallthrough]]; +#elif defined(__clang__) +# define YS_FALLTHROUGH [[clang::fallthrough]]; +#elif defined(__GNUC__) +# define YS_FALLTHROUGH [[gnu::fallthrough]]; +#else +# define YS_FALLTHROUGH +#endif + YOSYS_NAMESPACE_BEGIN // Note: All headers included in hashlib.h must be included diff --git a/passes/tests/test_autotb.cc b/passes/tests/test_autotb.cc index 42e8a61ea..19f21493d 100644 --- a/passes/tests/test_autotb.cc +++ b/passes/tests/test_autotb.cc @@ -81,6 +81,7 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s f << stringf("integer i;\n"); f << stringf("integer file;\n\n"); + f << stringf("reg [1023:0] filename;\n\n"); f << stringf("reg [31:0] xorshift128_x = 123456789;\n"); f << stringf("reg [31:0] xorshift128_y = 362436069;\n"); @@ -305,9 +306,15 @@ static void autotest(std::ostream &f, RTLIL::Design *design, int num_iter, int s } f << stringf("initial begin\n"); - f << stringf("\t// $dumpfile(\"testbench.vcd\");\n"); - f << stringf("\t// $dumpvars(0, testbench);\n"); - f << stringf("\tfile = $fopen(`outfile);\n"); + f << stringf("\tif ($value$plusargs(\"VCD=%%s\", filename)) begin\n"); + f << stringf("\t\t$dumpfile(filename);\n"); + f << stringf("\t\t$dumpvars(0, testbench);\n"); + f << stringf("\tend\n"); + f << stringf("\tif ($value$plusargs(\"OUT=%%s\", filename)) begin\n"); + f << stringf("\t\tfile = $fopen(filename);\n"); + f << stringf("\tend else begin\n"); + f << stringf("\t\tfile = $fopen(`outfile);\n"); + f << stringf("\tend\n"); for (auto module : design->modules()) if (!module->get_bool_attribute(ID::gentb_skip)) f << stringf("\t%s;\n", idy(module->name.str(), "test").c_str()); diff --git a/techlibs/ecp5/cells_bb.v b/techlibs/ecp5/cells_bb.v index ae124e7a3..756f05366 100644 --- a/techlibs/ecp5/cells_bb.v +++ b/techlibs/ecp5/cells_bb.v @@ -652,6 +652,10 @@ module DCUA( parameter CH1_PROTOCOL = "8B10B"; parameter CH0_CDR_MAX_RATE = "2.5"; parameter CH1_CDR_MAX_RATE = "2.5"; + parameter CH0_TXDEPRE = "DISABLED"; + parameter CH1_TXDEPRE = "DISABLED"; + parameter CH0_TXDEPOST = "DISABLED"; + parameter CH1_TXDEPOST = "DISABLED"; endmodule (* blackbox *) diff --git a/techlibs/ecp5/synth_ecp5.cc b/techlibs/ecp5/synth_ecp5.cc index ab740ea0d..b9b236a0c 100644 --- a/techlibs/ecp5/synth_ecp5.cc +++ b/techlibs/ecp5/synth_ecp5.cc @@ -30,6 +30,11 @@ struct SynthEcp5Pass : public ScriptPass { SynthEcp5Pass() : ScriptPass("synth_ecp5", "synthesis for ECP5 FPGAs") { } + void on_register() YS_OVERRIDE + { + RTLIL::constpad["synth_ecp5.abc9.W"] = "300"; + } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -324,6 +329,14 @@ struct SynthEcp5Pass : public ScriptPass if (abc9) { run("read_verilog -icells -lib -specify +/abc9_model.v +/ecp5/abc9_model.v"); + std::string abc9_opts; + if (nowidelut) + abc9_opts += " -maxlut 4"; + std::string k = "synth_ecp5.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) + abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); + else + abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); if (nowidelut) run("abc9 -maxlut 4 -W 200"); else diff --git a/techlibs/ice40/cells_sim.v b/techlibs/ice40/cells_sim.v index 6a0e3031e..5d107989d 100644 --- a/techlibs/ice40/cells_sim.v +++ b/techlibs/ice40/cells_sim.v @@ -1908,7 +1908,7 @@ module ICESTORM_LC ( o_reg <= SR_pd ? SET_NORESET : lut_o; reg o_reg_async = 1'b0; - always @(posedge polarized_clk, posedge SR) + always @(posedge polarized_clk, posedge SR_pd) if (SR_pd) o_reg_async <= SET_NORESET; else if (CEN_pu) diff --git a/techlibs/ice40/synth_ice40.cc b/techlibs/ice40/synth_ice40.cc index 9724b7dd5..6e05ab0b2 100644 --- a/techlibs/ice40/synth_ice40.cc +++ b/techlibs/ice40/synth_ice40.cc @@ -29,6 +29,13 @@ struct SynthIce40Pass : public ScriptPass { SynthIce40Pass() : ScriptPass("synth_ice40", "synthesis for iCE40 FPGAs") { } + void on_register() YS_OVERRIDE + { + RTLIL::constpad["synth_ice40.abc9.hx.W"] = "250"; + RTLIL::constpad["synth_ice40.abc9.lp.W"] = "400"; + RTLIL::constpad["synth_ice40.abc9.u.W"] = "750"; + } + void help() YS_OVERRIDE { // |---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---|---v---| @@ -218,10 +225,10 @@ struct SynthIce40Pass : public ScriptPass device_opt = args[++argidx]; continue; } - if (args[argidx] == "-flowmap") { - flowmap = true; - continue; - } + if (args[argidx] == "-flowmap") { + flowmap = true; + continue; + } break; } extra_args(args, argidx, design); @@ -233,13 +240,12 @@ struct SynthIce40Pass : public ScriptPass if (abc9 && retime) log_cmd_error("-retime option not currently compatible with -abc9!\n"); - - if (abc9 && noabc) - log_cmd_error("-abc9 is incompatible with -noabc!\n"); - if (abc9 && flowmap) - log_cmd_error("-abc9 is incompatible with -flowmap!\n"); - if (flowmap && noabc) - log_cmd_error("-flowmap is incompatible with -noabc!\n"); + if (abc9 && noabc) + log_cmd_error("-abc9 is incompatible with -noabc!\n"); + if (abc9 && flowmap) + log_cmd_error("-abc9 is incompatible with -flowmap!\n"); + if (flowmap && noabc) + log_cmd_error("-flowmap is incompatible with -noabc!\n"); log_header(design, "Executing SYNTH_ICE40 pass.\n"); log_push(); @@ -365,22 +371,23 @@ struct SynthIce40Pass : public ScriptPass run("techmap -map +/ice40/latches_map.v"); if (noabc || flowmap || help_mode) { run("simplemap", " (if -noabc or -flowmap)"); - if (noabc || help_mode) - run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); - if (flowmap || help_mode) - run("flowmap -maxlut 4", "(only if -flowmap)"); + if (noabc || help_mode) + run("techmap -map +/gate2lut.v -D LUT_WIDTH=4", "(only if -noabc)"); + if (flowmap || help_mode) + run("flowmap -maxlut 4", "(only if -flowmap)"); } if (!noabc) { if (abc9) { run("read_verilog " + define + " -icells -lib -specify +/abc9_model.v +/ice40/abc9_model.v"); - int wire_delay; - if (device_opt == "lp") - wire_delay = 400; - else if (device_opt == "u") - wire_delay = 750; - else - wire_delay = 250; - run(stringf("abc9 -W %d", wire_delay)); + std::string abc9_opts; + std::string k = "synth_ice40.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) + abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); + else { + k = stringf("synth_ice40.abc9.%s.W", device_opt.c_str()); + abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k).c_str()); + } + run("abc9 " + abc9_opts); } else run("abc -dress -lut 4", "(skip if -noabc)"); diff --git a/techlibs/intel_alm/Makefile.inc b/techlibs/intel_alm/Makefile.inc index bbf233aeb..ed6c4510b 100644 --- a/techlibs/intel_alm/Makefile.inc +++ b/techlibs/intel_alm/Makefile.inc @@ -7,13 +7,13 @@ $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/al $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/arith_alm_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_map.v)) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/dff_sim.v)) +$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/mem_sim.v)) # RAM bramtypes := m10k m20k $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype).txt))) $(foreach bramtype, $(bramtypes), $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/bram_$(bramtype)_map.v))) $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab.txt)) -$(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/lutram_mlab_map.v)) # Miscellaneous $(eval $(call add_share_file,share/intel_alm/common,techlibs/intel_alm/common/megafunction_bb.v)) diff --git a/techlibs/intel_alm/common/bram_m10k_map.v b/techlibs/intel_alm/common/bram_m10k_map.v index e5566010d..061463c3e 100644 --- a/techlibs/intel_alm/common/bram_m10k_map.v +++ b/techlibs/intel_alm/common/bram_m10k_map.v @@ -28,4 +28,4 @@ altsyncram #( .clock1(CLK1)
);
-endmodule +endmodule
diff --git a/techlibs/intel_alm/common/lutram_mlab.txt b/techlibs/intel_alm/common/lutram_mlab.txt index 1d6174d85..3cc69399d 100644 --- a/techlibs/intel_alm/common/lutram_mlab.txt +++ b/techlibs/intel_alm/common/lutram_mlab.txt @@ -1,20 +1,18 @@ -bram __MISTRAL_MLAB
- init 0 # TODO: Re-enable when I figure out how LUTRAM init works
- abits 5
- dbits 16 @D32x16
- dbits 18 @D32x18
- dbits 20 @D32x20
- groups 2
- ports 1 1
- wrmode 1 0
- # read enable
- enable 1 0
- transp 1 0
- clocks 1 2
- clkpol 1 1
-endbram
-
-match __MISTRAL_MLAB
- min efficiency 5
- make_outreg
-endmatch
+bram MISTRAL_MLAB + init 0 # TODO: Re-enable when Yosys remembers the original filename. + abits 5 + dbits 1 + groups 2 + ports 1 1 + wrmode 1 0 + # write enable + enable 1 0 + transp 0 0 + clocks 1 0 + clkpol 1 1 +endbram + +match MISTRAL_MLAB + min efficiency 5 + make_outreg +endmatch
\ No newline at end of file diff --git a/techlibs/intel_alm/common/lutram_mlab_map.v b/techlibs/intel_alm/common/lutram_mlab_map.v deleted file mode 100644 index 3a9c8590e..000000000 --- a/techlibs/intel_alm/common/lutram_mlab_map.v +++ /dev/null @@ -1,29 +0,0 @@ -module __MISTRAL_MLAB(CLK1, CLK2, A1ADDR, A1DATA, A1EN, B1ADDR, B1DATA);
-
-parameter CFG_ABITS = 5;
-parameter CFG_DBITS = 20;
-
-input CLK1, CLK2;
-input [CFG_ABITS-1:0] A1ADDR, B1ADDR;
-input [CFG_DBITS-1:0] A1DATA;
-input A1EN;
-output [CFG_DBITS-1:0] B1DATA;
-
-altsyncram #(
- .operation_mode("dual_port"),
- .ram_block_type("mlab"),
- .widthad_a(CFG_ABITS),
- .width_a(CFG_DBITS),
- .widthad_b(CFG_ABITS),
- .width_b(CFG_DBITS),
-) _TECHMAP_REPLACE_ (
- .address_a(A1ADDR),
- .data_a(A1DATA),
- .wren_a(A1EN),
- .address_b(B1ADDR),
- .q_b(B1DATA),
- .clock0(CLK1),
- .clock1(CLK1),
-);
-
-endmodule
diff --git a/techlibs/intel_alm/common/megafunction_bb.v b/techlibs/intel_alm/common/megafunction_bb.v index 21ba73a09..c749fa70b 100644 --- a/techlibs/intel_alm/common/megafunction_bb.v +++ b/techlibs/intel_alm/common/megafunction_bb.v @@ -106,3 +106,26 @@ input aclr1; output eccstatus; endmodule + +(* blackbox *) +module cyclonev_mlab_cell(portaaddr, portadatain, portbaddr, portbdataout, ena0, clk0, clk1); + +parameter logical_ram_name = ""; +parameter logical_ram_depth = 32; +parameter logical_ram_width = 20; +parameter mixed_port_feed_through_mode = "new"; +parameter first_bit_number = 0; +parameter first_address = 0; +parameter last_address = 31; +parameter address_width = 5; +parameter data_width = 1; +parameter byte_enable_mask_width = 1; +parameter port_b_data_out_clock = "NONE"; +parameter [639:0] mem_init0 = 640'b0; + +input [address_width-1:0] portaaddr, portbaddr; +input [data_width-1:0] portadatain; +output [data_width-1:0] portbdataout; +input ena0, clk0, clk1; + +endmodule diff --git a/techlibs/intel_alm/common/mem_sim.v b/techlibs/intel_alm/common/mem_sim.v new file mode 100644 index 000000000..ae79b19a4 --- /dev/null +++ b/techlibs/intel_alm/common/mem_sim.v @@ -0,0 +1,60 @@ +// The MLAB +// -------- +// In addition to Logic Array Blocks (LABs) that contain ten Adaptive Logic +// Modules (ALMs, see alm_sim.v), the Cyclone V/10GX also contain +// Memory/Logic Array Blocks (MLABs) that can act as either ten ALMs, or utilise +// the memory the ALM uses to store the look-up table data for general usage, +// producing a 32 address by 20-bit block of memory. MLABs are spread out +// around the chip, so they can be placed near where they are needed, rather than +// being comparatively limited in placement for a deep but narrow memory such as +// the M10K memory block. +// +// MLABs are used mainly for shallow but wide memories, such as CPU register +// files (which have perhaps 32 registers that are comparatively wide (16/32-bit)) +// or shift registers (by using the output of the Nth bit as input for the N+1th +// bit). +// +// Oddly, instead of providing a block 32 address by 20-bit cell, Quartus asks +// synthesis tools to build MLABs out of 32 address by 1-bit cells, and tries +// to put these cells in the same MLAB during cell placement. Because of this +// a MISTRAL_MLAB cell represents one of these 32 address by 1-bit cells, and +// 20 of them represent a physical MLAB. +// +// How the MLAB works +// ------------------ +// MLABs are poorly documented, so the following information is based mainly +// on the simulation model and my knowledge of how memories like these work. +// Additionally, note that the ports of MISTRAL_MLAB are the ones auto-generated +// by the Yosys `memory_bram` pass, and it doesn't make sense to me to use +// `techmap` just for the sake of renaming the cell ports. +// +// The MLAB can be initialised to any value, but unfortunately Quartus only +// allows memory initialisation from a file. Since Yosys doesn't preserve input +// file information, or write the contents of an `initial` block to a file, +// Yosys can't currently initialise the MLAB in a way Quartus will accept. +// +// The MLAB takes in data from A1DATA at the rising edge of CLK1, and if A1EN +// is high, writes it to the address in A1ADDR. A1EN can therefore be used to +// conditionally write data to the MLAB. +// +// Simultaneously, the MLAB reads data from B1ADDR, and outputs it to B1DATA, +// asynchronous to CLK1 and ignoring A1EN. If a synchronous read is needed +// then the output can be fed to embedded flops. Presently, Yosys assumes +// Quartus will pack external flops into the MLAB, but this is an assumption +// that needs testing. + +// The vendor sim model outputs 'x for a very short period (a few +// combinational delta cycles) after each write. This has been omitted from +// the following model because it's very difficult to trigger this in practice +// as clock cycles will be much longer than any potential blip of 'x, so the +// model can be treated as always returning a defined result. +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +reg [31:0] mem = 32'b0; + +always @(posedge CLK1) + if (A1EN) mem[A1ADDR] <= A1DATA; + +assign B1DATA = mem[B1ADDR]; + +endmodule diff --git a/techlibs/intel_alm/common/quartus_rename.v b/techlibs/intel_alm/common/quartus_rename.v index ac0fe12aa..c40a4e02d 100644 --- a/techlibs/intel_alm/common/quartus_rename.v +++ b/techlibs/intel_alm/common/quartus_rename.v @@ -1,8 +1,10 @@ `ifdef cyclonev `define LCELL cyclonev_lcell_comb +`define MLAB cyclonev_mlab_cell `endif `ifdef cyclone10gx `define LCELL cyclone10gx_lcell_comb +`define MLAB cyclone10gx_mlab_cell `endif module __MISTRAL_VCC(output Q); @@ -80,3 +82,40 @@ parameter LUT1 = 16'h0000; `LCELL #(.lut_mask({16'h0, LUT1, 16'h0, LUT0})) _TECHMAP_REPLACE_ (.dataa(A), .datab(B), .datac(C), .datad(D0), .dataf(D1), .cin(CI), .sumout(SO), .cout(CO)); endmodule + + +module MISTRAL_MLAB(input [4:0] A1ADDR, input A1DATA, A1EN, CLK1, input [4:0] B1ADDR, output B1DATA); + +// Here we get to an unfortunate situation. The cell has a mem_init0 parameter, +// which takes in a hexadecimal string that could be used to initialise RAM. +// In the vendor simulation models, this appears to work fine, but Quartus, +// either intentionally or not, forgets about this parameter and initialises the +// RAM to zero. +// +// Because of this, RAM initialisation is presently disabled, but the source +// used to generate mem_init0 is kept (commented out) in case this gets fixed +// or an undocumented way to get Quartus to initialise from mem_init0 is found. + +`MLAB #( + .logical_ram_name("MISTRAL_MLAB"), + .logical_ram_depth(32), + .logical_ram_width(1), + .mixed_port_feed_through_mode("Dont Care"), + .first_bit_number(0), + .first_address(0), + .last_address(31), + .address_width(5), + .data_width(1), + .byte_enable_mask_width(1), + .port_b_data_out_clock("NONE"), + // .mem_init0($sformatf("%08x", INIT)) +) _TECHMAP_REPLACE_ ( + .portaaddr(A1ADDR), + .portadatain(A1DATA), + .portbaddr(B1ADDR), + .portbdataout(B1DATA), + .ena0(A1EN), + .clk0(CLK1) +); + +endmodule diff --git a/techlibs/intel_alm/synth_intel_alm.cc b/techlibs/intel_alm/synth_intel_alm.cc index 200b0cdd1..bf9e746b8 100644 --- a/techlibs/intel_alm/synth_intel_alm.cc +++ b/techlibs/intel_alm/synth_intel_alm.cc @@ -164,6 +164,7 @@ struct SynthIntelALMPass : public ScriptPass { run(stringf("read_verilog -sv -lib +/intel/%s/cells_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/alm_sim.v", family_opt.c_str())); run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/dff_sim.v", family_opt.c_str())); + run(stringf("read_verilog -specify -lib -D %s +/intel_alm/common/mem_sim.v", family_opt.c_str())); // Misc and common cells run("read_verilog -lib +/intel/common/altpll_bb.v"); @@ -190,7 +191,6 @@ struct SynthIntelALMPass : public ScriptPass { if (!nolutram && check_label("map_lutram", "(skip if -nolutram)")) { run("memory_bram -rules +/intel_alm/common/lutram_mlab.txt", "(for Cyclone V / Cyclone 10GX)"); - run("techmap -map +/intel_alm/common/lutram_mlab_map.v", "(for Cyclone V / Cyclone 10GX)"); } if (check_label("map_ffram")) { diff --git a/techlibs/xilinx/synth_xilinx.cc b/techlibs/xilinx/synth_xilinx.cc index 1c190d37e..229ffcb3d 100644 --- a/techlibs/xilinx/synth_xilinx.cc +++ b/techlibs/xilinx/synth_xilinx.cc @@ -619,11 +619,13 @@ struct SynthXilinxPass : public ScriptPass run("techmap " + techmap_args); run("read_verilog -icells -lib -specify +/abc9_model.v +/xilinx/abc9_model.v"); std::string abc9_opts; - auto k = stringf("synth_xilinx.abc9.%s.W", family.c_str()); - if (active_design->scratchpad.count(k)) + std::string k = "synth_xilinx.abc9.W"; + if (active_design && active_design->scratchpad.count(k)) abc9_opts += stringf(" -W %s", active_design->scratchpad_get_string(k).c_str()); - else + else { + k = stringf("synth_xilinx.abc9.%s.W", family.c_str()); abc9_opts += stringf(" -W %s", RTLIL::constpad.at(k, RTLIL::constpad.at("synth_xilinx.abc9.xc7.W")).c_str()); + } if (nowidelut) abc9_opts += stringf(" -maxlut %d", lut_size); if (dff_mode) diff --git a/tests/arch/intel_alm/lutram.ys b/tests/arch/intel_alm/lutram.ys new file mode 100644 index 000000000..6f997b67b --- /dev/null +++ b/tests/arch/intel_alm/lutram.ys @@ -0,0 +1,20 @@ +read_verilog ../common/lutram.v +hierarchy -top lutram_1w1r +proc +memory -nomap +equiv_opt -run :prove -map +/intel_alm/common/alm_sim.v -map +/intel_alm/common/dff_sim.v -map +/intel_alm/common/mem_sim.v synth_intel_alm -family cyclonev -nobram +memory +opt -full + +miter -equiv -flatten -make_assert -make_outputs gold gate miter +sat -verify -prove-asserts -seq 5 -set-init-zero -show-inputs -show-outputs miter + +design -load postopt +cd lutram_1w1r +select -assert-count 16 t:MISTRAL_MLAB +select -assert-count 1 t:MISTRAL_NOT +select -assert-count 2 t:MISTRAL_ALUT2 +select -assert-count 8 t:MISTRAL_ALUT3 +select -assert-count 17 t:MISTRAL_FF +select -assert-none t:MISTRAL_NOT t:MISTRAL_ALUT2 t:MISTRAL_ALUT3 t:MISTRAL_FF t:MISTRAL_MLAB %% t:* %D + diff --git a/tests/simple/partsel.v b/tests/simple/partsel.v index 83493fcb0..5e9730d6b 100644 --- a/tests/simple/partsel.v +++ b/tests/simple/partsel.v @@ -64,3 +64,49 @@ endmodule module partsel_test003(input [2:0] a, b, input [31:0] din, output [3:0] dout); assign dout = din[a*b +: 2]; endmodule + +module partsel_test004 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test005 ( + input [31:0] din, + input signed [4:0] n, + output reg [31:0] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule + +module partsel_test006 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1 +: 2] = din[n +: 2]; + end +endmodule + + +module partsel_test007 ( + input [31:-32] din, + input signed [4:0] n, + output reg [31:-32] dout +); + always @(*) begin + dout = 0; + dout[n+1] = din[n]; + end +endmodule diff --git a/tests/various/gen_if_null.v b/tests/various/gen_if_null.v new file mode 100644 index 000000000..a12ac6288 --- /dev/null +++ b/tests/various/gen_if_null.v @@ -0,0 +1,13 @@ +module test(x, y, z); + localparam OFF = 0; + generate + if (OFF) ; + else input x; + if (!OFF) input y; + else ; + if (OFF) ; + else ; + if (OFF) ; + input z; + endgenerate +endmodule diff --git a/tests/various/gen_if_null.ys b/tests/various/gen_if_null.ys new file mode 100644 index 000000000..31dfc444b --- /dev/null +++ b/tests/various/gen_if_null.ys @@ -0,0 +1,4 @@ +read_verilog gen_if_null.v +select -assert-count 1 test/x +select -assert-count 1 test/y +select -assert-count 1 test/z diff --git a/tests/various/primitives.ys b/tests/various/primitives.ys new file mode 100644 index 000000000..9307ca50f --- /dev/null +++ b/tests/various/primitives.ys @@ -0,0 +1,16 @@ +read_verilog <<EOT +module top(input a, b, output [5:0] y); +and (y[0], a, b); +nand (y[1], a, b); +or (y[2], a, b); +nor (y[3], a, b); +xor (y[4], a, b); +xnor (y[5], a, b); +endmodule +EOT +select -assert-count 1 t:$and a:src=<<EOT:2.4-2.17 %i +select -assert-count 1 t:$and a:src=<<EOT:3.5-3.18 %i +select -assert-count 1 t:$or a:src=<<EOT:4.3-4.16 %i +select -assert-count 1 t:$or a:src=<<EOT:5.4-5.17 %i +select -assert-count 1 t:$xor a:src=<<EOT:6.4-6.17 %i +select -assert-count 1 t:$xor a:src=<<EOT:7.5-7.18 %i diff --git a/tests/various/specify.ys b/tests/various/specify.ys index 9d55b8eb5..d7260d524 100644 --- a/tests/various/specify.ys +++ b/tests/various/specify.ys @@ -4,10 +4,16 @@ cd test select t:$specify2 -assert-count 0 select t:$specify3 -assert-count 1 select t:$specrule -assert-count 2 +select t:$specify3 a:src=specify.v:10.3-10.49 %i -assert-count 1 +select t:$specrule a:src=specify.v:11.3-11.36 %i -assert-count 1 +select t:$specrule a:src=specify.v:12.3-12.35 %i -assert-count 1 cd test2 select t:$specify2 -assert-count 2 select t:$specify3 -assert-count 0 select t:$specrule -assert-count 0 +select t:$specify2 a:src=specify.v:26.3-26.20 %i -assert-count 1 + # ^^ Note use of macro +select t:$specify2 a:src=specify.v:28.3-28.18 %i -assert-count 1 cd write_verilog specify.out design -stash gold |