I am using a DE10-Nano with Quartus Prime to try to implement the following.
I have two modules: Module1
and Module2
. Module1
declares a RAM
like this:
reg [15:0] RAM[0:24576];
// init RAM 0:8191 with all 1
And then passes a subset of the RAM to Module2
:
Module2 Module2 (
// input
.screen_mem(RAM[0:8191]),
);
Module2
shows screen_mem
on a monitor to be displayed. Unfortunately above solution does not work, i.e., display goes all black.
But if I try:
reg [15:0] screen_mem[0:8191];
// init screen_mem with all 1
Module2 Module2 (
// input
.screen_mem(screen_mem),
);
This works, i.e., the display properly shows all the white pixels.
If I try to use a simulator, both solutions work.
What am I missing? Why I can't pass a slice of an unpacked array to a submodule? I also tried to use an intermediate wire
, but it still doesn't work. Am I missing something?
Thanks,
It is likely that your first implementation is resulting in an inferred ram, which is correct from a hardware-perspective.
However then you are trying to index directly into it as if it is an array of registers which the synthesis tool doesn't know how to do. Essentially you need to fully encapsulate your RAM as an inferred RAM block with write enables, write indexes, read enables, and read indexes, then combine that with your example of the screen_mem (which I assume is used like an array or registers):
// Read side of RAM
always@(posedge clk) begin
if(ram_read_en == 1'b1) begin
// This makes the RAM act like a true RAM
ram_read_data <= RAM[ram_read_addr];
end else begin
// Default here depends on your synthesizer....may not need it...
end
end
// Screen Mem Updater Handshaking
always@(posedge clk) begin
if(rst_n == 1'b0) begin
ram_read_addr <= '0;
ram_read_en <= '0;
end else begin
// "Map" address from RAM to screen_mem at same location
if(ram_read_addr == 'd8191) begin
ram_read_addr <= '0;
end else begin
ram_read_addr <= ram_read_addr + 1;
end
// Always reading to update screen_mem
ram_read_en <= '1;
end
end
// Screen Mem Updater
always@(posedge clk) begin
// Map RAM to screen_mem based on the same address above
// Probably have to play with pipelining of the ram_read_addr as
// the RAM takes time to readout...
screen_mem[ram_read_addr] <= ram_read_data;
end
It will end up synthesizing to something like this:
It is understandable that the simulator works correctly because it can use the RAM array as both a RAM and as an array of registers...it just sees it as an array of memory locations in the sim. Hardware, however, needs to map this to real objects in the FPGA which is why you have a simulation mismatch.