SURF  1.0
TrueDualPortRam.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : TrueDualPortRam.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-07-11
5 -- Last update: 2016-05-09
6 -------------------------------------------------------------------------------
7 -- Description: This will infer this module as Block RAM only
8 --
9 -- NOTE: TDP ram with read enable logic is not supported.
10 -------------------------------------------------------------------------------
11 -- This file is part of 'SLAC Firmware Standard Library'.
12 -- It is subject to the license terms in the LICENSE.txt file found in the
13 -- top-level directory of this distribution and at:
14 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
15 -- No part of 'SLAC Firmware Standard Library', including this file,
16 -- may be copied, modified, propagated, or distributed except according to
17 -- the terms contained in the LICENSE.txt file.
18 -------------------------------------------------------------------------------
19 
20 library ieee;
21 use ieee.std_logic_1164.all;
22 use ieee.std_logic_unsigned.all;
23 
24 use work.StdRtlPkg.all;
25 
26 --! @see entity
27  --! @ingroup base_ram
28 entity TrueDualPortRam is
29  -- MODE_G = {"no-change","read-first","write-first"}
30  generic (
31  TPD_G : time := 1 ns;
32  RST_POLARITY_G : sl := '1'; -- '1' for active high rst, '0' for active low
33  ALTERA_RAM_G : string := "M9K";
34  DOA_REG_G : boolean := false; -- Extra output register on doutA.
35  DOB_REG_G : boolean := false; -- Extra output register on doutB.
36  MODE_G : string := "read-first";
37  BYTE_WR_EN_G : boolean := false;
38  DATA_WIDTH_G : integer range 1 to (2**24) := 18;
39  BYTE_WIDTH_G : integer := 8; -- Should be multiple of 8 or 9.
40  ADDR_WIDTH_G : integer range 1 to (2**24) := 9;
41  INIT_G : slv := "0");
42  port (
43  -- Port A
44  clka : in sl := '0';
45  ena : in sl := '1';
46  wea : in sl := '0';
47  weaByte : in slv(wordCount(DATA_WIDTH_G, BYTE_WIDTH_G)-1 downto 0) := (others => '0');
48  rsta : in sl := not(RST_POLARITY_G);
49  addra : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0');
50  dina : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0');
51  douta : out slv(DATA_WIDTH_G-1 downto 0);
52  regcea : in sl := '1'; -- Clock enable for extra output reg. Only used when DOA_REG_G = true
53  -- Port B
54  clkb : in sl := '0';
55  enb : in sl := '1';
56  web : in sl := '0';
57  webByte : in slv(wordCount(DATA_WIDTH_G, BYTE_WIDTH_G)-1 downto 0) := (others => '0');
58  rstb : in sl := not(RST_POLARITY_G);
59  addrb : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0');
60  dinb : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0');
61  doutb : out slv(DATA_WIDTH_G-1 downto 0);
62  regceb : in sl := '1'); -- Clock enable for extra output reg. Only used when DOA_REG_G = true
63 end TrueDualPortRam;
64 
65 architecture rtl of TrueDualPortRam is
66 
67  -- Set byte width to word width if byte writes not enabled
68  -- Otherwise block ram parity bits wont be utilized
69  constant BYTE_WIDTH_C : natural := ite(BYTE_WR_EN_G, BYTE_WIDTH_G, DATA_WIDTH_G);
70  constant NUM_BYTES_C : natural := wordCount(DATA_WIDTH_G, BYTE_WIDTH_C);
71  constant FULL_DATA_WIDTH_C : natural := NUM_BYTES_C*BYTE_WIDTH_C;
72 
73  constant INIT_C : slv(FULL_DATA_WIDTH_C-1 downto 0) := ite(INIT_G = "0", slvZero(FULL_DATA_WIDTH_C), INIT_G);
74 
75  -- Shared memory
76  type mem_type is array ((2**ADDR_WIDTH_G)-1 downto 0) of slv(FULL_DATA_WIDTH_C-1 downto 0);
77  shared variable mem : mem_type := (others => INIT_C);
78 
79  signal doutAInt : slv(FULL_DATA_WIDTH_C-1 downto 0);
80  signal doutBInt : slv(FULL_DATA_WIDTH_C-1 downto 0);
81 
82  signal weaByteInt : slv(weaByte'range);
83  signal webByteInt : slv(webByte'range);
84 
85  -- Attribute for XST (Xilinx Synthesizer)
86  attribute ram_style : string;
87  attribute ram_style of mem : variable is "block";
88 
89  attribute ram_extract : string;
90  attribute ram_extract of mem : variable is "TRUE";
91 
92  attribute keep : boolean; --"keep" is same for XST and Altera
93  attribute keep of mem : variable is true; --"keep" is same for XST and Altera
94 
95  -- Attribute for Synplicity Synthesizer
96  attribute syn_ramstyle : string;
97  attribute syn_ramstyle of mem : variable is "block";
98 
99  attribute syn_keep : string;
100  attribute syn_keep of mem : variable is "TRUE";
101 
102  -- Attribute for Altera Synthesizer
103  attribute ramstyle : string;
104  attribute ramstyle of mem : variable is ALTERA_RAM_G;
105 
106 begin
107 
108  -- MODE_G check
109  assert (MODE_G = "no-change") or (MODE_G = "read-first") or (MODE_G = "write-first")
110  report "MODE_G must be either no-change, read-first, or write-first"
111  severity failure;
112  -- ALTERA_RAM_G check
113  assert ((ALTERA_RAM_G = "M512")
114  or (ALTERA_RAM_G = "M4K")
115  or (ALTERA_RAM_G = "M9K")
116  or (ALTERA_RAM_G = "M10K")
117  or (ALTERA_RAM_G = "M20K")
118  or (ALTERA_RAM_G = "M144K")
119  or (ALTERA_RAM_G = "M-RAM"))
120  report "Invalid ALTERA_RAM_G string"
121  severity failure;
122 
123  weaByteInt <= weaByte when BYTE_WR_EN_G else (others => wea);
124  webByteInt <= webByte when BYTE_WR_EN_G else (others => web);
125 
126 
127  -------------------------------------------------------------------------------------------------
128  -- No Change Mode
129  -------------------------------------------------------------------------------------------------
130  NO_CHANGE_MODE : if MODE_G = "no-change" generate
131  -- Port A
132  process(clka)
133  begin
134  if rising_edge(clka) then
135  if (ena = '1') then
136  for i in 0 to NUM_BYTES_C-1 loop
137  if (weaByteInt(i) = '1') then
138  mem(conv_integer(addra))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
139  resize(dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
140  end if;
141  end loop;
142  end if;
143  end if;
144  end process;
145 
146  -- Vivado does crazy stupid things if output isn't broken out into its own process in
147  -- no-change mode
148  process (clka) is
149  begin
150  if (rising_edge(clka)) then
151  if (ena = '1' and weaByte = 0 and wea = '0') then
152  doutAInt <= mem(conv_integer(addra)) after TPD_G;
153  end if;
154  if rsta = RST_POLARITY_G and DOA_REG_G = false then
155  doutAInt <= INIT_C after TPD_G;
156  end if;
157  end if;
158  end process;
159 
160  -- Port B
161  process(clkb)
162  begin
163  if rising_edge(clkb) then
164  if (enb = '1') then
165  for i in 0 to NUM_BYTES_C-1 loop
166  if (webByteInt(i) = '1') then
167  mem(conv_integer(addrb))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
168  resize(dinb(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
169  end if;
170  end loop;
171  end if;
172  end if;
173  end process;
174 
175  process (clkb) is
176  begin
177  if (rising_edge(clkb)) then
178  if (enb = '1' and webByte = 0 and web = '0') then
179  doutBInt <= mem(conv_integer(addrb)) after TPD_G;
180  end if;
181  if rstb = RST_POLARITY_G and DOA_REG_G = false then
182  doutBInt <= INIT_C after TPD_G;
183  end if;
184  end if;
185  end process;
186 
187  end generate;
188 
189  -------------------------------------------------------------------------------------------------
190  -- Read first mode
191  -------------------------------------------------------------------------------------------------
192  READ_FIRST_MODE : if MODE_G = "read-first" generate
193  -- Port A
194  process(clka)
195  begin
196  if rising_edge(clka) then
197  if (ena = '1') then
198  doutAInt <= mem(conv_integer(addra)) after TPD_G;
199  for i in 0 to NUM_BYTES_C-1 loop
200  if (weaByteInt(i) = '1') then
201  mem(conv_integer(addra))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
202  resize(dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
203  end if;
204  end loop;
205  end if;
206  if rsta = RST_POLARITY_G and DOA_REG_G = false then
207  doutAInt <= INIT_C after TPD_G;
208  end if;
209  end if;
210  end process;
211 
212  -- Port B
213  process(clkb)
214  begin
215  if rising_edge(clkb) then
216  if (enb = '1') then
217  doutBInt <= mem(conv_integer(addrb)) after TPD_G;
218  for i in 0 to NUM_BYTES_C-1 loop
219  if (webByteInt(i) = '1') then
220  mem(conv_integer(addrb))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
221  resize(dinb(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
222  end if;
223  end loop;
224  end if;
225  if rstb = RST_POLARITY_G and DOB_REG_G = false then
226  doutBInt <= INIT_C after TPD_G;
227  end if;
228  end if;
229  end process;
230 
231  end generate;
232 
233  -------------------------------------------------------------------------------------------------
234  -- Write first mode
235  -------------------------------------------------------------------------------------------------
236  WRITE_FIRST_MODE : if MODE_G = "write-first" generate
237  -- Port A
238  process(clka)
239  begin
240  if rising_edge(clka) then
241  if (ena = '1') then
242  for i in 0 to NUM_BYTES_C-1 loop
243  if (weaByteInt(i) = '1') then
244  mem(conv_integer(addra))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
245  resize(dina(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
246  end if;
247  end loop;
248  doutAInt <= mem(conv_integer(addra)) after TPD_G;
249  end if;
250  if rsta = RST_POLARITY_G and DOA_REG_G = false then
251  doutAInt <= INIT_C after TPD_G;
252  end if;
253  end if;
254 
255  end process;
256 
257  -- Port B
258  process(clkb)
259  begin
260  if rising_edge(clkb) then
261  if (enb = '1') then
262  for i in 0 to NUM_BYTES_C-1 loop
263  if (webByteInt(i) = '1') then
264  mem(conv_integer(addrb))((i+1)*BYTE_WIDTH_C-1 downto i*BYTE_WIDTH_C) :=
265  resize(dinb(minimum(DATA_WIDTH_G-1, (i+1)*BYTE_WIDTH_C-1) downto i*BYTE_WIDTH_C), BYTE_WIDTH_C);
266  end if;
267  end loop;
268  doutBInt <= mem(conv_integer(addrb)) after TPD_G;
269  end if;
270  if rstb = RST_POLARITY_G and DOB_REG_G = false then
271  doutBInt <= INIT_C after TPD_G;
272  end if;
273  end if;
274 
275  end process;
276 
277  end generate;
278 
279  -------------------------------------------------------------------------------------------------
280  -- Optional data output registers
281  -------------------------------------------------------------------------------------------------
282  NO_DOUT_A_REG : if (not DOA_REG_G) generate
283  douta <= doutAInt(DATA_WIDTH_G-1 downto 0);
284  end generate NO_DOUT_A_REG;
285 
286  DOUT_A_REG : if (DOA_REG_G) generate
287  process (clka) is
288  begin
289  if (rising_edge(clka)) then
290  if (rstA = RST_POLARITY_G) then
291  douta <= (others => '0') after TPD_G;
292  elsif (regcea = '1') then
293  douta <= doutAInt(DATA_WIDTH_G-1 downto 0) after TPD_G;
294  end if;
295  end if;
296  end process;
297  end generate DOUT_A_REG;
298 
299  NO_DOUT_B_REG : if (not DOB_REG_G) generate
300  doutb <= doutBInt(DATA_WIDTH_G-1 downto 0);
301  end generate NO_DOUT_B_REG;
302 
303  DOUT_B_REG : if (DOB_REG_G) generate
304  process (clkb) is
305  begin
306  if (rising_edge(clkb)) then
307  if (rstB = RST_POLARITY_G) then
308  doutb <= (others => '0') after TPD_G;
309  elsif (regceb = '1') then
310  doutb <= doutBInt(DATA_WIDTH_G-1 downto 0) after TPD_G;
311  end if;
312  end if;
313  end process;
314  end generate DOUT_B_REG;
315 
316 end rtl;
in rstbsl :=not ( RST_POLARITY_G)
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 9
std_logic sl
Definition: StdRtlPkg.vhd:28
TPD_Gtime := 1 ns
in weaByteslv( wordCount( DATA_WIDTH_G, BYTE_WIDTH_G)- 1 downto 0) :=( others => '0')
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 18
BYTE_WR_EN_Gboolean := false
in webByteslv( wordCount( DATA_WIDTH_G, BYTE_WIDTH_G)- 1 downto 0) :=( others => '0')
out doutaslv( DATA_WIDTH_G- 1 downto 0)
DOB_REG_Gboolean := false
RST_POLARITY_Gsl := '1'
in regcebsl := '1'
in regceasl := '1'
in clkbsl := '0'
in addraslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
BYTE_WIDTH_Ginteger := 8
ALTERA_RAM_Gstring := "M9K"
DOA_REG_Gboolean := false
in rstasl :=not ( RST_POLARITY_G)
out doutbslv( DATA_WIDTH_G- 1 downto 0)
MODE_Gstring := "read-first"
in clkasl := '0'
in dinaslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
in dinbslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
in addrbslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')