mirror of https://github.com/YosysHQ/yosys.git
Added "via_celltype" attribute on task/func
This commit is contained in:
parent
6f33fc3e87
commit
640d9fc551
27
README
27
README
|
@ -290,6 +290,33 @@ Verilog Attributes and non-standard features
|
|||
assign b = 42;
|
||||
"""
|
||||
|
||||
- The attribute "via_celltype" can be used to implement a verilog task or
|
||||
function by instantiating the specified cell type. The value is the name
|
||||
of the cell type to use. For functions the name of the output port can
|
||||
be specified by appending it to the cell type separated by a whitespace.
|
||||
The body of the task or function is unused in this case and can be used
|
||||
to specify a behavioral model of the cell type for simulation. For example:
|
||||
|
||||
module my_add3(A, B, C, Y);
|
||||
parameter WIDTH = 8;
|
||||
input [WIDTH-1:0] A, B, C;
|
||||
output [WIDTH-1:0] Y;
|
||||
...
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
...
|
||||
(* via_celltype = "my_add3 Y" *)
|
||||
(* via_celltype_defparam_WIDTH = 32 *)
|
||||
function [31:0] add3;
|
||||
input [31:0] A, B, C;
|
||||
begin
|
||||
add3 = A + B + C;
|
||||
end
|
||||
endfunction
|
||||
...
|
||||
endmodule
|
||||
|
||||
- Sized constants (the syntax <size>'s?[bodh]<value>) support constant
|
||||
expressions as <size>. If the expresion is not a simple identifier, it
|
||||
must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010
|
||||
|
|
|
@ -1450,9 +1450,15 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
log_error("Can't resolve task name `%s' at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
|
||||
AstNode *decl = current_scope[str];
|
||||
|
||||
std::stringstream sstr;
|
||||
sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$";
|
||||
std::string prefix = sstr.str();
|
||||
|
||||
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)
|
||||
if ((in_param || recommend_const_eval || require_const_eval) && !decl->attributes.count("\\via_celltype"))
|
||||
{
|
||||
bool all_args_const = true;
|
||||
for (auto child : children) {
|
||||
|
@ -1474,11 +1480,6 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
log_error("Function %s can only be called with constant arguments at %s:%d.\n", str.c_str(), filename.c_str(), linenum);
|
||||
}
|
||||
|
||||
AstNode *decl = current_scope[str];
|
||||
std::stringstream sstr;
|
||||
sstr << "$func$" << str << "$" << filename << ":" << linenum << "$" << (autoidx++) << "$";
|
||||
std::string prefix = sstr.str();
|
||||
|
||||
size_t arg_count = 0;
|
||||
std::map<std::string, std::string> replace_rules;
|
||||
|
||||
|
@ -1510,6 +1511,68 @@ skip_dynamic_range_lvalue_expansion:;
|
|||
goto replace_fcall_with_id;
|
||||
}
|
||||
|
||||
if (decl->attributes.count("\\via_celltype"))
|
||||
{
|
||||
std::string celltype = decl->attributes.at("\\via_celltype")->asAttrConst().decode_string();
|
||||
std::string outport = str;
|
||||
|
||||
if (celltype.find(' ') != std::string::npos) {
|
||||
int pos = celltype.find(' ');
|
||||
outport = RTLIL::escape_id(celltype.substr(pos+1));
|
||||
celltype = RTLIL::escape_id(celltype.substr(0, pos));
|
||||
} else
|
||||
celltype = RTLIL::escape_id(celltype);
|
||||
|
||||
AstNode *cell = new AstNode(AST_CELL, new AstNode(AST_CELLTYPE));
|
||||
cell->str = prefix.substr(0, SIZE(prefix)-1);
|
||||
cell->children[0]->str = celltype;
|
||||
|
||||
for (auto attr : decl->attributes)
|
||||
if (attr.first.str().rfind("\\via_celltype_defparam_", 0) == 0)
|
||||
{
|
||||
AstNode *cell_arg = new AstNode(AST_PARASET, attr.second->clone());
|
||||
cell_arg->str = RTLIL::escape_id(attr.first.str().substr(strlen("\\via_celltype_defparam_")));
|
||||
cell->children.push_back(cell_arg);
|
||||
}
|
||||
|
||||
for (auto child : decl->children)
|
||||
if (child->type == AST_WIRE && (child->is_input || child->is_output || (type == AST_FCALL && child->str == str)))
|
||||
{
|
||||
AstNode *wire = child->clone();
|
||||
wire->str = prefix + wire->str;
|
||||
wire->port_id = 0;
|
||||
wire->is_input = false;
|
||||
wire->is_output = false;
|
||||
current_ast_mod->children.push_back(wire);
|
||||
while (wire->simplify(true, false, false, 1, -1, false, false)) { }
|
||||
|
||||
AstNode *wire_id = new AstNode(AST_IDENTIFIER);
|
||||
wire_id->str = wire->str;
|
||||
|
||||
if ((child->is_input || child->is_output) && arg_count < children.size())
|
||||
{
|
||||
AstNode *arg = children[arg_count++]->clone();
|
||||
AstNode *assign = child->is_input ?
|
||||
new AstNode(AST_ASSIGN_EQ, wire_id, arg) :
|
||||
new AstNode(AST_ASSIGN_EQ, arg, wire_id);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
AstNode *cell_arg = new AstNode(AST_ARGUMENT, wire_id->clone());
|
||||
cell_arg->str = child->str == str ? outport : child->str;
|
||||
cell->children.push_back(cell_arg);
|
||||
}
|
||||
|
||||
current_ast_mod->children.push_back(cell);
|
||||
goto replace_fcall_with_id;
|
||||
}
|
||||
|
||||
for (auto child : decl->children)
|
||||
if (child->type == AST_WIRE)
|
||||
{
|
||||
|
|
|
@ -407,33 +407,35 @@ module_body_stmt:
|
|||
always_stmt | TOK_GENERATE module_gen_body TOK_ENDGENERATE | defattr | assert_property;
|
||||
|
||||
task_func_decl:
|
||||
TOK_TASK TOK_ID ';' {
|
||||
attr TOK_TASK TOK_ID ';' {
|
||||
current_function_or_task = new AstNode(AST_TASK);
|
||||
current_function_or_task->str = *$2;
|
||||
current_function_or_task->str = *$3;
|
||||
append_attr(current_function_or_task, $1);
|
||||
ast_stack.back()->children.push_back(current_function_or_task);
|
||||
ast_stack.push_back(current_function_or_task);
|
||||
current_function_or_task_port_id = 1;
|
||||
delete $2;
|
||||
delete $3;
|
||||
} task_func_body TOK_ENDTASK {
|
||||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
} |
|
||||
TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
|
||||
attr TOK_FUNCTION opt_signed range_or_signed_int TOK_ID ';' {
|
||||
current_function_or_task = new AstNode(AST_FUNCTION);
|
||||
current_function_or_task->str = *$4;
|
||||
current_function_or_task->str = *$5;
|
||||
append_attr(current_function_or_task, $1);
|
||||
ast_stack.back()->children.push_back(current_function_or_task);
|
||||
ast_stack.push_back(current_function_or_task);
|
||||
AstNode *outreg = new AstNode(AST_WIRE);
|
||||
outreg->str = *$4;
|
||||
outreg->is_signed = $2;
|
||||
if ($3 != NULL) {
|
||||
outreg->children.push_back($3);
|
||||
outreg->is_signed = $2 || $3->is_signed;
|
||||
$3->is_signed = false;
|
||||
outreg->str = *$5;
|
||||
outreg->is_signed = $3;
|
||||
if ($4 != NULL) {
|
||||
outreg->children.push_back($4);
|
||||
outreg->is_signed = $3 || $4->is_signed;
|
||||
$4->is_signed = false;
|
||||
}
|
||||
current_function_or_task->children.push_back(outreg);
|
||||
current_function_or_task_port_id = 1;
|
||||
delete $4;
|
||||
delete $5;
|
||||
} task_func_body TOK_ENDFUNCTION {
|
||||
current_function_or_task = NULL;
|
||||
ast_stack.pop_back();
|
||||
|
|
Loading…
Reference in New Issue