This website uses cookies. By using this site, you consent to the use of cookies. For more information, please take a look at our Privacy Policy.
Home > FPGA Technical Tutorials > Design Recipes for FPGAs Using Verilog and VHDL > Memory > Random Access Memory

TABLE OF CONTENTS

Xilinx FPGA FPGA Forum

Random Access Memory

FONT SIZE : AAA

A dynamic random access memory (RAM) block has a two-dimensional structure of memory that is divided into a grid structure that can be accessed by a row address and column address (obviously this is one way of carrying this out, but it is often the approach required for dynamic RAM). Note that this is asynchronous and therefore has no clock. The implication of being asynchronous is that great care must be taken with the timing of the memory access to ensure data integrity throughout the transfer process. 

The VHDL model has a single address input and two control signals row and col used to load the row and column address, respectively. There is also a rw signal that is defined as being write when high and read when low. Finally, the data is put onto the data signal, which is defined as an inout (bidirectional) signal. The resulting model is given in the VHDL following. In this example, the number of rows is 28 and the number of columns also 28. This gives a total data storage with 16 bits of 1 MBit.

1 library ieee;

2 use ieee.std_logic_1164.all; 3 use ieee.numeric_std.all; 45 entity dram1mb is

6 port ( 7 address : in integer range 0 to 2∗∗8−1; −− Row Address

8 row : in std_logic; −− Row Select

9 col : in std_logic; −− Column Select

10 rw : std_logic; −− Read/Write

11 data : inout std_logic_vector (15 downto 0) −− Data

12 );

13 end entity dram1mb;

14

15 architecture behav of dram1mb is

16 begin

17 process (row, col, rw) is

18 type dram is array (0 to 2∗∗16 − 1) of std_logic_vector(15 downto 0);

19 variable radd: INTEGER range 0 to 2∗∗8 − 1;

20 variable madd: INTEGER range 0 to 2∗∗16 − 1;

21 variable memory: dram;

22 begin

23 data <= (others => ’Z’);

24 if falling_edge(row) then

25 radd := address;

26 elsif falling_edge(col) then

27 madd :=radd∗2∗∗8 +address;

28 if row = ’0’ and rw = ’0’ then

29 memory(madd) := data;

30 end if;

31 elsif col = ’0’ and row = ’0’ and rw = ’1’ then

32 data <= memory(madd);

33 end if;

34 end process;

35 end architecture behav;

Using this model a simple testbench can be used to read in a data value to an address, then another value to another address and then the original value read back. The test bench to achieve this is given in the VHDL.

1 library ieee;

2 use ieee.std_logic_1164.all; 34 entity testram is

5 end entity testram;

67 architecture test of testram is

8 signal address : integer range 0 to 2∗∗8−1 := 0;

9 signal rw : std_logic;

10 signal c : std_logic;

11 signal r : std_logic;

12 signal data : std_logic_vector ( 15 downto 0 );

13 begin

14

15 dram: entity work.dram1mb(behav)

16 port map ( address, r, c, rw, data );

17 address <= 23 after 0 ns, 47 after 30 ns, 23 after 90 ns;

18 rw <= ’0’ after 0 ns, ’1’ after 90 ns;

19 c <= ’1’ after 0 ns, ’0’ after 20 ns,

20 ’1’ after 50 ns, ’0’ after 70 ns,

21 ’1’ after 90 ns, ’0’ after 100 ns;

22 r <= ’1’ after 0 ns, ’0’ after 10 ns,

23 ’1’ after 40 ns, ’0’ after 60 ns,

24 ’1’ after 80 ns, ’0’ after 100 ns;

25 data <= X"1234" after 0 ns, X"5678" after 40 ns;

26

27 end architecture test;

The results of testing this model can be seen in the waveform plot in Figure 11.1, which shows the correct behavior of the address, data, and control lines. 

The Verilog model has a single address input and two control signals row and col used to load the row and column address, respectively. There is also a rw signal that is defined as being write when high and read when low. Finally, the data is put onto the datain signal, which is defined as an input signal and read back from the dataout signal which is defined as a register. The resulting model is given in the Verilog following. In this example, the number of rows is 28 and the number of columns also 28. This gives a total data storage with 16 bits of 1 MBit.

1 module dram1mb ( address, row, col, rw, datain, dataout );

23 input [7:0] address; / Address

4 input row; / Row Selector

5 input col; / Column Selector

6 input rw; / Read/Write

7 input [15:0] datain ; / Data In

8 output [15:0] dataout ; / Data Out

9

10 wire [15:0] datain;

11 reg [15:0] dataout ; / Data defined as a register

