mirror of
https://github.com/YosysHQ/yosys
synced 2025-04-13 04:28:18 +00:00
Implemented part/bit select on memory read
This commit is contained in:
parent
d248419fe0
commit
19dba2561e
1
README
1
README
|
@ -293,7 +293,6 @@ Roadmap / Large-scale TODOs
|
||||||
|
|
||||||
- Missing Verilog-2005 features to be implemented soon:
|
- Missing Verilog-2005 features to be implemented soon:
|
||||||
- Fix corner cases with contextual name lookup
|
- Fix corner cases with contextual name lookup
|
||||||
- Part select on memory read
|
|
||||||
- Indexed part selects
|
- Indexed part selects
|
||||||
|
|
||||||
- Technology mapping for real-world applications
|
- Technology mapping for real-world applications
|
||||||
|
|
|
@ -470,6 +470,55 @@ bool AstNode::simplify(bool const_fold, bool at_zero, bool in_lvalue, int stage,
|
||||||
id2ast = current_scope[str];
|
id2ast = current_scope[str];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// split memory access with bit select to individual statements
|
||||||
|
if (type == AST_IDENTIFIER && children.size() == 2 && children[0]->type == AST_RANGE && children[1]->type == AST_RANGE)
|
||||||
|
{
|
||||||
|
if (id2ast == NULL || id2ast->type != AST_MEMORY || children[0]->children.size() != 1)
|
||||||
|
log_error("Invalid bit-select on memory access at %s:%d!\n", filename.c_str(), linenum);
|
||||||
|
|
||||||
|
int mem_width, mem_size, addr_bits;
|
||||||
|
id2ast->meminfo(mem_width, mem_size, addr_bits);
|
||||||
|
|
||||||
|
std::stringstream sstr;
|
||||||
|
sstr << "$mem2bits$" << children[0]->str << "$" << filename << ":" << linenum << "$" << (RTLIL::autoidx++);
|
||||||
|
std::string wire_id = sstr.str();
|
||||||
|
|
||||||
|
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||||
|
wire->str = wire_id;
|
||||||
|
if (current_block)
|
||||||
|
wire->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
|
current_ast_mod->children.push_back(wire);
|
||||||
|
while (wire->simplify(true, false, false, 1, -1, false)) { }
|
||||||
|
|
||||||
|
AstNode *data = clone();
|
||||||
|
delete data->children[1];
|
||||||
|
data->children.pop_back();
|
||||||
|
|
||||||
|
AstNode *assign = new AstNode(AST_ASSIGN_EQ, new AstNode(AST_IDENTIFIER), data);
|
||||||
|
assign->children[0]->str = wire_id;
|
||||||
|
|
||||||
|
if (current_block)
|
||||||
|
{
|
||||||
|
size_t assign_idx = 0;
|
||||||
|
while (assign_idx < current_block->children.size() && current_block->children[assign_idx] != current_block_child)
|
||||||
|
assign_idx++;
|
||||||
|
log_assert(assign_idx < current_block->children.size());
|
||||||
|
current_block->children.insert(current_block->children.begin()+assign_idx, assign);
|
||||||
|
wire->is_reg = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AstNode *proc = new AstNode(AST_ALWAYS, new AstNode(AST_BLOCK));
|
||||||
|
proc->children[0]->children.push_back(assign);
|
||||||
|
current_ast_mod->children.push_back(proc);
|
||||||
|
}
|
||||||
|
|
||||||
|
newNode = new AstNode(AST_IDENTIFIER, children[1]->clone());
|
||||||
|
newNode->str = wire_id;
|
||||||
|
newNode->id2ast = wire;
|
||||||
|
goto apply_newNode;
|
||||||
|
}
|
||||||
|
|
||||||
// unroll for loops and generate-for blocks
|
// unroll for loops and generate-for blocks
|
||||||
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
|
if ((type == AST_GENFOR || type == AST_FOR) && children.size() != 0)
|
||||||
{
|
{
|
||||||
|
@ -1281,6 +1330,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
||||||
|
|
||||||
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
|
AstNode *wire_addr = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(addr_bits-1, true), mkconst_int(0, true)));
|
||||||
wire_addr->str = id_addr;
|
wire_addr->str = id_addr;
|
||||||
|
wire_addr->is_reg = true;
|
||||||
if (block)
|
if (block)
|
||||||
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_addr->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
mod->children.push_back(wire_addr);
|
mod->children.push_back(wire_addr);
|
||||||
|
@ -1288,6 +1338,7 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
||||||
|
|
||||||
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
AstNode *wire_data = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(mem_width-1, true), mkconst_int(0, true)));
|
||||||
wire_data->str = id_data;
|
wire_data->str = id_data;
|
||||||
|
wire_data->is_reg = true;
|
||||||
if (block)
|
if (block)
|
||||||
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
wire_data->attributes["\\nosync"] = AstNode::mkconst_int(1, false);
|
||||||
mod->children.push_back(wire_data);
|
mod->children.push_back(wire_data);
|
||||||
|
@ -1328,8 +1379,6 @@ void AstNode::mem2reg_as_needed_pass2(std::set<AstNode*> &mem2reg_set, AstNode *
|
||||||
assert(assign_idx < block->children.size());
|
assert(assign_idx < block->children.size());
|
||||||
block->children.insert(block->children.begin()+assign_idx, case_node);
|
block->children.insert(block->children.begin()+assign_idx, case_node);
|
||||||
block->children.insert(block->children.begin()+assign_idx, assign_addr);
|
block->children.insert(block->children.begin()+assign_idx, assign_addr);
|
||||||
wire_addr->is_reg = true;
|
|
||||||
wire_data->is_reg = true;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -105,7 +105,7 @@ static void free_attr(std::map<std::string, AstNode*> *al)
|
||||||
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
%token TOK_SYNOPSYS_FULL_CASE TOK_SYNOPSYS_PARALLEL_CASE
|
||||||
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
%token TOK_SUPPLY0 TOK_SUPPLY1 TOK_TO_SIGNED TOK_TO_UNSIGNED
|
||||||
|
|
||||||
%type <ast> wire_type range expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
%type <ast> wire_type range non_opt_range expr basic_expr concat_list rvalue lvalue lvalue_concat_list
|
||||||
%type <string> opt_label tok_prim_wrapper hierarchical_id
|
%type <string> opt_label tok_prim_wrapper hierarchical_id
|
||||||
%type <boolean> opt_signed
|
%type <boolean> opt_signed
|
||||||
%type <al> attr
|
%type <al> attr
|
||||||
|
@ -330,7 +330,7 @@ wire_type_token:
|
||||||
astbuf3->is_signed = true;
|
astbuf3->is_signed = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
range:
|
non_opt_range:
|
||||||
'[' expr ':' expr ']' {
|
'[' expr ':' expr ']' {
|
||||||
$$ = new AstNode(AST_RANGE);
|
$$ = new AstNode(AST_RANGE);
|
||||||
$$->children.push_back($2);
|
$$->children.push_back($2);
|
||||||
|
@ -339,6 +339,11 @@ range:
|
||||||
'[' expr ']' {
|
'[' expr ']' {
|
||||||
$$ = new AstNode(AST_RANGE);
|
$$ = new AstNode(AST_RANGE);
|
||||||
$$->children.push_back($2);
|
$$->children.push_back($2);
|
||||||
|
};
|
||||||
|
|
||||||
|
range:
|
||||||
|
non_opt_range {
|
||||||
|
$$ = $1;
|
||||||
} |
|
} |
|
||||||
/* empty */ {
|
/* empty */ {
|
||||||
$$ = NULL;
|
$$ = NULL;
|
||||||
|
@ -893,6 +898,11 @@ rvalue:
|
||||||
$$ = new AstNode(AST_IDENTIFIER, $2);
|
$$ = new AstNode(AST_IDENTIFIER, $2);
|
||||||
$$->str = *$1;
|
$$->str = *$1;
|
||||||
delete $1;
|
delete $1;
|
||||||
|
} |
|
||||||
|
hierarchical_id non_opt_range non_opt_range {
|
||||||
|
$$ = new AstNode(AST_IDENTIFIER, $2, $3);
|
||||||
|
$$->str = *$1;
|
||||||
|
delete $1;
|
||||||
};
|
};
|
||||||
|
|
||||||
lvalue:
|
lvalue:
|
||||||
|
|
|
@ -17,3 +17,44 @@ always @(posedge clk)
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
// ----------------------------------------------------------
|
||||||
|
|
||||||
|
module test02(clk, setA, setB, addr, bit, y1, y2, y3, y4);
|
||||||
|
|
||||||
|
input clk, setA, setB;
|
||||||
|
input [1:0] addr;
|
||||||
|
input [2:0] bit;
|
||||||
|
output reg y1, y2;
|
||||||
|
output y3, y4;
|
||||||
|
|
||||||
|
reg [7:0] mem1 [3:0];
|
||||||
|
|
||||||
|
(* mem2reg *)
|
||||||
|
reg [7:0] mem2 [3:0];
|
||||||
|
|
||||||
|
always @(posedge clk) begin
|
||||||
|
if (setA) begin
|
||||||
|
mem1[0] <= 10;
|
||||||
|
mem1[1] <= 20;
|
||||||
|
mem1[2] <= 30;
|
||||||
|
mem2[0] <= 17;
|
||||||
|
mem2[1] <= 27;
|
||||||
|
mem2[2] <= 37;
|
||||||
|
end
|
||||||
|
if (setB) begin
|
||||||
|
mem1[0] <= 1;
|
||||||
|
mem1[1] <= 2;
|
||||||
|
mem1[2] <= 3;
|
||||||
|
mem2[0] <= 71;
|
||||||
|
mem2[1] <= 72;
|
||||||
|
mem2[2] <= 73;
|
||||||
|
end
|
||||||
|
y1 <= mem1[addr][bit];
|
||||||
|
y2 <= mem2[addr][bit];
|
||||||
|
end
|
||||||
|
|
||||||
|
assign y3 = mem1[addr][bit];
|
||||||
|
assign y4 = mem2[addr][bit];
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue