I started Verilog a few weeks ago and now I'm implementing MIPS pipelining on an FPGA board and I'm on the MEM part of the pipelining stage. I'm trying to code the Data memory unit (in picture -> Data memory Unit).
I don't understand the use of memread. I understand that if memwrite is 1, the contents of the current address is passed to read data.
So far, this is my code:
module data_memory (
input wire [31:0] addr, // Memory Address
input wire [31:0] write_data, // Memory Address Contents
input wire memwrite, memread,
output reg [31:0] read_data // Output of Memory Address Contents
);
reg [31:0] MEMO[0:255]; // 256 words of 32-bit memory
integer i;
initial begin
read_data <= 0;
for (i = 0; i < 256; i = i + 1)
MEMO[i] = i;
end
always @ (addr) begin
//**I don't understand the use of memread**//
if (memwrite == 1'b1)
MEMO[addr] <= write_data;
end
end
assign read_data = MEMO[addr];
endmodule
Do I need another if statement for the memread? Any help is greatly appreciated. Thanks
In the design you have coded above, you dont use memread
, instead choosing to combinationally read from the memory via the last line of your module. And without more details on how exactly the memory in your diagram is suppose to function, its difficult to say the exact usage of memread
. Typical memories only have a memwrite
and assume that if an address is supplied and memwrite
is deasserted, the access is a read. In this case, I can only assuming memread
should be asserted to read from the memory. Also, I would suggest a few edits to your code to make it work better and follow a better synchronous design style (this will incorporate memread
so you can see how it can be used):
module data_memory (
input wire [31:0] addr, // Memory Address
input wire [31:0] write_data, // Memory Address Contents
input wire memwrite, memread,
input wire clk, // All synchronous elements, including memories, should have a clock signal
output reg [31:0] read_data // Output of Memory Address Contents
);
reg [31:0] MEMO[0:255]; // 256 words of 32-bit memory
integer i;
initial begin
read_data <= 0;
for (i = 0; i < 256; i = i + 1) begin
MEMO[i] = i;
end
end
// Using @(addr) will lead to unexpected behavior as memories are synchronous elements like registers
always @(posedge clk) begin
if (memwrite == 1'b1) begin
MEMO[addr] <= write_data;
end
// Use memread to indicate a valid address is on the line and read the memory into a register at that address when memread is asserted
if (memread == 1'b1) begin
read_data <= MEMO[addr];
end
end
endmodule
Important to note also the need for a clock in your design. Most block diagrams at that level will omit the clock as it is assumed but all synchronous elements (memories and registers) will be synchronized to a common clock (or multiple clocks in some cases).
@Unn gives excellent answer, moreover I just want add that, if you not use read_enable
, Then it may unsynchronised data read operation, It is also preferred to flop the output read_data
on read_clk
.
Here with see below templent for reference.
parameter RAM_WIDTH = <ram_width>;
parameter RAM_ADDR_BITS = <ram_addr_bits>;
(* RAM_STYLE="{AUTO | BLOCK | BLOCK_POWER1 | BLOCK_POWER2}" *)
reg [RAM_WIDTH-1:0] <ram_name> [(2**RAM_ADDR_BITS)-1:0];
reg [RAM_WIDTH-1:0] <output_dataB>;
<reg_or_wire> [RAM_ADDR_BITS-1:0] <addressA>, <addressB>;
<reg_or_wire> [RAM_WIDTH-1:0] <input_dataA>;
// The forllowing code is only necessary if you wish to initialize the RAM
// contents via an external file (use $readmemb for binary data)
initial
$readmemh("<data_file_name>", <ram_name>, <begin_address>, <end_address>);
always @(posedge <clockA>)
if (<enableA>)
if (<write_enableA>)
<ram_name>[<addressA>] <= <input_dataA>;
always @(posedge <clockB>)
if (<enableB>)
<output_dataB> <= <ram_name>[<addressB>];