Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16614 Discussions

What's Wrong with This SV Code Involving Interfaces?

Altera_Forum
Honored Contributor II
2,709 Views

I'm trying to set initial conditions for registers in an array of interfaces. Doing it manually seems to work. In my project, this builds in Quartus without errors: 

initial begin ports.done = '1; ports.done = '1; ports.done = '1; ports.done = '1; end  

 

However, changing that block of code to this causes the build to fail: 

 

initial begin for(int n=0; n<4; n++) begin ports.done = '1; end end  

 

In the second case I get an error of 'can't resolve reference to object "ports"' as though the array doesn't exist. Am I making a dumb mistake or trying something that isn't possible? My eventual goal is to have a parameterized number of ports, but that requires being able to make assignments using loops.
0 Kudos
5 Replies
Altera_Forum
Honored Contributor II
1,288 Views

Try using a generate block. I do it all the time. I suspect you cannot do this because interfaces appear as unpacked data structures in the memory. 

-sanjay
0 Kudos
Altera_Forum
Honored Contributor II
1,288 Views

I think I see what you’re saying, but I’m struggling to make it work for what I actually want to do. As far as seeing what you mean, this design builds fine for me in Quartus: 

 

interface my_interface; logic some_byte; endinterface module fpga_test( input wire clk, my_interface ports ); genvar n; generate for(n=0; n<4; n++) begin: init_ports initial ports.some_byte = '1; always_ff @(posedge clk) ports.some_byte <= ports.some_byte + 1'd1; end endgenerate endmodule 

 

In practice, though, I’m trying to use this in an application where all the ports are sharing a single resource. I need priority so that when multiple ports request the resource, only the lowest index port is given access.  

 

I came up with an example that’s closer to what I want to do. I started by writing it out explicitly. The idea here is that the fpga_test module initializes and increments the some_byte register in each port. Each port has a an increment_enable signal that comes from the outside world. If increment_enable is asserted on any of the ports, I want only the lowest numbered port to increment. That simulates the concept of priority that I’m trying to achieve. This explicit version builds in Quartus: 

 

interface my_interface; logic some_byte; logic increment_enable; //This is an input from another module endinterface module fpga_test( input wire clk, my_interface ports ); initial begin ports.some_byte = '1; ports.some_byte = '1; ports.some_byte = '1; ports.some_byte = '1; end always_ff @(posedge clk) begin //Check if any of the increment_enable lines are high. If one or more is high, only act based on the //lowest index. if(increment_now) ports.some_byte <= ports.some_byte + 1'd1; end function increment_now; //Check if any increment_enable lines are high logic result = 0; //Written like this so that it's obvious how to make it into a for loop result = result | ports.increment_enable; result = result | ports.increment_enable; result = result | ports.increment_enable; result = result | ports.increment_enable; return result; endfunction function get_increment_index; //Get the index of the lowest active increment_enable logic result = '0; //Written like this so that it's obvious how to make it into a for loop if (ports.increment_enable) result = 2'd0; else if (ports.increment_enable) result = 2'd1; else if (ports.increment_enable) result = 2'd2; else if (ports.increment_enable) result = 2'd3; return result; endfunction endmodule 

 

Can this be made to work with loops so that I can parameterize the number of ports? I get build errors when trying to make almost any of that loop-based. I can't even get the functions alone to build when written as loops.
0 Kudos
Altera_Forum
Honored Contributor II
1,288 Views

Arrays of instances cannot be dynamically selected with a variable index. You must use a constant select (provided by a generate as well). The reason for this is because of parameter overrides that can make each element a unique kind if instance. With a variable array, the elements must be identical.

0 Kudos
Altera_Forum
Honored Contributor II
1,288 Views

Thank you for the clarification. That is annoying, because in this case there are no parameters that could lead to the instances being different. It’s too bad there’s no exception for a case like this where every element of the array is identical. 

 

Building from your comment, I wondered what would happen if I inserted a struct between the port array and the rest of the code. I used a generate loop to link the port array with the struct array. Then I just updated my loops to reference the struct array instead of the port array. 

 

interface my_interface; logic some_byte; logic increment_enable; //This is an input from another module endinterface typedef struct { logic some_byte; logic increment_enable; } my_struct; module fpga_test( input wire clk, my_interface ports ); //Create a structure used to work around the issue of not being able to access elements of a port array in loops my_struct ports_cheating ; //Use generated assignments to make the structure array a proxy for the port array. genvar n; generate for(n=0; n<4; n++) begin: port_assignments assign ports.some_byte = ports_cheating.some_byte; assign ports_cheating.increment_enable = ports.increment_enable; end endgenerate initial begin for(int n=0; n<4; n++) ports_cheating.some_byte = '1; end always_ff @(posedge clk) begin //Check if any of the increment_enable lines are high. If one or more is high, only act based on the lowest index. if(increment_now) ports_cheating.some_byte <= ports_cheating.some_byte + 1'd1; end function increment_now; //Check if any increment_enable lines are high logic result = 0; for(int n=0; n<4; n++) result = result | ports_cheating.increment_enable; return result; endfunction function get_increment_index; //Get the index of the lowest active increment_enable logic result = '0; for(int n=0; n<4; n++) begin if(ports_cheating.increment_enable) begin result = n; break; end end return result; endfunction endmodule  

 

That builds! It has a couple issues, though. It doesn't run in the Quartus simulator (it looks like ModelSim says there's an error in the .do file that Quartus is generating). I'll try it in a real testbench next. It also has a worrisome warning: 

 

"Warning (10855): Verilog HDL warning at fpga_test.sv(27): initial value for variable ports_cheating should be constant" 

 

'1 is clearly a constant value. What is unclear about that? I don't see any inversions happening in the Technology Map Viewer, so it looks like the initial statements are probably being ignored.
0 Kudos
Altera_Forum
Honored Contributor II
1,288 Views

My bad... all the elements of a struct must share the same type of assignment. My combination of continuous and procedural assignments above is what caused the initial state confusion. Structs aren't necessary for what I was trying to do, anyway. Here's a version that works in ModelSim and builds in Quartus: 

 

interface my_interface; logic some_byte; logic increment_enable; //This is an input from another module endinterface module fpga_test( input wire clk, my_interface ports ); //Create arrays used to work around the issue of not being able to access elements of a port array in loops logic increment_enables ; logic some_bytes ; //Use generated assignments to make the local arrays proxies for the port array elements. genvar n; generate for(n=0; n<4; n++) begin: port_assignments assign ports.some_byte = some_bytes; assign increment_enables = ports.increment_enable; end endgenerate initial begin for(int n=0; n<4; n++) some_bytes = '1; end function increment_now; //Check if any increment_enable lines are high automatic logic result = 0; for(int n=0; n<4; n++) result = result | increment_enables; return result; endfunction function get_increment_index; //Get the index of the lowest active increment_enable automatic logic result = '0; for(int n=0; n<4; n++) begin if(increment_enables) begin result = n; break; end end return result; endfunction always_ff @(posedge clk) begin //Check if any of the increment_enable lines are high. If one or more is high, only act based on the lowest index. if(increment_now) some_bytes <= some_bytes + 1'd1; end endmodule 

 

Now that everything is working with loops, it should scale easily. This accomplishes what I was going for, so I have a workable solution now. Maybe someone else will find the code and issues useful.
0 Kudos
Reply