mirror of https://github.com/YosysHQ/yosys.git
Handling of attributes for struct / union variables
(* nowrshmsk *) on a struct / union variable now affects dynamic bit slice assignments to members of the struct / union. (* nowrshmsk *) can in some cases yield significant resource savings; the combination of pipeline shifting and indexed writes is an example of this. Constructs similar to the one below can benefit from (* nowrshmsk *), and in addition it is no longer necessary to split out the shift assignments on separate lines in order to avoid the error message "ERROR: incompatible mix of lookahead and non-lookahead IDs in LHS expression." always_ff @(posedge clk) begin if (rotate) begin { v5, v4, v3, v2, v1, v0 } <= { v4, v3, v2, v1, v0, v5 }; if (res) begin v0.bytes <= '0; end else if (w) begin v0.bytes[addr] <= data; end end end
This commit is contained in:
parent
cee3cb31b9
commit
ad437c178d
|
@ -557,7 +557,7 @@ static int get_max_offset(AstNode *node)
|
|||
return node->range_left;
|
||||
}
|
||||
|
||||
static AstNode *make_packed_struct(AstNode *template_node, std::string &name)
|
||||
static AstNode *make_packed_struct(AstNode *template_node, std::string &name, decltype(AstNode::attributes) &attributes)
|
||||
{
|
||||
// create a wire for the packed struct
|
||||
auto wnode = new AstNode(AST_WIRE);
|
||||
|
@ -565,6 +565,9 @@ static AstNode *make_packed_struct(AstNode *template_node, std::string &name)
|
|||
wnode->is_logic = true;
|
||||
wnode->range_valid = true;
|
||||
wnode->is_signed = template_node->is_signed;
|
||||
for (auto &pair : attributes) {
|
||||
wnode->attributes[pair.first] = pair.second->clone();
|
||||
}
|
||||
int offset = get_max_offset(template_node);
|
||||
auto range = make_range(offset, 0);
|
||||
wnode->children.push_back(range);
|
||||
|
@ -1368,7 +1371,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
// instance rather than just a type in a typedef or outer struct?
|
||||
if (!str.empty() && str[0] == '\\') {
|
||||
// instance so add a wire for the packed structure
|
||||
auto wnode = make_packed_struct(this, str);
|
||||
auto wnode = make_packed_struct(this, str, attributes);
|
||||
log_assert(current_ast_mod);
|
||||
current_ast_mod->children.push_back(wnode);
|
||||
}
|
||||
|
@ -1792,7 +1795,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
|
||||
if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
|
||||
// replace with wire representing the packed structure
|
||||
newNode = make_packed_struct(template_node, str);
|
||||
newNode = make_packed_struct(template_node, str, attributes);
|
||||
newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str);
|
||||
// add original input/output attribute to resolved wire
|
||||
newNode->is_input = this->is_input;
|
||||
|
@ -1857,7 +1860,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
|
||||
if (template_node->type == AST_STRUCT || template_node->type == AST_UNION) {
|
||||
// replace with wire representing the packed structure
|
||||
newNode = make_packed_struct(template_node, str);
|
||||
newNode = make_packed_struct(template_node, str, attributes);
|
||||
newNode->attributes[ID::wiretype] = mkconst_str(resolved_type_node->str);
|
||||
newNode->type = type;
|
||||
current_scope[str] = this;
|
||||
|
@ -2709,11 +2712,23 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
int source_width = children[0]->id2ast->range_left - children[0]->id2ast->range_right + 1;
|
||||
int source_offset = children[0]->id2ast->range_right;
|
||||
int result_width = 1;
|
||||
int stride = 1;
|
||||
AST::AstNode *member_node = get_struct_member(children[0]);
|
||||
if (member_node) {
|
||||
// Clamp chunk to range of member within struct/union.
|
||||
log_assert(!source_offset && !children[0]->id2ast->range_swapped);
|
||||
source_width = member_node->range_left - member_node->range_right + 1;
|
||||
|
||||
// When the (* nowrshmsk *) attribute is set, a CASE block is generated below
|
||||
// to select the indexed bit slice. When a multirange array is indexed, the
|
||||
// start of each possible slice is separated by the bit stride of the last
|
||||
// index dimension, and we can optimize the CASE block accordingly.
|
||||
// The dimension of the original array expression is saved in the 'integer' field.
|
||||
int dims = children[0]->integer;
|
||||
stride = source_width;
|
||||
for (int dim = 0; dim < dims; dim++) {
|
||||
stride /= get_struct_range_width(member_node, dim);
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *shift_expr = NULL;
|
||||
|
@ -2754,7 +2769,7 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
|||
|
||||
did_something = true;
|
||||
newNode = new AstNode(AST_CASE, shift_expr);
|
||||
for (int i = 0; i < source_width; i++) {
|
||||
for (int i = 0; i < source_width; i += stride) {
|
||||
int start_bit = source_offset + i;
|
||||
int end_bit = std::min(start_bit+result_width,source_width) - 1;
|
||||
AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true));
|
||||
|
|
|
@ -1809,7 +1809,12 @@ enum_decl: enum_type enum_var_list ';' { delete $1; }
|
|||
// struct or union
|
||||
//////////////////
|
||||
|
||||
struct_decl: struct_type struct_var_list ';' { delete astbuf2; }
|
||||
struct_decl:
|
||||
attr struct_type {
|
||||
append_attr($2, $1);
|
||||
} struct_var_list ';' {
|
||||
delete astbuf2;
|
||||
}
|
||||
;
|
||||
|
||||
struct_type: struct_union { astbuf2 = $1; } struct_body { $$ = astbuf2; }
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/*.log
|
||||
/*.out
|
||||
/run-test.mk
|
||||
/temp
|
||||
|
|
|
@ -4,7 +4,7 @@ module range_shift_mask(
|
|||
input logic [2:0] addr_o,
|
||||
output logic [7:0] data_o
|
||||
);
|
||||
// (* nowrshmsk = 0 *)
|
||||
(* nowrshmsk = 0 *)
|
||||
struct packed {
|
||||
logic [7:0] msb;
|
||||
logic [0:3][7:0] data;
|
||||
|
@ -24,7 +24,7 @@ module range_case(
|
|||
input logic [2:0] addr_o,
|
||||
output logic [7:0] data_o
|
||||
);
|
||||
// (* nowrshmsk = 1 *)
|
||||
(* nowrshmsk = 1 *)
|
||||
struct packed {
|
||||
logic [7:0] msb;
|
||||
logic [0:3][7:0] data;
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
! mkdir -p temp
|
||||
read_verilog -sv struct_dynamic_range.sv
|
||||
write_rtlil temp/struct_dynamic_range.il
|
||||
! grep -F -q ' cell $shift ' temp/struct_dynamic_range.il
|
||||
! grep -F -q ' switch $mul' temp/struct_dynamic_range.il
|
||||
prep -top top
|
||||
flatten
|
||||
sat -enable_undef -verify -prove-asserts
|
||||
|
|
Loading…
Reference in New Issue