From 640d9fc551c546b511f8d64c0ccfc438937164a1 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Mon, 18 Aug 2014 14:29:30 +0200 Subject: [PATCH] Added "via_celltype" attribute on task/func --- README | 27 ++++++++++++++ frontends/ast/simplify.cc | 75 +++++++++++++++++++++++++++++++++++--- frontends/verilog/parser.y | 26 +++++++------ 3 files changed, 110 insertions(+), 18 deletions(-) diff --git a/README b/README index 1ecaa07df..a0e67e8a4 100644 --- a/README +++ b/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 's?[bodh]) support constant expressions as . If the expresion is not a simple identifier, it must be put in parentheses. Examples: WIDTH'd42, (4+2)'b101010 diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc index 85671213d..2572fa4a9 100644 --- a/frontends/ast/simplify.cc +++ b/frontends/ast/simplify.cc @@ -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 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) { diff --git a/frontends/verilog/parser.y b/frontends/verilog/parser.y index f619d3c2b..bf9b21bb6 100644 --- a/frontends/verilog/parser.y +++ b/frontends/verilog/parser.y @@ -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(); -- 2.30.2