Wrong with following Verilog code where I am trying to pass a one-dimensional array

system-verilogverilog

What is wrong with following Verilog code where I am trying to pass a one-dimensional array?

module stimulus;             
wire [3:0] max,med,min;                  
reg[3:0] row_data[0:2];               
reg cin;               
sorting_three sr(max,med,min,row_data,cin);      // line no.27      
initial begin              
row_data[0]=4'b0010;            
row_data[1]=4'b1001;                 
row_data[2]=4'b1010;              
cin=1'b0;                      
end                   
endmodule   

It's giving an error like:

ERROR:HDLCompiler:251 – "stimulus.v" Line 27. Cannot access memory row_data directly
ERROR:HDLCompiler:598 – "stimulus.v" Line 21. Module stimulus ignored due to previous errors

Best Answer

There seems to be a problem in the port declaration for module sorting_three. You're trying to pass an argument that can't exist.

Looks like module stimulus must be a test bench for module sorting_three, since module stimulus does not have any input or output ports.

Test bench module stimulus declares memory row_data as a 1-dimensional array of 4-bit registers, first address 0 last address 2. So this memory must have two address bits and four data bits. Initial values are declared in the initial block. This seems to be used as read-only memory, there's nothing to indicate that the values would ever be changed from the initial values when the circuit is synthesized.

But how does that row_data memory connect to module sorting_three?

Verilog is a hardware synthesis language. The read-only memory row_data must connect to module sorting_three through its 2-bit address port and its 4-bit data port. There is no such thing as the address of the row_data array "in memory", there's only the RTL code that describes the hardware. If you've come from a software programming background, this is the trickiest thing about learning Verilog or VHDL: thinking about what hardware circit you want to synthesize instead of describing its runtime behavior.

The test bench has to declare not only that the row_data memory array exists somewhere in the hardware, but also declare the wires that connect to the memory's address and data ports:

reg  [3:0] row_data[0:2];  // read-only memory, 4-bit data x 2-bit address
wire [1:0] row_data_address; // driven by module sorting_three
wire [3:0] row_data_dout; // driven by row_data[row_data_address]
assign row_data_dout = row_data[row_data_address];

The declaration for sorting_three should look like this (note I'm using Verilog 2001 style port declarations for readability):

module sorting_three_Memory (
    output reg  [3:0] max,
    output reg  [3:0] med,
    output reg  [3:0] min,
    output reg  [1:0] row_data_address, // drives row_data address
    input  wire [3:0] row_data_dout, // driven by row_data data out
    input  wire cin // clock
    );

Inside module sorting_three, the output port row_data_address must be driven to 2'b00, 2'b01, or 2'b10 to select one element of row_data on each clock cycle. Then, on the next clock cycle, valid data from row_data should be available from row_data_dout.

If the module needed to be able to write into the memory as well as read, then the memory needs to use additional ports for data_in and write_enable.

If the module was accessing off-chip memory, then additional clock cycles (known as "wait states") might be needed before valid data became available. But for on-chip memory inside an FPGA, usually single cycle access.

Alternative without synchronous memory access

Since there are only three addresses, and they seem to be read-only, you could pass them all individually instead of packing them into row_data memory:

module sorting_three_noMemory (
    output reg  [3:0] max,
    output reg  [3:0] med,
    output reg  [3:0] min,
    input  wire [3:0] row_data_0, // example 4'b0010
    input  wire [3:0] row_data_1, // example 4'b1001
    input  wire [3:0] row_data_2, // example 4'b1010
    input  wire cin
    );

However Verilog doesn't support a port declaration like input wire [3:0] row_data_array [0:2], that's not something that could be synthesized in hardware.

No clock in testbench

A second problem is this test bench doesn't seem to be driving a clock. I usually use something like this to generate a testbench clock for simulation:

localparam CLK_FREQ_HZ = 50_000_000;
localparam CLK_PERIOD_NS = 1_000_000_000 / CLK_FREQ_HZ;
always begin 
    #(CLK_PERIOD_NS/2.0); 
    clk=1; 
    #(CLK_PERIOD_NS/2.0); 
    clk=0; 
end