Skip to content
Snippets Groups Projects
Commit 545c969f authored by David Brouwer's avatar David Brouwer
Browse files

Created to be compatible with Agilex 7. Copied common_paged_ram_crw_crw.vhd...

Created to be compatible with Agilex 7. Copied common_paged_ram_crw_crw.vhd and modified it based on the entity ports of common_ram_cr_cw.vhd. Replaced information header and added purpose, description, remarks and reference.
parent 6839c742
No related branches found
No related tags found
1 merge request!363Porting ram for Intel Agilex 7
-- -----------------------------------------------------------------------------
--
-- Copyright 2023
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-- -----------------------------------------------------------------------------
--
-- Author:
-- D.F. Brouwer
-- Purpose:
-- Multi page memory with seperate clock and address per port with single wr
-- and single rd
-- Description:
-- When *_next_page pulses then the next access will occur in the next page.
-- Remarks:
-- . There are three architecture variants (default use "use_adr"):
-- . use_mux : Use multiplexer logic and one RAM per page
-- . use_adr : Use MSbit address lines and one buf RAM for all pages
-- . use_ofs : Use address offset adders and one buf RAM for all pages
-- . The "use_mux" variant requires the multiplexer logic but can be more
-- efficient regarding RAM usage than the "use_adr" variant.
-- The "use_ofs" variant requires address adder logic, but is optimal
-- regarding RAM usage in case the page size is not a power of 2, because the
-- pages are then mapped at subsequent addresses in the buf RAM.
-- . The "use_adr" variant is optimal for speed, so that is set as default.
--
-- . The crw_crw RAM covers all other variants, which were utilized by other
-- common RAM variant files. However, because the crw_crw IP is no longer
-- supported as it was previously used for previous FPGA technology identifiers
-- (device types) by the Agilex 7 (agi027_xxxx), the individual IPs should be
-- used. As a result, this file has been created. [1]
-- Reference:
-- [1] Based on the architecture of common_paged_ram_crw_crw.vhd.
library IEEE, technology_lib;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
library common_lib;
use work.common_pkg.all;
use work.common_mem_pkg.all;
use technology_lib.technology_select_pkg.all;
entity common_paged_ram_cr_cw is
generic (
g_technology : natural := c_tech_select_default;
g_str : string := "use_adr";
g_data_w : natural;
g_nof_pages : natural := 2; -- >= 2
g_page_sz : natural;
g_wr_start_page : natural := 0;
g_rd_start_page : natural := 0;
g_rd_latency : natural := 1
);
port (
-- Write port clock domain
wr_rst : in std_logic;
wr_clk : in std_logic;
wr_clken : in std_logic := '1';
wr_next_page : in std_logic;
wr_adr : in std_logic_vector(ceil_log2(g_page_sz) - 1 downto 0) := (others => '0');
wr_en : in std_logic := '0';
wr_dat : in std_logic_vector(g_data_w - 1 downto 0) := (others => '0');
-- Read port clock domain
rd_rst : in std_logic;
rd_clk : in std_logic;
rd_clken : in std_logic := '1';
rd_next_page : in std_logic;
rd_adr : in std_logic_vector(ceil_log2(g_page_sz) - 1 downto 0) := (others => '0');
rd_en : in std_logic := '1';
rd_dat : out std_logic_vector(g_data_w - 1 downto 0);
rd_val : out std_logic
);
end common_paged_ram_cr_cw;
architecture rtl of common_paged_ram_cr_cw is
type t_page_sel_arr is array (integer range <>) of natural range 0 to g_nof_pages - 1;
constant c_page_addr_w : natural := ceil_log2(g_page_sz);
-- g_str = "use_mux" :
constant c_page_ram : t_c_mem := (latency => g_rd_latency,
adr_w => c_page_addr_w,
dat_w => g_data_w,
nof_dat => g_page_sz,
init_sl => '0');
type t_data_arr is array (integer range <>) of std_logic_vector(g_data_w - 1 downto 0);
-- g_str = "use_adr" :
constant c_mem_nof_pages_w : natural := true_log2(g_nof_pages);
constant c_mem_addr_w : natural := c_mem_nof_pages_w + c_page_addr_w;
constant c_mem_nof_words : natural := g_nof_pages * 2**c_page_addr_w; -- <= 2**c_mem_addr_w
constant c_mem_ram : t_c_mem := (latency => g_rd_latency,
adr_w => c_mem_addr_w,
dat_w => g_data_w,
nof_dat => c_mem_nof_words,
init_sl => '0');
-- g_str = "use_ofs" :
constant c_buf_addr_w : natural := ceil_log2(g_nof_pages * g_page_sz);
constant c_buf_nof_words : natural := g_nof_pages * g_page_sz;
constant c_buf_ram : t_c_mem := (latency => g_rd_latency,
adr_w => c_buf_addr_w,
dat_w => g_data_w,
nof_dat => c_buf_nof_words,
init_sl => '0');
-- >>> Page control
-- g_str = "use_mux" and g_str = "use_adr" :
-- . use page_sel direct for wr_en, rd_en, and address
signal page_sel_wr : natural range 0 to g_nof_pages - 1;
signal nxt_page_sel_wr : natural;
signal page_sel_rd : natural range 0 to g_nof_pages - 1;
signal nxt_page_sel_rd : natural;
-- . use page_sel_dly to adjust for g_rd_latency of rd_dat and rd_val
signal page_sel_wr_dly : t_page_sel_arr(0 to g_rd_latency - 1);
signal nxt_page_sel_wr_dly : t_page_sel_arr(0 to g_rd_latency - 1);
signal page_sel_rd_dly : t_page_sel_arr(0 to g_rd_latency - 1);
signal nxt_page_sel_rd_dly : t_page_sel_arr(0 to g_rd_latency - 1);
-- g_str = "use_ofs" :
signal page_ofs_wr : natural range 0 to c_buf_nof_words - 1;
signal nxt_page_ofs_wr : natural;
signal page_ofs_rd : natural range 0 to c_buf_nof_words - 1;
signal nxt_page_ofs_rd : natural;
-- >>> Access control
-- g_str = "use_mux" :
signal page_wr_en : std_logic_vector(0 to g_nof_pages - 1);
signal page_wr_dat : t_data_arr(0 to g_nof_pages - 1);
signal page_rd_en : std_logic_vector(0 to g_nof_pages - 1);
signal page_rd_dat : t_data_arr(0 to g_nof_pages - 1);
signal page_rd_val : std_logic_vector(0 to g_nof_pages - 1);
-- g_str = "use_adr" :
signal mem_wr_adr : std_logic_vector(c_mem_addr_w - 1 downto 0);
signal mem_rd_adr : std_logic_vector(c_mem_addr_w - 1 downto 0);
-- g_str = "use_ofs" :
signal buf_wr_adr : std_logic_vector(c_buf_addr_w - 1 downto 0);
signal buf_rd_adr : std_logic_vector(c_buf_addr_w - 1 downto 0);
begin
-- page select (for all) and page address offset (for use_ofs)
p_reg_wr : process (wr_rst, wr_clk)
begin
if wr_rst = '1' then
page_sel_wr <= g_wr_start_page;
page_sel_wr_dly <= (others => g_wr_start_page);
page_ofs_wr <= g_wr_start_page * g_page_sz;
elsif rising_edge(wr_clk) then
page_sel_wr <= nxt_page_sel_wr;
page_sel_wr_dly <= nxt_page_sel_wr_dly;
page_ofs_wr <= nxt_page_ofs_wr;
end if;
end process;
p_reg_rd : process (rd_rst, rd_clk)
begin
if rd_rst = '1' then
page_sel_rd <= g_rd_start_page;
page_sel_rd_dly <= (others => g_rd_start_page);
page_ofs_rd <= g_rd_start_page * g_page_sz;
elsif rising_edge(rd_clk) then
page_sel_rd <= nxt_page_sel_rd;
page_sel_rd_dly <= nxt_page_sel_rd_dly;
page_ofs_rd <= nxt_page_ofs_rd;
end if;
end process;
nxt_page_sel_wr_dly(0) <= page_sel_wr;
nxt_page_sel_wr_dly(1 to g_rd_latency - 1) <= page_sel_wr_dly(0 to g_rd_latency - 2);
nxt_page_sel_rd_dly(0) <= page_sel_rd;
nxt_page_sel_rd_dly(1 to g_rd_latency - 1) <= page_sel_rd_dly(0 to g_rd_latency - 2);
p_wr_next_page : process(wr_next_page, page_sel_wr, page_ofs_wr)
begin
nxt_page_sel_wr <= page_sel_wr;
nxt_page_ofs_wr <= page_ofs_wr;
if wr_next_page = '1' then
if page_sel_wr < g_nof_pages - 1 then
nxt_page_sel_wr <= page_sel_wr + 1;
nxt_page_ofs_wr <= page_ofs_wr + g_page_sz;
else
nxt_page_sel_wr <= 0;
nxt_page_ofs_wr <= 0;
end if;
end if;
end process;
p_rd_next_page : process(rd_next_page, page_sel_rd, page_ofs_rd)
begin
nxt_page_sel_rd <= page_sel_rd;
nxt_page_ofs_rd <= page_ofs_rd;
if rd_next_page = '1' then
if page_sel_rd < g_nof_pages - 1 then
nxt_page_sel_rd <= page_sel_rd + 1;
nxt_page_ofs_rd <= page_ofs_rd + g_page_sz;
else
nxt_page_sel_rd <= 0;
nxt_page_ofs_rd <= 0;
end if;
end if;
end process;
gen_mux : if g_str = "use_mux" generate
gen_pages : for I in 0 to g_nof_pages - 1 generate
u_ram : entity work.common_ram_cr_cw
generic map (
g_technology => g_technology,
g_ram => c_page_ram,
g_init_file => "UNUSED"
)
port map (
wr_rst => wr_rst,
wr_clk => wr_clk,
wr_clken => wr_clken,
rd_rst => rd_rst,
rd_clk => rd_clk,
rd_clken => rd_clken,
wr_adr => wr_adr,
wr_en => page_wr_en(I),
wr_dat => wr_dat,
rd_adr => rd_adr,
rd_en => page_rd_en(I),
rd_dat => page_rd_dat(I),
rd_val => page_rd_val(I)
);
end generate;
p_mux : process(page_sel_wr, wr_en, page_sel_wr_dly, page_sel_rd,
rd_en, page_sel_rd_dly, page_rd_dat, page_rd_val)
begin
-- use page_sel direct for control
page_wr_en <= (others => '0');
page_rd_en <= (others => '0');
page_wr_en(page_sel_wr) <= wr_en;
page_rd_en(page_sel_rd) <= rd_en;
-- use page_sel_dly to account for the RAM read latency
rd_dat <= page_rd_dat(page_sel_rd_dly(g_rd_latency - 1));
rd_val <= page_rd_val(page_sel_rd_dly(g_rd_latency - 1));
end process;
end generate; -- gen_mux
gen_adr : if g_str = "use_adr" generate
u_mem : entity work.common_ram_cr_cw
generic map (
g_technology => g_technology,
g_ram => c_mem_ram,
g_init_file => "UNUSED"
)
port map (
wr_rst => wr_rst,
wr_clk => wr_clk,
wr_clken => wr_clken,
rd_rst => rd_rst,
rd_clk => rd_clk,
rd_clken => rd_clken,
wr_adr => mem_wr_adr,
wr_en => wr_en,
wr_dat => wr_dat,
rd_adr => mem_rd_adr,
rd_en => rd_en,
rd_dat => rd_dat,
rd_val => rd_val
);
mem_wr_adr <= TO_UVEC(page_sel_wr, c_mem_nof_pages_w) & wr_adr;
mem_rd_adr <= TO_UVEC(page_sel_rd, c_mem_nof_pages_w) & rd_adr;
end generate; -- gen_adr
gen_ofs : if g_str = "use_ofs" generate
u_buf : entity work.common_ram_cr_cw
generic map (
g_technology => g_technology,
g_ram => c_buf_ram,
g_init_file => "UNUSED"
)
port map (
wr_rst => wr_rst,
wr_clk => wr_clk,
wr_clken => wr_clken,
rd_rst => rd_rst,
rd_clk => rd_clk,
rd_clken => rd_clken,
wr_adr => buf_wr_adr,
wr_en => wr_en,
wr_dat => wr_dat,
rd_adr => buf_rd_adr,
rd_en => rd_en,
rd_dat => rd_dat,
rd_val => rd_val
);
buf_wr_adr <= INCR_UVEC(RESIZE_UVEC(wr_adr, c_buf_addr_w), page_ofs_wr);
buf_rd_adr <= INCR_UVEC(RESIZE_UVEC(rd_adr, c_buf_addr_w), page_ofs_rd);
end generate; -- gen_ofs
end rtl;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment