SURF  1.0
AxiDualPortRam.vhd
Go to the documentation of this file.
1 -------------------------------------------------------------------------------
2 -- File : AxiDualPortRam.vhd
3 -- Company : SLAC National Accelerator Laboratory
4 -- Created : 2013-12-17
5 -- Last update: 2017-01-11
6 -------------------------------------------------------------------------------
7 -- Description: A wrapper of StdLib DualPortRam that places an AxiLite
8 -- interface on the read/write port.
9 -------------------------------------------------------------------------------
10 -- This file is part of 'SLAC Firmware Standard Library'.
11 -- It is subject to the license terms in the LICENSE.txt file found in the
12 -- top-level directory of this distribution and at:
13 -- https://confluence.slac.stanford.edu/display/ppareg/LICENSE.html.
14 -- No part of 'SLAC Firmware Standard Library', including this file,
15 -- may be copied, modified, propagated, or distributed except according to
16 -- the terms contained in the LICENSE.txt file.
17 -------------------------------------------------------------------------------
18 
19 library ieee;
20 use ieee.std_logic_1164.all;
21 use ieee.std_logic_arith.all;
22 use ieee.std_logic_unsigned.all;
23 
24 use work.StdRtlPkg.all;
25 use work.AxiLitePkg.all;
26 
27 --! @see entity
28  --! @ingroup axi
29 entity AxiDualPortRam is
30 
31  generic (
32  TPD_G : time := 1 ns;
33  BRAM_EN_G : boolean := false;
34  REG_EN_G : boolean := true;
35  MODE_G : string := "read-first";
36  AXI_WR_EN_G : boolean := true;
37  SYS_WR_EN_G : boolean := false;
38  SYS_BYTE_WR_EN_G : boolean := false;
39  COMMON_CLK_G : boolean := false;
40  ADDR_WIDTH_G : integer range 1 to (2**24) := 5;
41  DATA_WIDTH_G : integer := 32;
42  INIT_G : slv := "0";
44 
45  port (
46  -- Axi Port
47  axiClk : in sl;
48  axiRst : in sl;
53 
54  -- Standard Port
55  clk : in sl := '0';
56  en : in sl := '1';
57  we : in sl := '0';
58  weByte : in slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0) := (others => '0');
59  rst : in sl := '0';
60  addr : in slv(ADDR_WIDTH_G-1 downto 0) := (others => '0');
61  din : in slv(DATA_WIDTH_G-1 downto 0) := (others => '0');
62  dout : out slv(DATA_WIDTH_G-1 downto 0);
63  axiWrValid : out sl;
64  axiWrStrobe : out slv(wordCount(DATA_WIDTH_G, 8)-1 downto 0);
65  axiWrAddr : out slv(ADDR_WIDTH_G-1 downto 0);
66  axiWrData : out slv(DATA_WIDTH_G-1 downto 0));
67 
68 end entity AxiDualPortRam;
69 
70 architecture rtl of AxiDualPortRam is
71 
72  -- Number of Axi address bits that need to be manually decoded
73  constant AXI_DEC_BITS_C : integer := ite(DATA_WIDTH_G <= 32, 0, log2((DATA_WIDTH_G-1)/32));
74  subtype AXI_DEC_ADDR_RANGE_C is integer range 1+AXI_DEC_BITS_C downto 2;
75  subtype AXI_RAM_ADDR_RANGE_C is integer range ADDR_WIDTH_G+AXI_DEC_ADDR_RANGE_C'high downto AXI_DEC_ADDR_RANGE_C'high+1;
76 
77 
78  constant ADDR_AXI_WORDS_C : natural := wordCount(DATA_WIDTH_G, 32);
79  constant ADDR_AXI_BYTES_C : natural := wordCount(DATA_WIDTH_G, 8);
80  constant RAM_WIDTH_C : natural := ADDR_AXI_WORDS_C*32;
81  constant STRB_WIDTH_C : natural := minimum(4, ADDR_AXI_BYTES_C);
82 
83  type RegType is record
86  axiAddr : slv(ADDR_WIDTH_G-1 downto 0);
87  axiWrStrobe : slv(ADDR_AXI_WORDS_C*4-1 downto 0);
88  axiRdEn : slv(2 downto 0);
89  end record;
90 
91  constant REG_INIT_C : RegType := (
94  axiAddr => (others => '0'),
95  axiWrStrobe => (others => '0'),
96  axiRdEn => (others => '0'));
97 
98  signal r : RegType := REG_INIT_C;
99  signal rin : RegType;
100 
101  signal axiWrDataFanout : slv(RAM_WIDTH_C-1 downto 0);
102  signal axiDout : slv(RAM_WIDTH_C-1 downto 0) := (others => '0');
103 
104  signal axiSyncWrEn : sl;
105  signal axiSyncIn : slv(DATA_WIDTH_G + ADDR_WIDTH_G + ADDR_AXI_BYTES_C - 1 downto 0);
106  signal axiSyncOut : slv(DATA_WIDTH_G + ADDR_WIDTH_G + ADDR_AXI_BYTES_C - 1 downto 0);
107 
108 begin
109 
110 
111  -- AXI read only, sys writable or read only (rom)
112  AXI_R0_SYS_RW : if (not AXI_WR_EN_G and SYS_WR_EN_G) generate
113  DualPortRam_1 : entity work.DualPortRam
114  generic map (
115  TPD_G => TPD_G,
116  BRAM_EN_G => BRAM_EN_G,
117  REG_EN_G => REG_EN_G,
118  DOA_REG_G => REG_EN_G,
119  DOB_REG_G => REG_EN_G,
120  MODE_G => MODE_G,
124  INIT_G => INIT_G)
125  port map (
126  clka => clk,
127  ena => en,
128  wea => we,
129  weaByte => weByte,
130  rsta => rst,
131  addra => addr,
132  dina => din,
133  douta => dout,
134 
135  clkb => axiClk,
136  enb => '1',
137  rstb => '0',
138  addrb => r.axiAddr,
139  doutb => axiDout(DATA_WIDTH_G-1 downto 0));
140  end generate;
141 
142  -- System Read only, Axi writable or read only (ROM)
143  -- Logic disables axi writes if AXI_WR_EN_G=false
144  AXI_RW_SYS_RO : if (not SYS_WR_EN_G) generate
145  DualPortRam_1 : entity work.DualPortRam
146  generic map (
147  TPD_G => TPD_G,
148  BRAM_EN_G => BRAM_EN_G,
149  REG_EN_G => REG_EN_G,
150  DOA_REG_G => REG_EN_G,
151  DOB_REG_G => REG_EN_G,
152  MODE_G => MODE_G,
153  BYTE_WR_EN_G => true,
155  BYTE_WIDTH_G => 8,
157  INIT_G => INIT_G)
158  port map (
159  clka => axiClk,
160  ena => '1',
161  weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0),
162  rsta => '0',
163  addra => r.axiAddr,
164  dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0),
165  douta => axiDout(DATA_WIDTH_G-1 downto 0),
166  clkb => clk,
167  enb => en,
168  rstb => rst,
169  addrb => addr,
170  doutb => dout);
171  end generate;
172 
173 -- -- Both sides writable, true dual port ram
174  AXI_RW_SYS_RW : if (AXI_WR_EN_G and SYS_WR_EN_G) generate
175  U_TrueDualPortRam_1 : entity work.TrueDualPortRam
176  generic map (
177  TPD_G => TPD_G,
178  MODE_G => MODE_G,
179  BYTE_WR_EN_G => true,
180  DOA_REG_G => REG_EN_G,
181  DOB_REG_G => REG_EN_G,
183  BYTE_WIDTH_G => 8,
185  INIT_G => INIT_G)
186  port map (
187  clka => axiClk, -- [in]
188  ena => '1', -- [in]
189  wea => '1',
190  weaByte => r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0),
191  rsta => '0', -- [in]
192  addra => r.axiAddr, -- [in]
193  dina => axiWrDataFanout(DATA_WIDTH_G-1 downto 0), -- [in]
194  douta => axiDout(DATA_WIDTH_G-1 downto 0), -- [out]
195  clkb => clk, -- [in]
196  enb => en, -- [in]
197  web => we, -- [in]
198  webByte => weByte, -- [in]
199  rstb => rst, -- [in]
200  addrb => addr, -- [in]
201  dinb => din, -- [in]
202  doutb => dout); -- [out]
203 
204  end generate;
205 
206  axiSyncIn(DATA_WIDTH_G-1 downto 0)
207  <= axiWrDataFanout(DATA_WIDTH_G-1 downto 0);
208  axiSyncIn(ADDR_WIDTH_G+DATA_WIDTH_G-1 downto DATA_WIDTH_G)
209  <= r.axiAddr;
210  axiSyncIn(ADDR_WIDTH_G+DATA_WIDTH_G+ADDR_AXI_BYTES_C-1 downto ADDR_WIDTH_G+DATA_WIDTH_G)
211  <= r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0);
212  axiSyncWrEn <= uOr(r.axiWrStrobe(ADDR_AXI_BYTES_C-1 downto 0));
213  U_SynchronizerFifo_1 : entity work.SynchronizerFifo
214  generic map (
215  TPD_G => TPD_G,
217  BRAM_EN_G => false,
218  DATA_WIDTH_G => ADDR_WIDTH_G+DATA_WIDTH_G+ADDR_AXI_BYTES_C)
219  port map (
220  rst => rst, -- [in]
221  wr_clk => axiClk, -- [in]
222  wr_en => axiSyncWrEn, -- [in]
223  din => axiSyncIn, -- [in]
224  rd_clk => clk, -- [in]
225  rd_en => '1', -- [in]
226  valid => axiWrValid, -- [out]
227  dout => axiSyncOut); -- [out]
228 
229  axiWrData <= axiSyncOut(DATA_WIDTH_G-1 downto 0);
230  axiWrAddr <= axiSyncOut(ADDR_WIDTH_G+DATA_WIDTH_G-1 downto DATA_WIDTH_G);
231  axiWrStrobe <= axiSyncOut(ADDR_WIDTH_G+DATA_WIDTH_G+ADDR_AXI_BYTES_C-1 downto ADDR_WIDTH_G+DATA_WIDTH_G);
232 
233 
234  axiWrMap : for i in 0 to ADDR_AXI_WORDS_C-1 generate
235  axiWrDataFanout((i+1)*32-1 downto i*32) <= axiWriteMaster.wdata;
236  end generate axiWrMap;
237 
238  comb : process (axiDout, axiReadMaster, axiRst, axiWriteMaster, r) is
239  variable v : RegType;
240  variable axiStatus : AxiLiteStatusType;
241  variable decAddrInt : integer;
242  begin
243  v := r;
244 
245 
246  -- Reset strobes and shift Register
247  v.axiWrStrobe := (others => '0');
248  v.axiRdEn(0) := '0';
249  v.axiRdEn(1) := r.axiRdEn(0);
250  v.axiRdEn(2) := r.axiRdEn(1);
251 
252 
254  v.axiReadSlave.rdata := (others => '0');
255 
256 
257  -- Multiplex read data onto axi bus
258  decAddrInt := conv_integer(axiReadMaster.araddr(AXI_DEC_ADDR_RANGE_C));
259  v.axiReadSlave.rdata := axiDout((decAddrInt+1)*32-1 downto decAddrInt*32);
260 
261  -- Set axiAddr to read address by default
262  v.axiAddr := axiReadMaster.araddr(AXI_RAM_ADDR_RANGE_C);
263 
264  -- Don't allow a write if a read is active
265  if (axiStatus.writeEnable = '1' and r.axiRdEn = "000") then
266  if (AXI_WR_EN_G) then
267  v.axiAddr := axiWriteMaster.awaddr(AXI_RAM_ADDR_RANGE_C);
268  decAddrInt := conv_integer(axiWriteMaster.awaddr(AXI_DEC_ADDR_RANGE_C));
269  v.axiWrStrobe((decAddrInt+1)*4-1 downto decAddrInt*4) :=
271  end if;
272  axiSlaveWriteResponse(v.axiWriteSlave, ite(AXI_WR_EN_G, AXI_RESP_OK_C, AXI_RESP_SLVERR_C));
273 
274 
275  elsif (axiStatus.readEnable = '1' and r.axiRdEn = "000") then
276  -- Set the address bus
277  v.axiAddr := axiReadMaster.araddr(AXI_RAM_ADDR_RANGE_C);
278  -- Check for registered BRAM
279  if (BRAM_EN_G = true) and (REG_EN_G = true) then
280  v.axiRdEn := "001"; -- read in 3 cycles
281  -- Check for non-registered BRAM
282  elsif (BRAM_EN_G = true) and (REG_EN_G = false) then
283  v.axiRdEn := "010"; -- read in 2 cycles
284  -- Check for registered LUTRAM
285  elsif (BRAM_EN_G = false) and (REG_EN_G = true) then
286  v.axiRdEn := "010"; -- read in 2 cycles
287  -- Else non-registered LUTRAM
288  else
289  v.axiRdEn := "100"; -- read on next cycle
290  end if;
291  end if;
292 
293  if (r.axiRdEn(2) = '1') then
294  axiSlaveReadResponse(v.axiReadSlave);
295  end if;
296 
297  if (axiRst = '1') then
298  v := REG_INIT_C;
299  end if;
300 
301  rin <= v;
304 
305  end process comb;
306 
307  seq : process (axiClk) is
308  begin
309  if (rising_edge(axiClk)) then
310  r <= rin after TPD_G;
311  end if;
312  end process seq;
313 
314 end architecture rtl;
in enbsl := '1'
Definition: DualPortRam.vhd:54
out axiWrAddrslv( ADDR_WIDTH_G- 1 downto 0)
BRAM_EN_Gboolean := true
Definition: DualPortRam.vhd:31
in addrslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
in rstbsl :=not ( RST_POLARITY_G)
AXI_ERROR_RESP_Gslv( 1 downto 0) := AXI_RESP_DECERR_C
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 9
SYS_BYTE_WR_EN_Gboolean := false
AxiLiteWriteMasterType
Definition: AxiLitePkg.vhd:111
std_logic sl
Definition: StdRtlPkg.vhd:28
TPD_Gtime := 1 ns
in dinslv( DATA_WIDTH_G- 1 downto 0)
out doutbslv( DATA_WIDTH_G- 1 downto 0)
Definition: DualPortRam.vhd:57
in weaByteslv( wordCount( DATA_WIDTH_G, BYTE_WIDTH_G)- 1 downto 0) :=( others => '0')
TPD_Gtime := 1 ns
Definition: DualPortRam.vhd:29
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 18
TPD_Gtime := 1 ns
slv( 31 downto 0) rdata
Definition: AxiLitePkg.vhd:89
BYTE_WR_EN_Gboolean := false
out doutslv( DATA_WIDTH_G- 1 downto 0)
DATA_WIDTH_Ginteger := 32
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 4
Definition: DualPortRam.vhd:39
in webByteslv( wordCount( DATA_WIDTH_G, BYTE_WIDTH_G)- 1 downto 0) :=( others => '0')
BRAM_EN_Gboolean := false
MODE_Gstring := "read-first"
Definition: DualPortRam.vhd:35
out doutaslv( DATA_WIDTH_G- 1 downto 0)
INIT_Gslv := "0"
in clkasl := '0'
Definition: DualPortRam.vhd:43
BYTE_WR_EN_Gboolean := false
Definition: DualPortRam.vhd:36
slv( 31 downto 0) wdata
Definition: AxiLitePkg.vhd:117
out doutslv( DATA_WIDTH_G- 1 downto 0)
AxiLiteStatusType axiStatus
Definition: AxiLitePkg.vhd:183
slv( 1 downto 0) := "10" AXI_RESP_SLVERR_C
Definition: AxiLitePkg.vhd:36
out axiReadSlaveAxiLiteReadSlaveType
COMMON_CLK_Gboolean := false
slv( 1 downto 0) := "11" AXI_RESP_DECERR_C
Definition: AxiLitePkg.vhd:49
in clksl := '0'
in clkbsl := '0'
Definition: DualPortRam.vhd:53
DOB_REG_Gboolean := false
Definition: DualPortRam.vhd:34
in axiWriteMasterAxiLiteWriteMasterType
COMMON_CLK_Gboolean := false
INIT_Gslv := "0"
Definition: DualPortRam.vhd:40
out doutaslv( DATA_WIDTH_G- 1 downto 0)
Definition: DualPortRam.vhd:50
SYS_WR_EN_Gboolean := false
in enasl := '1'
Definition: DualPortRam.vhd:44
DOB_REG_Gboolean := false
AxiLiteReadMasterType
Definition: AxiLitePkg.vhd:59
in weByteslv( wordCount( DATA_WIDTH_G, 8)- 1 downto 0) :=( others => '0')
in addrbslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
Definition: DualPortRam.vhd:56
in weaByteslv( wordCount( DATA_WIDTH_G, BYTE_WIDTH_G)- 1 downto 0) :=( others => '1')
Definition: DualPortRam.vhd:46
in weasl := '0'
Definition: DualPortRam.vhd:45
slv( 31 downto 0) awaddr
Definition: AxiLitePkg.vhd:113
out axiWrDataslv( DATA_WIDTH_G- 1 downto 0)
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
Definition: DualPortRam.vhd:37
AxiLiteReadSlaveType :=(arready => '0',rdata =>( others => '0'),rresp =>( others => '0'),rvalid => '0') AXI_LITE_READ_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:95
in rstasl :=not ( RST_POLARITY_G)
Definition: DualPortRam.vhd:47
in clkbsl := '0'
BYTE_WIDTH_Ginteger := 8
Definition: DualPortRam.vhd:38
in addraslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
in dinaslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
Definition: DualPortRam.vhd:49
REG_EN_Gboolean := true
Definition: DualPortRam.vhd:32
DOA_REG_Gboolean := false
Definition: DualPortRam.vhd:33
AxiLiteReadSlaveType
Definition: AxiLitePkg.vhd:85
in wesl := '0'
in rstsl := '0'
in axiReadMasterAxiLiteReadMasterType
in ensl := '1'
out axiWriteSlaveAxiLiteWriteSlaveType
BYTE_WIDTH_Ginteger := 8
in dinslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
slv( 1 downto 0) := "00" AXI_RESP_OK_C
Definition: AxiLitePkg.vhd:31
BRAM_EN_Gboolean := false
DOA_REG_Gboolean := false
slv( 31 downto 0) araddr
Definition: AxiLitePkg.vhd:61
in rstasl :=not ( RST_POLARITY_G)
slv( 3 downto 0) wstrb
Definition: AxiLitePkg.vhd:118
out doutbslv( DATA_WIDTH_G- 1 downto 0)
in addraslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')
Definition: DualPortRam.vhd:48
MODE_Gstring := "read-first"
ADDR_WIDTH_Ginteger range 1 to ( 2** 24):= 5
REG_EN_Gboolean := true
MODE_Gstring := "read-first"
in clkasl := '0'
out axiWrStrobeslv( wordCount( DATA_WIDTH_G, 8)- 1 downto 0)
in rstbsl :=not ( RST_POLARITY_G)
Definition: DualPortRam.vhd:55
AxiLiteWriteSlaveType :=(awready => '0',wready => '0',bresp =>( others => '0'),bvalid => '0') AXI_LITE_WRITE_SLAVE_INIT_C
Definition: AxiLitePkg.vhd:156
in dinaslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
AXI_WR_EN_Gboolean := true
in dinbslv( DATA_WIDTH_G- 1 downto 0) :=( others => '0')
_library_ ieeeieee
Definition: AxiDmaPkg.vhd:19
DATA_WIDTH_Ginteger range 1 to ( 2** 24):= 16
std_logic_vector slv
Definition: StdRtlPkg.vhd:29
in addrbslv( ADDR_WIDTH_G- 1 downto 0) :=( others => '0')