Skip to content

1. Modeling Memories

Irivinti Shiva Teja edited this page Jun 8, 2022 · 6 revisions

This is my notes. I still have to explore on the comments I've made at a few places.

What do we mean by a 4kB memory (a 4-kilo byte memory)?

4kbyte mem

How to model memory?

In the industry, the memories are instantiated from a pre-designed module of a particular library. Alternatively, we can model memories as two-dimensional arrays:

memory as array

Example:

module mem (a, b);
input a;
output b;
reg [7:0] mem [0:1023]; //this creates an array called mem which has 1024 words each of 8-bit length with mem[0] as the first word.
integer i;

initial begin //this block initializes the whole mem = 0
for (i=0; i<1024; i=i+1)
	begin
		mem[i] = 8'b00000000;
	end
end

//the following are other ways of initializing a memory from a .txt/.dat file
//$readmemb (filename, memname, startaddress, stopaddress)
//the above command reads the data in binary
//$readmemh (filename, memname, startadress, stopaddress)
//the above command reads the data in hexadecimal
//we may even write $readmemb (filename, memname) in which case the whole mem is //read

endmodule

Single-port RAM with synchronous read/write

Synchronous read/write means that reading and writing should happen in sync with the clock signal.

singleportRAm

module sngl_prtsyncRM (addr, clk, rd, wr, cs, data);
input [2:0] addr;
input clk, rd, wr, cs;
inout [7:0] data;
reg [7:0] data_out;
reg [7:0] mem [0:7];

assign data [7:0] = (cs&&rd) ? data_out [7:0] : 8'bz;//if we assign 8'bz to data //when cs&&rd is 0, then how can we give data to mem [addr] ? refer the note blw
always @ (posedge clk)
	begin
		if (cs&&rd&&!wr)
			data_out <= mem [addr];
		else if (cs&&!rd&&wr)
			mem [addr] <= data;//here...how? isn't data = 8'bz?
	end
//try to synthesize this later and add your notes. observe that all cases are not //covered. latching will happen but how? Also check what difference it makes to 
//use blocking style.

endmodule

Note:

Generally it is better to avoid the inout datatype as some tools behave inconsistently with this data type. Instead we may opt for seperate lines for data_input and data_output signals as shown below:

//this is an async RAM btw
module ram_noinout (addr, rd, cs, wr, data_in, data_out);
input [2:0] addr;
input rd, cs, wr;
input [7:0] data_in;
output reg [7:0] data_out;
reg [7:0] mem [0:7];

always @ (cs&&wr&&!rd)
	begin
		mem [addr]<= data_in;
	end
always @ (cs&&!wr&&rd) //we may even go with a single rd/wr in which case we //could use an if-else statement inside the always block
	begin
		data_out <= mem [addr];
	end
endmodule

Infact, we may even choose to realise a bi-directional bus using tri-state buffers:

bidir_buff

the code for which would be:

module tri_buff (wr, rd, data_in, data_out);
input wr, rd, data_in; //we may even define data_in as a word in which case, the //bi-bus would be assigned to word_length z if buffers off
output data_out;
tri bi_bus;

assign bi_bus = wr ? data_in : 1'bz;
assign data_out = rd ? bi_bus : 1'bz;

endmodule

Writing testbench for RAM

module ram_noinout_tb();
reg [2:0] addr;
reg rd, wr, cs;
reg [7:0] data_in;
wire [7:0] data_out;
integer i, k;

ram_noinout dut(addr, rd, cs, wr, data_in, data_out);

initial 
	begin
		for (i=0; i<9; i=i+1)
			begin
				data_in = i*i;
				rd = 0;
				wr = 1;
				cs = 1;
				#2 wr = 0; cs = 0;
			end
		repeat (8)
			begin
				#2 addr = {$random (k)} % 7;
				wr = 0; cs = 1; rd = 1;
                                $display ("Address: %d    and    Data: %d", addr, data_out);
                        end
        end
initial k = 4;
endmodule

more notes on the random task here

ROM

module sngl_prtROM (addr, rd_en, cs, data); //no clock here. we just want to read
input [2:0] addr;
input red_en, cs;
output reg [7:0] data;

always @ (*) 
//check how it'll be different if we remove 'data' from the sensitivity list
	case (addr)
		0 : data = 12;
		1 : data = 14;
		2 : data = 18;
		3 : data = 15;
		4 : data = 13;
		5 : data = 16;
		6 : data = 17;
		7 : data = 19;
	endcase
endmodule