12

13 reg [7:0] radd; / Row Address

14 reg [15:0] madd; / Overall memory Address

15

16 / define the memory array

17 reg [15:0] memory [0:255]; / the memory array is 16 bits wide (data) and

2∗∗8 −1 deep (address)

18

19 always @ (negedge row)

20 begin

Figure 11.1 

Basic VHDL RAM simulation.

21 radd = address;

22 end

23

24 always @ (negedge col)

25 begin

26 madd = radd∗2∗∗8 + address;

27 if(!rw) begin

28 memory[madd] <= datain;

29 end

30 else begin

31 dataout <= memory[madd];

32 end

33 end

34 endmodule

Using this model, a simple testbench can be used to read in a data value to an address, then another value to another address and then the original value read back. The test bench to achieve this is given in the Verilog following. Note as stated earlier that this is an asynchronous model, which means that the rw signal must be defined prior to the col control signal going low (and it is very important to not make this coincident with the rw signal, otherwise a race condition would arise).

12 module dram1mb_tb();

3 / declare the counter signals

4 reg row;

5 reg col;

6 reg rw;

7 reg [7:0] address;

8 wire [15:0] dataout;

9

10 reg [15:0] datain;

11

12 / Set up the initial variables and reset

13 initial begin

14 $display ("time\t row col rw address data data_set");

15 $monitor ("%g\t %b %b %b %d %d %d",

16 $time, row, col, rw, address, datain, dataout);

17 row = 1; / initialize the row to 1

18 col = 1; / set the col to 1

19 rw = 1; / set the rw to 1

20

21 #1 address = 0; / set the row to 1

22 #1 datain = 23;

23 #1 row = 0; / set the row to 0

24 #1 row = 1; / set the row to 1

25 #1 address = 1; / set the row to 1

26 #1 rw = 0; / set the rw to 0

27 #1 col = 0; / set the col to 0

28 #1 col = 1; / set the col to 1

29 #1 rw = 1; / set the rw to 1

30

31 / This should have written the data of 23 into location 0:1

32

33

34 #1 address = 0; / set the row to 1

35 #1 datain = 47; / set the data to 47

36 #1 row = 0; / set the row to 0

37 #1 row = 1; / set the row to 1

38 #1 address = 2; / set the row to 2

39 #1 rw = 0; / set the rw to 0

40 #1 col = 0; / set the col to 0

41 #1 col = 1; / set the col to 1

42 #1 rw = 1; / set the rw to 1

43

44 / This should have written the data of 47 into location 0:2

45

46 #1 address = 0; / set the row to 1

47 #1 row = 0; / set the row to 0

48 #1 row = 1; / set the row to 1

49 #1 address = 1; / set the row to 1

50 #1 col = 0; / set the col to 0

51 #1 col = 1; / set the col to 1

52

53 #100 $finish; / Finish the simulation

54 end

55

56 dram1mb RAM ( address, row, col, rw, datain, dataout);

57

58 endmodule

The results of testing this model can be seen in the waveform plot in Figure 11.2 which shows the correct behavior of the address, data, and control lines. 

This model is different from the VHDL in an important aspect: that the memory has a separate data input and output port (defined as an input and output, respectively). This is not what was defined in the VHDL model, which used a single inout port for the data. Therefore, how can this be done using Verilog? We have two basic types in verilog, wire for direct connections and reg for registers. If we use an inout type for the port, then a register cannot be used, but also a wire does not hold the value, so how can we reconcile this in a RAM model? The answer is to declare an internal register to hold the output value of the data port, and then, depending on the value of the rw command signal, define the data port as having the value defined by the output register (in this model dataout) or making it a high impedance state (tri-state). This port can then be driven externally, as is shown in the test bench.

Figure 11.2 

Basic Verilog RAM simulation.

1 module dram1mbio ( address, row, col, rw, data );

2 input [7:0] address; / Address

3 input row; / Row Selector

4 input col; / Column Selector

5 input rw; / Read/Write

6 inout [15:0] data ; / Data In

78 wire [15:0] data;

9 reg [15:0] dataout ; / Data defined as a register

10

11 reg [7:0] radd; / Row Address

12 reg [15:0] madd; / Overall memory Address

13

14 / define the memory array

15 reg [15:0] memory [0:255]; / the memory array is 16 bits wide (data) and

2∗∗8 −1 deep (address)

16 assign data = (rw) ? dataout : 16’hz;

17 always @ (negedge row)

18 begin

19 radd = address;

20 end

21

22 always @ (negedge col)

23 begin

24 madd = radd∗2∗∗8 + address;

