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

View File

@ -146,6 +146,17 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
std::map<RTLIL::Cell*, std::pair<int, int>> array_cells;
std::string filename;
bool has_interface_ports = false;
// If any of the ports are actually interface ports, we will always need to
// reprocess the module:
if(!module->get_bool_attribute("\\interfaces_replaced_in_module")) {
for (auto &wire : module->wires_) {
if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface"))
has_interface_ports = true;
}
}
// Always keep track of all derived interfaces available in the current module in 'interfaces_in_module':
dict<RTLIL::IdString, RTLIL::Module*> interfaces_in_module;
for (auto &cell_it : module->cells_)
@ -244,8 +255,14 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
RTLIL::IdString interface_name = interface_name_str;
bool not_found_interface = false;
if(module->get_bool_attribute("\\interfaces_replaced_in_module")) { // If 'interfaces' in the cell have not be been handled yet, there is no need to derive the sub-module either
if (interfaces_in_module.count(interface_name) > 0) { // Check if the interface instance is present in module
RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name);
int nexactmatch = interfaces_in_module.count(interface_name) > 0;
std::string interface_name_str2 = interface_name_str + "_inst_from_top_dummy";
RTLIL::IdString interface_name2 = interface_name_str2;
int nmatch2 = interfaces_in_module.count(interface_name2) > 0;
if (nexactmatch > 0 || nmatch2 > 0) { // Check if the interface instance is present in module
if (nexactmatch != 0)
interface_name2 = interface_name;
RTLIL::Module *mod_replace_ports = interfaces_in_module.at(interface_name2);
for (auto &mod_wire : mod_replace_ports->wires_) { // Go over all wires in interface, and add replacements to lists.
std::string signal_name1 = conn.first.str() + "." + log_id(mod_wire.first);
std::string signal_name2 = interface_name.str() + "." + log_id(mod_wire.first);
@ -259,7 +276,7 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
}
}
connections_to_remove.push_back(conn.first);
interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name);
interfaces_to_add_to_submodule[conn.first] = interfaces_in_module.at(interface_name2);
// Add modports to a dict which will be passed to AstModule::derive
if (interface_modport != "") {
@ -363,8 +380,8 @@ bool expand_module(RTLIL::Design *design, RTLIL::Module *module, bool flag_check
module->attributes.erase("\\cells_not_processed");
// If any interface instances were found in the module, we need to rederive it completely:
if (interfaces_in_module.size() > 0 && !module->get_bool_attribute("\\interfaces_replaced_in_module")) {
// If any interface instances or interface ports were found in the module, we need to rederive it completely:
if ((interfaces_in_module.size() > 0 || has_interface_ports) && !module->get_bool_attribute("\\interfaces_replaced_in_module")) {
module->reprocess_module(design, interfaces_in_module);
return did_something;
}
@ -438,6 +455,20 @@ void hierarchy_clean(RTLIL::Design *design, RTLIL::Module *top, bool purge_lib)
for (auto &it : design->modules_)
if (used.count(it.second) == 0)
del_modules.push_back(it.second);
else {
// Now all interface ports must have been exploded, and it is hence
// safe to delete all of the remaining dummy interface ports:
pool<RTLIL::Wire*> del_wires;
for(auto &wire : it.second->wires_) {
if ((wire.second->port_input || wire.second->port_output) && wire.second->get_bool_attribute("\\is_interface")) {
del_wires.insert(wire.second);
}
}
if (del_wires.size() > 0) {
it.second->remove(del_wires);
it.second->fixup_ports();
}
}
int del_counter = 0;
for (auto mod : del_modules) {

View File

@ -3,3 +3,4 @@
./runone.sh svinterface1
./runone.sh svinterface_at_top

View File

@ -22,11 +22,14 @@ iverilog -g2012 ${TESTNAME}_syn.v
iverilog -g2012 ${TESTNAME}_ref_syn.v
set +e
iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_ref_syn.v
./a.out
mv output.txt reference_result.txt
iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_syn.v
if [ -f ${TESTNAME}_wrapper.v ] ; then
iverilog -g2012 ${TESTNAME}_tb_wrapper.v ${TESTNAME}_syn.v
else
iverilog -g2012 ${TESTNAME}_tb.v ${TESTNAME}_syn.v
fi
./a.out
mv output.txt dut_result.txt

View File

@ -0,0 +1,125 @@
module TopModule(
input logic clk,
input logic rst,
output logic [21:0] outOther,
input logic [1:0] sig,
input logic flip,
output logic [1:0] sig_out,
MyInterface.submodule1 interfaceInstanceAtTop,
output logic [15:0] passThrough);
MyInterface #(.WIDTH(4)) MyInterfaceInstance();
SubModule1 u_SubModule1 (
.clk(clk),
.rst(rst),
.u_MyInterface(MyInterfaceInstance),
.u_MyInterfaceFromTop(interfaceInstanceAtTop),
.outOther(outOther),
.sig (sig)
);
assign sig_out = MyInterfaceInstance.mysig_out;
assign MyInterfaceInstance.setting = flip;
assign passThrough = MyInterfaceInstance.passThrough;
endmodule
interface MyInterface #(
parameter WIDTH = 3)(
);
logic setting;
logic [WIDTH-1:0] other_setting;
logic [1:0] mysig_out;
logic [15:0] passThrough;
modport submodule1 (
input setting,
output other_setting,
output mysig_out,
output passThrough
);
modport submodule2 (
input setting,
output other_setting,
input mysig_out,
output passThrough
);
endinterface
module SubModule1(
input logic clk,
input logic rst,
MyInterface.submodule1 u_MyInterface,
MyInterface.submodule1 u_MyInterfaceFromTop,
input logic [1:0] sig,
output logic [21:0] outOther
);
always_ff @(posedge clk or posedge rst)
if(rst)
u_MyInterface.mysig_out <= 0;
else begin
if(u_MyInterface.setting)
u_MyInterface.mysig_out <= sig;
else
u_MyInterface.mysig_out <= ~sig;
end
MyInterface #(.WIDTH(22)) MyInterfaceInstanceInSub();
SubModule2 u_SubModule2 (
.clk(clk),
.rst(rst),
.u_MyInterfaceFromTopDown(u_MyInterfaceFromTop),
.u_MyInterfaceInSub2(u_MyInterface),
.u_MyInterfaceInSub3(MyInterfaceInstanceInSub)
);
assign outOther = MyInterfaceInstanceInSub.other_setting;
assign MyInterfaceInstanceInSub.setting = 0;
assign MyInterfaceInstanceInSub.mysig_out = sig;
endmodule
module SubModule2(
input logic clk,
input logic rst,
MyInterface.submodule2 u_MyInterfaceInSub2,
MyInterface.submodule1 u_MyInterfaceFromTopDown,
MyInterface.submodule2 u_MyInterfaceInSub3
);
assign u_MyInterfaceFromTopDown.mysig_out = u_MyInterfaceFromTop.setting ? 10 : 20;
always_comb begin
if (u_MyInterfaceInSub3.mysig_out == 2'b00)
u_MyInterfaceInSub3.other_setting[21:0] = 1000;
else if (u_MyInterfaceInSub3.mysig_out == 2'b01)
u_MyInterfaceInSub3.other_setting[21:0] = 2000;
else if (u_MyInterfaceInSub3.mysig_out == 2'b10)
u_MyInterfaceInSub3.other_setting[21:0] = 3000;
else
u_MyInterfaceInSub3.other_setting[21:0] = 4000;
end
assign u_MyInterfaceInSub2.passThrough[7:0] = 124;
assign u_MyInterfaceInSub2.passThrough[15:8] = 200;
endmodule

View File

@ -0,0 +1,120 @@
module TopModule(
input logic clk,
input logic rst,
input logic [1:0] sig,
input logic flip,
output logic [15:0] passThrough,
output logic [21:0] outOther,
input logic interfaceInstanceAtTop_setting,
output logic [2:0] interfaceInstanceAtTop_other_setting,
output logic [1:0] interfaceInstanceAtTop_mysig_out,
output logic [15:0] interfaceInstanceAtTop_passThrough,
output logic [1:0] sig_out);
logic MyInterfaceInstance_setting;
logic [3:0] MyInterfaceInstance_other_setting;
logic [1:0] MyInterfaceInstance_mysig_out;
SubModule1 u_SubModule1 (
.clk(clk),
.rst(rst),
.u_MyInterface_setting(MyInterfaceInstance_setting),
.u_MyInterface_mysig_out(MyInterfaceInstance_mysig_out),
.u_MyInterface_other_setting(MyInterfaceInstance_other_setting),
.u_MyInterfaceFromTop_setting(interfaceInstanceAtTop_setting),
.u_MyInterfaceFromTop_other_setting(interfaceInstanceAtTop_other_setting),
.u_MyInterfaceFromTop_mysig_out(interfaceInstanceAtTop_mysig_out),
.u_MyInterfaceFromTop_passThrough(interfaceInstanceAtTop_passThrough),
.outOther(outOther),
.passThrough (passThrough),
.sig (sig)
);
assign sig_out = MyInterfaceInstance_mysig_out;
assign MyInterfaceInstance_setting = flip;
endmodule
module SubModule1(
input logic clk,
input logic rst,
input logic u_MyInterface_setting,
output logic [3:0] u_MyInterface_other_setting,
output logic [1:0] u_MyInterface_mysig_out,
output logic [21:0] outOther,
input logic [1:0] sig,
input logic u_MyInterfaceFromTop_setting,
output logic [2:0] u_MyInterfaceFromTop_other_setting,
output logic [1:0] u_MyInterfaceFromTop_mysig_out,
output logic [14:0] u_MyInterfaceFromTop_passThrough,
output logic [15:0] passThrough
);
always @(posedge clk or posedge rst)
if(rst)
u_MyInterface_mysig_out <= 0;
else begin
if(u_MyInterface_setting)
u_MyInterface_mysig_out <= sig;
else
u_MyInterface_mysig_out <= ~sig;
end
logic MyInterfaceInstanceInSub_setting;
logic [21:0] MyInterfaceInstanceInSub_other_setting;
logic [1:0] MyInterfaceInstanceInSub_mysig_out;
assign u_MyInterfaceFromTop_mysig_out = u_MyInterfaceFromTop_setting ? 10 : 20;
SubModule2 u_SubModule2 (
.clk(clk),
.rst(rst),
.u_MyInterfaceInSub2_setting(u_MyInterface_setting),
.u_MyInterfaceInSub2_mysig_out(u_MyInterface_mysig_out),
.u_MyInterfaceInSub2_other_setting(u_MyInterface_other_setting),
.u_MyInterfaceInSub3_setting(MyInterfaceInstanceInSub_setting),
.u_MyInterfaceInSub3_mysig_out(MyInterfaceInstanceInSub_mysig_out),
.u_MyInterfaceInSub3_other_setting(MyInterfaceInstanceInSub_other_setting),
.passThrough (passThrough)
);
assign outOther = MyInterfaceInstanceInSub_other_setting;
assign MyInterfaceInstanceInSub_setting = 0;
assign MyInterfaceInstanceInSub_mysig_out = sig;
endmodule
module SubModule2(
input logic clk,
input logic rst,
input logic u_MyInterfaceInSub2_setting,
output logic [3:0] u_MyInterfaceInSub2_other_setting,
input logic [1:0] u_MyInterfaceInSub2_mysig_out,
input logic u_MyInterfaceInSub3_setting,
output logic [21:0] u_MyInterfaceInSub3_other_setting,
input logic [1:0] u_MyInterfaceInSub3_mysig_out,
output logic [15:0] passThrough
);
always @(u_MyInterfaceInSub3_mysig_out) begin
if (u_MyInterfaceInSub3_mysig_out == 2'b00)
u_MyInterfaceInSub3_other_setting[21:0] = 1000;
else if (u_MyInterfaceInSub3_mysig_out == 2'b01)
u_MyInterfaceInSub3_other_setting[21:0] = 2000;
else if (u_MyInterfaceInSub3_mysig_out == 2'b10)
u_MyInterfaceInSub3_other_setting[21:0] = 3000;
else
u_MyInterfaceInSub3_other_setting[21:0] = 4000;
end
assign passThrough[7:0] = 124;
assign passThrough[15:8] = 200;
endmodule

View File

@ -0,0 +1,68 @@
`timescale 1ns/10ps
module svinterface_at_top_tb;
logic clk;
logic rst;
logic [21:0] outOther;
logic [1:0] sig;
logic [1:0] sig_out;
logic flip;
logic [15:0] passThrough;
integer outfile;
logic interfaceInstanceAtTop_setting;
logic [2:0] interfaceInstanceAtTop_other_setting;
logic [1:0] interfaceInstanceAtTop_mysig_out;
logic [15:0] interfaceInstanceAtTop_passThrough;
TopModule u_dut (
.clk(clk),
.rst(rst),
.outOther(outOther),
.sig(sig),
.flip(flip),
.passThrough(passThrough),
.interfaceInstanceAtTop_setting(interfaceInstanceAtTop_setting),
.interfaceInstanceAtTop_other_setting(interfaceInstanceAtTop_other_setting),
.interfaceInstanceAtTop_mysig_out(interfaceInstanceAtTop_mysig_out),
.interfaceInstanceAtTop_passThrough(interfaceInstanceAtTop_passThrough),
.sig_out(sig_out)
);
initial begin
clk = 0;
while(1) begin
clk = ~clk;
#50;
end
end
initial begin
outfile = $fopen("output.txt");
rst = 1;
interfaceInstanceAtTop_setting = 0;
sig = 0;
flip = 0;
@(posedge clk);
#(2);
rst = 0;
@(posedge clk);
for(int j=0;j<2;j++) begin
for(int i=0;i<20;i++) begin
#(2);
flip = j;
sig = i;
@(posedge clk);
end
end
$finish;
end
always @(negedge clk) begin
$fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out);
end
endmodule

View File

@ -0,0 +1,68 @@
`timescale 1ns/10ps
module svinterface_at_top_tb_wrapper;
logic clk;
logic rst;
logic [21:0] outOther;
logic [1:0] sig;
logic [1:0] sig_out;
logic flip;
logic [15:0] passThrough;
integer outfile;
logic interfaceInstanceAtTop_setting;
logic [2:0] interfaceInstanceAtTop_other_setting;
logic [1:0] interfaceInstanceAtTop_mysig_out;
logic [15:0] interfaceInstanceAtTop_passThrough;
TopModule u_dut (
.clk(clk),
.rst(rst),
.outOther(outOther),
.sig(sig),
.flip(flip),
.passThrough(passThrough),
.\interfaceInstanceAtTop.setting (interfaceInstanceAtTop_setting),
.\interfaceInstanceAtTop.other_setting (interfaceInstanceAtTop_other_setting),
.\interfaceInstanceAtTop.mysig_out (interfaceInstanceAtTop_mysig_out),
.\interfaceInstanceAtTop.passThrough (interfaceInstanceAtTop_passThrough),
.sig_out(sig_out)
);
initial begin
clk = 0;
while(1) begin
clk = ~clk;
#50;
end
end
initial begin
outfile = $fopen("output.txt");
rst = 1;
sig = 0;
interfaceInstanceAtTop_setting = 0;
flip = 0;
@(posedge clk);
#(2);
rst = 0;
@(posedge clk);
for(int j=0;j<2;j++) begin
for(int i=0;i<20;i++) begin
#(2);
flip = j;
sig = i;
@(posedge clk);
end
end
$finish;
end
always @(negedge clk) begin
$fdisplay(outfile, "%d %d %d %d", outOther, sig_out, passThrough, interfaceInstanceAtTop_mysig_out);
end
endmodule

View File

@ -0,0 +1,33 @@
`timescale 1ns/10ps
module svinterface_at_top_wrapper(
input logic clk,
input logic rst,
output logic [21:0] outOther,
input logic [1:0] sig,
output logic [1:0] sig_out,
input logic flip,
output logic [15:0] passThrough,
input logic interfaceInstanceAtTop_setting,
output logic [2:0] interfaceInstanceAtTop_other_setting,
output logic [1:0] interfaceInstanceAtTop_mysig_out,
output logic [15:0] interfaceInstanceAtTop_passThrough,
);
TopModule u_dut (
.clk(clk),
.rst(rst),
.outOther(outOther),
.sig(sig),
.flip(flip),
.passThrough(passThrough),
.\interfaceInstanceAtTop.setting(interfaceInstanceAtTop_setting),
.\interfaceInstanceAtTop.other_setting(interfaceInstanceAtTop_other_setting),
.\interfaceInstanceAtTop.mysig_out(interfaceInstanceAtTop_mysig_out),
.\interfaceInstanceAtTop.passThrough(interfaceInstanceAtTop_passThrough),
.sig_out(sig_out)
);
endmodule