FONT SIZE : AAA
In the preceding chapter, we observed how the memory is accessed asynchronously, whereas synchronous RAM (SRAM) requires a clock. In most practical designs, the RAM will be implemented off-chip as a separate memory device, but sometimes it is useful to define a small block of RAM on the FPGA for fast access or local storage close to the hardware device that requires frequent access to a relatively small memory block.
The usual design constraints apply to memory, more so than some other possible functions, as the use of flip-flops to store data without using much of the other logic in a look-up table (LUT) is area intensive. The trade-off, as ever with FPGA design, is whether the potential for improved performance and speed using on-board RAM outweighs the increased area required as a result.
From the design perspective, the synchronous RAM model is very similar to the previously demonstrated basic asynchronous RAM model. The only difference is that, instead of the data being available immediately on the address being applied (or after some short delay), the data in a synchronous RAM is only accessed when the clock edge occurs (rising or falling edge depending on the design required).
If we consider the VHDL for the SRAM, we can see that for a memory size of 2m and a data bus of 2n, the following model is required. The VHDL model has two parameters, m and n. In the default case, the value of m as 16 provides 64k address words and the number of bits (n) set to 16 gives a total of 1M bits in the RAM. Obviously this could be made any size, but this shows the type of calculation required to obtain the specified memory blocks.
1 library ieee;
2 use ieee.std_logic_1164.all; 3 use ieee.numeric_std.all; 45 entity sram is
6 generic ( 7 m : natural := 16;
8 n : natural := 16
9 );
10 port (
11 clk : in std_logic;
12 addr : in std_logic_vector (m−1 downto 0);
13 wr : in std_logic;
14 d : in std_logic_vector (n−1 downto 0);
15 q : out std_logic_vector (n−1 downto 0)
16 );
17 end entity sram;
18
19 architecture dualport of sram is
20 type sramdata is array (0 to 2∗∗m−1) of std_logic_vector (n−1 downto 0);
21 signal memory : sramdata;
22 begin
23 process (clk ) is
24 begin
25 if rising_edge(clk) then
26 if wr = ’0’ then
27 memory(to_integer(unsigned(addr))) <= d;
28 else
29 q <= memory(to_integer(unsigned(addr)));
30 end if;
31 end if;
32 end process;
33 end architecture dualport;
Notice that there are two control signals, the clock, clk, and the write enable, wr. We could make the memory synchronous write, synchronous read, or a more complex port structure, but in this case, we will show the operation as being synchronous read and write, on the rising edge of the clock. Also, the convention we will use is for the write enable state to be active when wr is low.
There are several interesting aspects to this model that are worth considering. The first is the access of the memory. If we define the address as a std_logic_vector type in VHDL, then we can’t simply use this value to access a specific element of an array. This requires an integer argument. We also cannot simply cast a std_logic_vector type directly to an integer. The first thing we must do is convert the std_logic_vector type to an unsigned number. This is a “halfway house” from std_logic_vector to integer, in that we can use the variable as a number, but it is limited to the same bit resolution as the original std_logic_vector. In this case, clearly this is not an issue as we do not want the address to be larger than the memory, otherwise errors will result. The final step is to convert the unsigned type to an integer. This is accomplished using the to_integer function and is the final step to convert the address into the integer form required to access the individual element of the array. As a consequence of using these numeric functions, we need to also include the IEEE standard numeric library in the header of the model as shown:
1 library ieee;
2 use ieee.std_logic_1164.all;
3 use ieee.numeric_std.all;
It is also worth noting that the read and write functions are mutually exclusive, in that you cannot read from the memory and write to it at the same time. This ensures the integrity of the data. Also note that the read and write functions are both clocked and so the memory is both read and write synchronous.
We can test this model by using a test bench similar to that used for the previous RAM models as given in the following listing:
1 library ieee;
2 use ieee.std_logic_1164.all; 3 use ieee.numeric_std.all; 45 entity testram is
6 end entity testram;
78 architecture test of testram is
9 signal address : std_logic_vector ( 7 downto 0 );
10 signal clk : std_logic;
11 signal wr : std_logic;
12 signal d : std_logic_vector ( 15 downto 0 );
13 signal q : std_logic_vector ( 15 downto 0 );
14 constant period : time := 5 ns;
15 begin
16
17 sram: entity work.sram(dualport) generic map ( 8, 16) port map( clk, address,
wr, d, q ) ;
18
19 address <= ”00000001” after 0 ns, ”00000010” after 30 ns, ”00000001” after 90
ns;
20 wr <= ’0’ after 0 ns, ’1’ after 90 ns;
21 d <= X”1234” after 0 ns, X”5678” after 40 ns;
22
Figure 11.4
Basic VHDL SRAM Simulation.
23
24 −− Clock process definitions( clock with 50% duty cycle is generated here.
25 clk_process :process
26 begin
27 clk <= ’0’;
28 wait for period/2;
29 clk <= ’1’;
30 wait for period/2;
31 end process;
32
33 end architecture test;
The results of testing this model can be seen in the waveform diagram in Figure 11.4, which shows the correct behavior of the address, data, and control lines.
Implementing the SRAM in Verilog is similar to the dual port RAM model earlier in this chapter, with an address, data input, and output ports, but importantly this model is now synchronous and so the management of the data to and from the memory is controlled by the clock signal clk.
1 module sram_verilog ( address, clk, rw, d, q );
2 parameter m = 8; / Address Bus Width
3 parameter n = 16; / Data Bus Width
4 input [m−1:0] address; / Address
5 input clk; / Clock
6 input rw; / Read/Write
7 input [n−1:0] d ; / Data In
8 output [n−1:0] q ; / Data Out
9
10 wire [n−1:0] d;
11 reg [n−1:0] q ; / Data defined as a register
12
13
14 / define the memory array
15 reg [n−1:0] memory [0:2∗∗m−1]; / the memory array is n bits wide (data) and
2∗∗m −1 deep (address)
16
17 always @ (posedge clk)
18 begin
19 if(!rw) begin
20 memory[address] <= d;
21 end
22 else begin
23 q <= memory[address];
24 end
25 end
26 endmodule
The test bench of the model is almost identical to the previous memory test benches; however, the clock is defined in the test bench, and as a result the variables can be seen to be changing at a rate dependent on the clock (in this case the clock changes every 5 ‘ticks’ and the other signals are therefore defined to change every 10 ‘ticks’).
12 module sram_verilog_tb();
3 / declare the counter signals
4 parameter m = 8;
5 parameter n = 16;
6 reg rw;
7 reg clk;
8 reg [m−1:0] address;
9 wire [n−1:0] dataout;
10
11 reg [n−1:0] datain;
12
13 / Set up the initial variables and reset
14 initial begin
15 $display ("time\t rw address data data_set");
16 $monitor ("%g\t %b %d %d %d",
17 $time, rw, address, datain, dataout);
18 rw = 1; / set the rw to 1
19 clk = 0; / INit the clk to 0
20
21 #10 address = 0; / set the row to 1
22 #10 datain = 23;
23 #10 rw = 0; / set the rw to 0
24 #10 address = 1; / set the row to 1
25
26 #10 rw = 1; / set the rw to 1
27
28 / This should have written the data of 23 into location 0:1
29
30
31 #10 address = 0; / set the row to 1
32 #10 datain = 47; / set the data to 47
33 #10 address = 2; / set the row to 2
34 #10 rw = 0; / set the rw to 0
35 #10 rw = 1; / set the rw to 1
36
37 / This should have written the data of 47 into location 0:2
38
39 #10 address = 0; / set the row to 1
40 #10 address = 1; / set the row to 1
41
42
43 #100 $finish; / Finish the simulation
44 end
45
46 / Clock
47 always begin
48 #5 clk = ~clk; / Invert the clock every 5 time ticks
49 end
50
51 sram_verilog RAM ( address, clk, rw, datain, dataout);
52
53 endmodule
The results of testing this model can be seen in the waveform diagram in Figure 11.5, which shows the correct behavior of the address, data, and control lines.
Manufacturer:Xilinx
Product Categories: Disjoncteur
Lifecycle:Obsolete -
RoHS:
Manufacturer:Xilinx
Product Categories:
Lifecycle:Obsolete -
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAs (Field Programmable Gate Array)
Lifecycle:Obsolete -
RoHS:
Manufacturer:Xilinx
Product Categories:
Lifecycle:Obsolete -
RoHS:
Manufacturer:Xilinx
Product Categories: FPGAs
Lifecycle:Active Active
RoHS:
Support