25 if(!rw) begin

26 memory[madd] <= data;

27 end

28 else begin

29 dataout <= memory[madd];

30 end

31 end

32 endmodule

Using this model a simple testbench can be used to read in a data value to an address, then another value to another address, and then the original value read back. The test bench to achieve this is given in the Verilog following. Note as stated earlier that this is an asynchronous model, which means that the rw signal must be defined prior to the col control signal going low (and it is very important to not make this coincident with the rw signal, otherwise a race condition would arise). In the test bench, it can be seen that the same tri-state technique is required as in the RAM model itself, allowing the single port to be used as an input to read the data into the memory or as a register to write the requested data value back out to the data bus.

12 module dram1mbio_tb();

3 / declare the counter signals

4 reg row;

5 reg col;

6 reg rw;

7 reg [7:0] address;

8 wire [15:0] data;

9

10 reg [15:0] datain;

11

12 assign data = (!rw) ? datain : 16’hz;

13

14 / Set up the initial variables and reset

15 initial begin

16 $display ("time\t row col rw address data data_set");

17 $monitor ("%g\t %b %b %b %d %d %d",

18 $time, row, col, rw, address, datain, data);

19 col = 1; / set the col to 1

20 rw = 1; / set the rw to 1

21

22 #1 address = 0; / set the row to 1

23 #1 datain = 23;

24 #1 row = 0; / set the row to 0

25 #1 row = 1; / set the row to 1

26 #1 address = 1; / set the row to 1

27 #1 rw = 0; / set the rw to 0

28 #1 col = 0; / set the col to 0

29 #1 col = 1; / set the col to 1

30 #1 rw = 1; / set the rw to 1

31

32 / This should have written the data of 23 into location 0:1

33

34

35 #1 address = 0; / set the row to 1

36 #1 datain = 47; / set the data to 47

37 #1 row = 0; / set the row to 0

38 #1 row = 1; / set the row to 1

39 #1 address = 2; / set the row to 2

40 #1 rw = 0; / set the rw to 0

41 #1 col = 0; / set the col to 0

42 #1 col = 1; / set the col to 1

43 #1 rw = 1; / set the rw to 1

44

45 / This should have written the data of 47 into location 0:2

46

47 #1 address = 0; / set the row to 1

48 #1 row = 0; / set the row to 0

49 #1 row = 1; / set the row to 1

50 #1 address = 1; / set the row to 1

51 #1 col = 0; / set the col to 0

52 #1 col = 1; / set the col to 1

53

54 #100 $finish; / Finish the simulation

55 end

Figure 11.3 

Basic RAM simulation with a common data port.

56

57 dram1mbio RAM ( address, row, col, rw, data);

58

59 endmodule

The results of testing this model can be seen in the waveform plot in Figure 11.3 which shows the correct behavior of the address, data, and control lines. 

It is important to note that the RAM model in both VHDL and Verilog cases does not model any of the actual delays that would appear in practice and if this is important to the functionality of the design, then it MUST be added to the model. Also, note that this could be obtained from a data sheet for DRAM (dynamic RAM); however, the delays would have an uncertainty attached to them.


  • XCS30XL-4TQ144Q

    Manufacturer:Xilinx

  • Xilinx TQFP144
  • Product Categories:

    Lifecycle:Obsolete -

    RoHS: -

  • XC3090A-6PC84C

    Manufacturer:Xilinx

  • FPGA XC3000 Family 6K Gates 320 Cells 135MHz 5V 84-Pin PLCC
  • Product Categories:

    Lifecycle:Obsolete -

    RoHS: No RoHS

  • XC2V250-4CS144I

    Manufacturer:Xilinx

  • FPGA Virtex-II Family 250K Gates 3456 Cells 650MHz 0.15um Technology 1.5V 144-Pin CSBGA
  • Product Categories:

    Lifecycle:Obsolete -

    RoHS: No RoHS

  • XC2V250-4FG456I

    Manufacturer:Xilinx

  • FPGA Virtex-II Family 250K Gates 3456 Cells 650MHz 0.15um Technology 1.5V 456-Pin FBGA
  • Product Categories: FPGAs

    Lifecycle:Obsolete -

    RoHS:

  • XCV300-6FG456C

    Manufacturer:Xilinx

  • FPGA Virtex Family 322.97K Gates 6912 Cells 333MHz 0.22um Technology 2.5V 456-Pin FBGA
  • Product Categories: Condensateurs électrolytiques en aluminium

    Lifecycle:Obsolete -

    RoHS:

Need Help?

Support

If you have any questions about the product and related issues, Please contact us.