3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2025-04-27 02:45:52 +00:00

Support for SystemVerilog interfaces as a port in the top level module + test case

This commit is contained in:
Ruben Undheim 2018-10-20 11:58:25 +02:00
parent d9a4381012
commit 397dfccb30
9 changed files with 561 additions and 10 deletions

View file

@ -904,7 +904,7 @@ RTLIL::Const AstNode::realAsConst(int width)
}
// create a new AstModule from an AST_MODULE AST node
static AstModule* process_module(AstNode *ast, bool defer)
static AstModule* process_module(AstNode *ast, bool defer, AstNode *original_ast = NULL)
{
log_assert(ast->type == AST_MODULE || ast->type == AST_INTERFACE);
@ -920,7 +920,11 @@ static AstModule* process_module(AstNode *ast, bool defer)
current_module->set_bool_attribute("\\cells_not_processed");
current_ast_mod = ast;
AstNode *ast_before_simplify = ast->clone();
AstNode *ast_before_simplify;
if (original_ast != NULL)
ast_before_simplify = original_ast;
else
ast_before_simplify = ast->clone();
if (flag_dump_ast1) {
log("Dumping Verilog AST before simplification:\n");
@ -1105,6 +1109,104 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT
}
}
AstNode *ast_before_replacing_interface_ports = new_ast->clone();
// Explode all interface ports. Note this will only have any effect on top
// level modules. Other sub-modules will have their interface ports
// exploded in derive(..)
for (size_t i =0; i<new_ast->children.size(); i++)
{
AstNode *ch2 = new_ast->children[i];
std::string interface_type = "";
std::string interface_modport = "";
if (ch2->type == AST_INTERFACEPORT) {
std::string name_port = ch2->str;
if (ch2->children.size() > 0) {
for(size_t j=0; j<ch2->children.size();j++) {
AstNode *ch = ch2->children[j];
if(ch->type == AST_INTERFACEPORTTYPE) {
std::string name_type = ch->str;
size_t ndots = std::count(name_type.begin(), name_type.end(), '.');
// Separate the interface instance name from any modports:
if (ndots == 0) { // Does not have modport
interface_type = name_type;
}
else {
std::stringstream name_type_stream(name_type);
std::string segment;
std::vector<std::string> seglist;
while(std::getline(name_type_stream, segment, '.')) {
seglist.push_back(segment);
}
if (ndots == 1) { // Has modport
interface_type = seglist[0];
interface_modport = seglist[1];
}
else { // Erroneous port type
log_error("More than two '.' in signal port type (%s)\n", name_type.c_str());
}
}
if (design->modules_.count(interface_type) > 0) {
AstNode *celltype_for_intf = new AstNode(AST_CELLTYPE);
celltype_for_intf->str = interface_type;
AstNode *cell_for_intf = new AstNode(AST_CELL, celltype_for_intf);
cell_for_intf->str = name_port + "_inst_from_top_dummy";
new_ast->children.push_back(cell_for_intf);
RTLIL::Module *intfmodule = design->modules_[interface_type];
AstModule *ast_module_of_interface = (AstModule*)intfmodule;
AstNode *ast_node_of_interface = ast_module_of_interface->ast;
AstNode *modport = NULL;
std::string interface_modport_compare_str = "\\" + interface_modport;
for (auto &chm : ast_node_of_interface->children) {
if (chm->type == AST_MODPORT) {
if (chm->str == interface_modport_compare_str) { // Modport found
modport = chm;
}
}
}
std::string intfname = name_port;
for (auto &wire_it : intfmodule->wires_){
AstNode *wire = new AstNode(AST_WIRE, new AstNode(AST_RANGE, AstNode::mkconst_int(wire_it.second->width -1, true), AstNode::mkconst_int(0, true)));
std::string origname = log_id(wire_it.first);
std::string newname = intfname + "." + origname;
wire->str = newname;
if (modport != NULL) {
bool found_in_modport = false;
// Search for the current wire in the wire list for the current modport
for (auto &ch : modport->children) {
if (ch->type == AST_MODPORTMEMBER) {
std::string compare_name = "\\" + origname;
if (ch->str == compare_name) { // Found signal. The modport decides whether it is input or output
found_in_modport = true;
wire->is_input = ch->is_input;
wire->is_output = ch->is_output;
break;
}
}
}
if (found_in_modport) {
new_ast->children.push_back(wire);
}
else { // If not found in modport, do not create port
delete wire;
}
}
else { // If no modport, set inout
wire->is_input = true;
wire->is_output = true;
new_ast->children.push_back(wire);
}
}
}
}
}
}
}
}
// The old module will be deleted. Rename and mark for deletion:
std::string original_name = this->name.str();
std::string changed_name = original_name + "_before_replacing_local_interfaces";
@ -1119,7 +1221,7 @@ void AstModule::reprocess_module(RTLIL::Design *design, dict<RTLIL::IdString, RT
}
// Generate RTLIL from AST for the new module and add to the design:
AstModule *newmod = process_module(new_ast, false);
AstModule *newmod = process_module(new_ast, false, ast_before_replacing_interface_ports);
delete(new_ast);
design->add(newmod);
RTLIL::Module* mod = design->module(original_name);