BRAM Example - red-bote/VHDL_Demos GitHub Wiki
The example project presented on this page demonstrates reading and writing a block RAM in VHDL.
btn_U advances a counter through u_accum that in turn steps the address input of u_ram. SUM output of u_adder is connected to data input di of u_ram. The A input of u_adder is connected to the do output of u_ram. The B input of u_adder is connected to a std_logic_vector that is all 0 most of the time, except on the rising edge of btn_D the input B becomes a vector of "0001". The signal from btn_D is also wired to write enable port we on the RAM causing the incremented SUM to be stored at the presently addressed RAM location.
The address bus (6 bits) is connected to LEDs [15:10]. In the circuit shown in the diagram above, just the lower 4 data bits are connected to LEDs [3:0]. The accumulator width is intentionally limited to 4 bits so the btn_U is pushed 16 times to cycle the entire 4-bit address space. Similarly u_adder is 4-bits wide so btn_D can cycle the data space with 16 pushes.
The code below shows the top-level of the design. The de-bounce blocks were shown in the Accumulator Demo example. The accumulator and adder blocks are from xilinx_xstug_examples.
architecture Behavioral of rtl_top is
signal btn_U_deb : std_logic;
signal btn_D_deb : std_logic;
signal adder_sum : std_logic_vector (DATA_BITS-1 downto 0);
signal cnt_add : std_logic_vector (DATA_BITS-1 downto 0);
signal accum_inc : std_logic_vector ((ADDR_BITS-1) downto 0);
signal accum_out : std_logic_vector ((ADDR_BITS-1) downto 0);
-- RAM address is 6-bits
signal ram_addr : std_logic_vector (5 downto 0) := (others => '0');
signal ram_dout : std_logic_vector (DATA_BITS-1 downto 0);
signal ram_we : std_logic;
begin
u_btn_U_deb : entity work.btn_debounce
Port map (
clk => clk,
btn_inp => btnU,
btn_pressed => open,
btn_make => open,
btn_break => btn_U_deb
);
u_btn_D_deb : entity work.btn_debounce
Port map (
clk => clk,
btn_inp => btnD,
btn_pressed => open,
btn_make => btn_D_deb,
btn_break => open
);
p_address_inc : process(btn_U_deb)
begin
if btn_U_deb = '1' then
accum_inc <= (others => '0');
accum_inc(0) <= '1'; -- x"0001";
else
accum_inc <= (others => '0');
end if;
end process p_address_inc;
u_accum : entity work.accumulators_2
generic map (
WIDTH => ADDR_BITS)
port map (
clk => clk,
rst => reset,
D => accum_inc,-- in std_logic_vector(WIDTH-1 downto 0);
Q => accum_out -- out std_logic_vector(WIDTH-1 downto 0));
);
ram_addr <= "00" & accum_out; -- RAM address width is 6-bits
p_cntr_step : process(btn_D_deb)
begin
if btn_D_deb = '1' then
cnt_add <= (others => '0');
cnt_add(0) <= '1'; -- x"0001";
ram_we <= '1';
else
cnt_add <= (others => '0');
ram_we <= '0';
end if;
end process p_cntr_step;
u_adder_unsigned : entity work.adders_1
generic map (
WIDTH => DATA_BITS)
port map (
A => ram_dout,
B => cnt_add,
SUM => adder_sum
);
u_ram : entity work.rams_07
port map (
clk => clk,
we => ram_we,
a => ram_addr, -- in std_logic_vector(5 downto 0);
di => adder_sum, -- in std_logic_vector(15 downto 0);
do => ram_dout -- std_logic_vector(15 downto 0));
);
-- led(3 downto 0) <= ram_dout(3 downto 0); -- only display lower bits of data word
-- led(15 downto 10) <= ram_addr;
p_led_outp : process(clk)
begin
if rising_edge(clk) then
led <= ram_addr & -- 6
"000000" & -- 6
ram_dout(3 downto 0); -- 4
end if;
end process p_led_outp;
end Behavioral;
The output to external led ports occurs within the p_led_outp process synchronized with clk (led_reg in RTL schematic).