Added "via_celltype" attribute on task/func

This commit is contained in:
Clifford Wolf 2014-08-18 14:29:30 +02:00
parent 6f33fc3e87
commit 640d9fc551
3 changed files with 110 additions and 18 deletions

27
README
View File

@ -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

View File

@ -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)
{

View File

@ -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();