- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page