-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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:
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
Synchronous read/write means that reading and writing should happen in sync with the clock signal.
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
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:
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
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
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