1library ieee;
2use ieee.std_logic_1164.all,
3    ieee.numeric_std.all;
4
5entity tdp_ram is
6    generic (
7        ADDRWIDTH_A : positive := 12;
8        WIDTH_A     : positive := 8;
9
10        ADDRWIDTH_B : positive := 10;
11        WIDTH_B     : positive := 32;
12
13        COL_WIDTH : positive := 8
14    );
15    port (
16        clk_a        : in  std_logic;
17        read_a       : in  std_logic;
18        write_a      : in  std_logic;
19        byteen_a     : in  std_logic_vector(WIDTH_A/COL_WIDTH - 1 downto 0);
20        addr_a       : in  std_logic_vector(ADDRWIDTH_A - 1 downto 0);
21        data_read_a  : out std_logic_vector(WIDTH_A - 1 downto 0);
22        data_write_a : in  std_logic_vector(WIDTH_A - 1 downto 0);
23
24        clk_b        : in  std_logic;
25        read_b       : in  std_logic;
26        write_b      : in  std_logic;
27        byteen_b     : in  std_logic_vector(WIDTH_B/COL_WIDTH - 1 downto 0);
28        addr_b       : in  std_logic_vector(ADDRWIDTH_B - 1 downto 0);
29        data_read_b  : out std_logic_vector(WIDTH_B - 1 downto 0);
30        data_write_b : in  std_logic_vector(WIDTH_B - 1 downto 0)
31    );
32end tdp_ram;
33
34architecture behavioral of tdp_ram is
35    function log2(val : INTEGER) return natural is
36        variable res : natural;
37    begin
38        for i in 0 to 31 loop
39            if (val <= (2 ** i)) then
40                res := i;
41                exit;
42            end if;
43        end loop;
44
45        return res;
46    end function log2;
47
48    function eq_assert(x : integer; y : integer) return integer is
49    begin
50        assert x = y;
51        return x;
52    end function eq_assert;
53
54    constant COLS_A : positive := WIDTH_A / COL_WIDTH;
55    constant COLS_B : positive := WIDTH_B / COL_WIDTH;
56
57    constant TOTAL_COLS : positive := eq_assert(COLS_A * 2 ** ADDRWIDTH_A, COLS_B * 2 ** ADDRWIDTH_B);
58
59    constant EXTRA_ADDR_BITS_A : natural := log2(COLS_A);
60    constant EXTRA_ADDR_BITS_B : natural := log2(COLS_B);
61
62    type ram_t is array(0 to TOTAL_COLS - 1) of std_logic_vector(COL_WIDTH - 1 downto 0);
63    shared variable store : ram_t := (others => (others => '0'));
64
65    signal reg_a : std_logic_vector(WIDTH_A - 1 downto 0);
66    signal reg_b : std_logic_vector(WIDTH_B - 1 downto 0);
67begin
68    assert WIDTH_A mod COL_WIDTH = 0 and
69           WIDTH_B mod COL_WIDTH = 0 and
70           2 ** (ADDRWIDTH_A + EXTRA_ADDR_BITS_A) = TOTAL_COLS and
71           2 ** (ADDRWIDTH_B + EXTRA_ADDR_BITS_B) = TOTAL_COLS
72        report "Both WIDTH_A and WIDTH_B have to be a power-of-two multiple of COL_WIDTH"
73        severity failure;
74
75    process(clk_a)
76    begin
77        if rising_edge(clk_a) then
78            for i in 0 to COLS_A - 1 loop
79                if write_a = '1' and byteen_a(i) = '1' then
80                    store(to_integer(unsigned(addr_a) & to_unsigned(i, EXTRA_ADDR_BITS_A))) :=
81                        data_write_a((i+1) * COL_WIDTH - 1 downto i * COL_WIDTH);
82                end if;
83
84                if read_a = '1' then
85                    reg_a((i+1) * COL_WIDTH - 1 downto i * COL_WIDTH) <=
86                        store(to_integer(unsigned(addr_a) & to_unsigned(i, EXTRA_ADDR_BITS_A)));
87                end if;
88            end loop;
89
90            data_read_a <= reg_a;
91        end if;
92    end process;
93
94    process(clk_b)
95    begin
96        if rising_edge(clk_b) then
97            for i in 0 to COLS_B - 1 loop
98                if write_b = '1' and byteen_b(i) = '1' then
99                    store(to_integer(unsigned(addr_b) & to_unsigned(i, EXTRA_ADDR_BITS_B))) :=
100                        data_write_b((i+1) * COL_WIDTH - 1 downto i * COL_WIDTH);
101                end if;
102
103                if read_b = '1' then
104                    reg_b((i+1) * COL_WIDTH - 1 downto i * COL_WIDTH) <=
105                        store(to_integer(unsigned(addr_b) & to_unsigned(i, EXTRA_ADDR_BITS_B)));
106                end if;
107            end loop;
108
109            data_read_b <= reg_b;
110        end if;
111    end process;
112end behavioral;
113