diff options
Diffstat (limited to 'frontends')
-rw-r--r-- | frontends/ast/simplify.cc | 120 | ||||
-rw-r--r-- | frontends/verific/verific.cc | 113 | ||||
-rw-r--r-- | frontends/verific/verific.h | 1 |
3 files changed, 193 insertions, 41 deletions
diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 2dbabca28..7edff38d9 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -278,17 +278,21 @@ static int range_width(AstNode *node, AstNode *rnode) log_file_error(node->filename, node->location.first_line, "Unpacked array in packed struct/union member %s\n", node->str.c_str()); } -static void save_struct_array_width(AstNode *node, int width) +static void save_struct_range_dimensions(AstNode *node, AstNode *rnode) { - // stash the stride for the array - node->multirange_dimensions.push_back(width); - + node->multirange_dimensions.push_back(rnode->range_right); + node->multirange_dimensions.push_back(range_width(node, rnode)); + node->multirange_swapped.push_back(rnode->range_swapped); } -static void save_struct_range_swapped(AstNode *node, bool range_swapped) +static int get_struct_range_offset(AstNode *node, int dimension) { - node->multirange_swapped.push_back(range_swapped); + return node->multirange_dimensions[2*dimension]; +} +static int get_struct_range_width(AstNode *node, int dimension) +{ + return node->multirange_dimensions[2*dimension + 1]; } static int size_packed_struct(AstNode *snode, int base_offset) @@ -322,14 +326,17 @@ static int size_packed_struct(AstNode *snode, int base_offset) if (node->children[1]->type == AST_RANGE) { // Unpacked array, e.g. bit [63:0] a [0:3] auto rnode = node->children[1]; - // C-style array size, e.g. bit [63:0] a [4] - bool c_type = rnode->children.size() == 1; - int array_count = c_type ? rnode->range_left : range_width(node, rnode); - save_struct_array_width(node, array_count); - save_struct_range_swapped(node, rnode->range_swapped || c_type); - save_struct_array_width(node, width); - save_struct_range_swapped(node, node->children[0]->range_swapped); - width *= array_count; + if (rnode->children.size() == 1) { + // C-style array size, e.g. bit [63:0] a [4] + node->multirange_dimensions.push_back(0); + node->multirange_dimensions.push_back(rnode->range_left); + node->multirange_swapped.push_back(true); + width *= rnode->range_left; + } else { + save_struct_range_dimensions(node, rnode); + width *= range_width(node, rnode); + } + save_struct_range_dimensions(node, node->children[0]); } else { // The Yosys extension for unpacked arrays in packed structs / unions @@ -338,8 +345,7 @@ static int size_packed_struct(AstNode *snode, int base_offset) } } else { // Vector - save_struct_array_width(node, width); - save_struct_range_swapped(node, node->children[0]->range_swapped); + save_struct_range_dimensions(node, node->children[0]); } // range nodes are now redundant for (AstNode *child : node->children) @@ -355,10 +361,8 @@ static int size_packed_struct(AstNode *snode, int base_offset) } width = 1; for (auto rnode : node->children[0]->children) { - int rwidth = range_width(node, rnode); - save_struct_array_width(node, rwidth); - save_struct_range_swapped(node, rnode->range_swapped); - width *= rwidth; + save_struct_range_dimensions(node, rnode); + width *= range_width(node, rnode); } // range nodes are now redundant for (AstNode *child : node->children) @@ -422,9 +426,14 @@ static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int { expr = expr->clone(); + int offset = get_struct_range_offset(member_node, dimension); + if (offset) { + expr = new AstNode(AST_SUB, expr, node_int(offset)); + } + if (member_node->multirange_swapped[dimension]) { // The dimension has swapped range; swap index into the struct accordingly. - int msb = member_node->multirange_dimensions[dimension] - 1; + int msb = get_struct_range_width(member_node, dimension) - 1; expr = new AstNode(AST_SUB, node_int(msb), expr); } @@ -433,7 +442,7 @@ static AstNode *normalize_struct_index(AstNode *expr, AstNode *member_node, int static AstNode *struct_index_lsb_offset(AstNode *lsb_offset, AstNode *rnode, AstNode *member_node, int dimension, int &stride) { - stride /= member_node->multirange_dimensions[dimension]; + stride /= get_struct_range_width(member_node, dimension); auto right = normalize_struct_index(rnode->children.back(), member_node, dimension); auto offset = stride > 1 ? multiply_by_const(right, stride) : right; return new AstNode(AST_ADD, lsb_offset, offset); @@ -1016,7 +1025,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, // create name resolution entries for all objects with names // also merge multiple declarations for the same wire (e.g. "output foobar; reg foobar;") - if (type == AST_MODULE) { + if (type == AST_MODULE || type == AST_INTERFACE) { current_scope.clear(); std::set<std::string> existing; int counter = 0; @@ -1701,7 +1710,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, current_filename = filename; - if (type == AST_MODULE) + if (type == AST_MODULE || type == AST_INTERFACE) current_scope.clear(); // convert defparam nodes to cell parameters @@ -2068,6 +2077,14 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage, auto range = make_struct_member_range(this, item_node); newNode = new AstNode(AST_IDENTIFIER, range); newNode->str = sname; + // save type and original number of dimensions for $size() etc. + newNode->attributes[ID::wiretype] = item_node->clone(); + if (!item_node->multirange_dimensions.empty() && children.size() > 0) { + if (children[0]->type == AST_RANGE) + newNode->integer = 1; + else if (children[0]->type == AST_MULTIRANGE) + newNode->integer = children[0]->children.size(); + } newNode->basic_prep = true; if (item_node->is_signed) newNode = new AstNode(AST_TO_SIGNED, newNode); @@ -3384,24 +3401,42 @@ skip_dynamic_range_lvalue_expansion:; id_ast = current_scope.at(buf->str); if (!id_ast) log_file_error(filename, location.first_line, "Failed to resolve identifier %s for width detection!\n", buf->str.c_str()); - // a slice of our identifier means we advance to the next dimension, e.g. $size(a[3]) - if (buf->children.size() > 0) { - // something is hanging below this identifier - if (buf->children[0]->type == AST_RANGE && buf->integer == 0) - // if integer == 0, this node was originally created as AST_RANGE so it's dimension is 1 - dim++; - // more than one range, e.g. $size(a[3][2]) - else // created an AST_MULTIRANGE, converted to AST_RANGE, but original dimension saved in 'integer' field - dim += buf->integer; // increment by multirange size + + // Check for item in packed struct / union + AST::AstNode *item_node; + if (id_ast->type == AST_WIRE && + buf->attributes.count(ID::wiretype) && (item_node = buf->attributes[ID::wiretype]) && + (item_node->type == AST_STRUCT_ITEM || item_node->type == AST_STRUCT || item_node->type == AST_UNION)) + { + // The dimension of the original array expression is saved in the 'integer' field + dim += buf->integer; + if (item_node->multirange_dimensions.empty()) { + if (dim != 1) + log_file_error(filename, location.first_line, "Dimension %d out of range in `%s', as it only has one dimension!\n", dim, item_node->str.c_str()); + left = high = item_node->range_left; + right = low = item_node->range_right; + } else { + int dims = GetSize(item_node->multirange_dimensions)/2; + if (dim < 1 || dim > dims) + log_file_error(filename, location.first_line, "Dimension %d out of range in `%s', as it only has dimensions 1..%d!\n", dim, item_node->str.c_str(), dims); + right = low = get_struct_range_offset(item_node, dim - 1); + left = high = low + get_struct_range_width(item_node, dim - 1) - 1; + if (item_node->multirange_swapped[dim - 1]) { + std::swap(left, right); + } + for (int i = dim; i < dims; i++) { + mem_depth *= get_struct_range_width(item_node, i); + } + } } - // We have 4 cases: + // Otherwise, we have 4 cases: // wire x; ==> AST_WIRE, no AST_RANGE children // wire [1:0]x; ==> AST_WIRE, AST_RANGE children // wire [1:0]x[1:0]; ==> AST_MEMORY, two AST_RANGE children (1st for packed, 2nd for unpacked) // wire [1:0]x[1:0][1:0]; ==> AST_MEMORY, one AST_RANGE child (0) for packed, then AST_MULTIRANGE child (1) for unpacked // (updated: actually by the time we are here, AST_MULTIRANGE is converted into one big AST_RANGE) // case 0 handled by default - if ((id_ast->type == AST_WIRE || id_ast->type == AST_MEMORY) && id_ast->children.size() > 0) { + else if ((id_ast->type == AST_WIRE || id_ast->type == AST_MEMORY) && id_ast->children.size() > 0) { // handle packed array left/right for case 1, and cases 2/3 when requesting the last dimension (packed side) AstNode *wire_range = id_ast->children[0]; left = wire_range->children[0]->integer; @@ -3410,6 +3445,17 @@ skip_dynamic_range_lvalue_expansion:; low = min(left, right); } if (id_ast->type == AST_MEMORY) { + // a slice of our identifier means we advance to the next dimension, e.g. $size(a[3]) + if (buf->children.size() > 0) { + // something is hanging below this identifier + if (buf->children[0]->type == AST_RANGE && buf->integer == 0) + // if integer == 0, this node was originally created as AST_RANGE so it's dimension is 1 + dim++; + // more than one range, e.g. $size(a[3][2]) + else // created an AST_MULTIRANGE, converted to AST_RANGE, but original dimension saved in 'integer' field + dim += buf->integer; // increment by multirange size + } + // We got here only if the argument is a memory // Otherwise $size() and $bits() return the expression width AstNode *mem_range = id_ast->children[1]; @@ -3469,7 +3515,7 @@ skip_dynamic_range_lvalue_expansion:; result = right; else if (str == "\\$size") result = width; - else { + else { // str == "\\$bits" result = width * mem_depth; } newNode = mkconst_int(result, true); @@ -4691,7 +4737,7 @@ void AstNode::mem2reg_as_needed_pass1(dict<AstNode*, pool<std::string>> &mem2reg if (type == AST_MEMORY && (get_bool_attribute(ID::mem2reg) || (flags & AstNode::MEM2REG_FL_ALL) || !(is_reg || is_logic))) mem2reg_candidates[this] |= AstNode::MEM2REG_FL_FORCED; - if (type == AST_MODULE && get_bool_attribute(ID::mem2reg)) + if ((type == AST_MODULE || type == AST_INTERFACE) && get_bool_attribute(ID::mem2reg)) children_flags |= AstNode::MEM2REG_FL_ALL; dict<AstNode*, uint32_t> *proc_flags_p = NULL; diff --git a/frontends/verific/verific.cc b/frontends/verific/verific.cc index 8898c4597..ab3e55427 100644 --- a/frontends/verific/verific.cc +++ b/frontends/verific/verific.cc @@ -361,10 +361,16 @@ RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portn for (unsigned i = 0; i < portbus->Size(); i++) { Net *net = inst->GetNet(portbus->ElementAtIndex(i)); if (net) { - if (net->IsGnd()) - sig.append(RTLIL::State::S0); - else if (net->IsPwr()) - sig.append(RTLIL::State::S1); + if (net->IsConstant()) { + if (net->IsGnd()) + sig.append(RTLIL::State::S0); + else if (net->IsPwr()) + sig.append(RTLIL::State::S1); + else if (net->IsX()) + sig.append(RTLIL::State::Sx); + else + sig.append(RTLIL::State::Sz); + } else sig.append(net_map_at(net)); } else @@ -379,6 +385,36 @@ RTLIL::SigSpec VerificImporter::operatorInport(Instance *inst, const char *portn } } +RTLIL::SigSpec VerificImporter::operatorInportCase(Instance *inst, const char *portname) +{ + PortBus *portbus = inst->View()->GetPortBus(portname); + if (portbus) { + RTLIL::SigSpec sig; + for (unsigned i = 0; i < portbus->Size(); i++) { + Net *net = inst->GetNet(portbus->ElementAtIndex(i)); + if (net) { + if (net->IsConstant()) { + if (net->IsGnd()) + sig.append(RTLIL::State::S0); + else if (net->IsPwr()) + sig.append(RTLIL::State::S1); + else + sig.append(RTLIL::State::Sa); + } + else + sig.append(net_map_at(net)); + } else + sig.append(RTLIL::State::Sa); + } + return sig; + } else { + Port *port = inst->View()->GetPort(portname); + log_assert(port != NULL); + Net *net = inst->GetNet(port); + return net_map_at(net); + } +} + RTLIL::SigSpec VerificImporter::operatorOutput(Instance *inst, const pool<Net*, hash_ptr_ops> *any_all_nets) { RTLIL::SigSpec sig; @@ -989,6 +1025,75 @@ bool VerificImporter::import_netlist_instance_cells(Instance *inst, RTLIL::IdStr return true; } + if (inst->Type() == OPER_WIDE_CASE_SELECT_BOX) + { + RTLIL::SigSpec sig_out_val = operatorInport(inst, "out_value"); + RTLIL::SigSpec sig_select = operatorInport(inst, "select"); + RTLIL::SigSpec sig_select_values = operatorInportCase(inst, "select_values"); + RTLIL::SigSpec sig_data_values = operatorInport(inst, "data_values"); + RTLIL::SigSpec sig_data_default = operatorInport(inst, "default_value"); + + RTLIL::Process *proc = module->addProcess(new_verific_id(inst)); + import_attributes(proc->attributes, inst); + + RTLIL::CaseRule *current_case = &proc->root_case; + current_case = &proc->root_case; + + RTLIL::SwitchRule *sw = new RTLIL::SwitchRule; + sw->signal = sig_select; + current_case->switches.push_back(sw); + + unsigned select_width = inst->InputSize(); + unsigned data_width = inst->OutputSize(); + unsigned offset_data = 0; + unsigned offset_select = 0; + + OperWideCaseSelector* selector = (OperWideCaseSelector*) inst->View(); + + for (unsigned i = 0 ; i < selector->GetNumBranches() ; ++i) { + + SigSig action(sig_out_val, sig_data_values.extract(offset_data, data_width)); + offset_data += data_width; + + for (unsigned j = 0 ; j < selector->GetNumConditions(i) ; ++j) { + Array left_bound, right_bound ; + selector->GetCondition(i, j, &left_bound, &right_bound); + + SigSpec sel_left = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + if (right_bound.Size()) { + SigSpec sel_right = sig_select_values.extract(offset_select, select_width); + offset_select += select_width; + + log_assert(sel_right.is_fully_const() && sel_right.is_fully_def()); + log_assert(sel_left.is_fully_const() && sel_right.is_fully_def()); + + int32_t left = sel_left.as_int(); + int32_t right = sel_right.as_int(); + int width = sel_left.size(); + + for (int32_t i = right; i<left; i++) { + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(RTLIL::Const(i,width)); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } + } + + RTLIL::CaseRule *cs = new RTLIL::CaseRule; + cs->compare.push_back(sel_left); + cs->actions.push_back(action); + sw->cases.push_back(cs); + } + } + RTLIL::CaseRule *cs_default = new RTLIL::CaseRule; + cs_default->actions.push_back(SigSig(sig_out_val, sig_data_default)); + sw->cases.push_back(cs_default); + + return true; + } + #undef IN #undef IN1 #undef IN2 diff --git a/frontends/verific/verific.h b/frontends/verific/verific.h index d9f0077db..44485751c 100644 --- a/frontends/verific/verific.h +++ b/frontends/verific/verific.h @@ -87,6 +87,7 @@ struct VerificImporter RTLIL::SigSpec operatorInput1(Verific::Instance *inst); RTLIL::SigSpec operatorInput2(Verific::Instance *inst); RTLIL::SigSpec operatorInport(Verific::Instance *inst, const char *portname); + RTLIL::SigSpec operatorInportCase(Verific::Instance *inst, const char *portname); RTLIL::SigSpec operatorOutput(Verific::Instance *inst, const pool<Verific::Net*, hash_ptr_ops> *any_all_nets = nullptr); bool import_netlist_instance_gates(Verific::Instance *inst, RTLIL::IdString inst_name); |