BRAM Example - red-bote/VHDL_Demos GitHub Wiki

The example project presented on this page demonstrates reading and writing a block RAM in VHDL.

images/bram/XlBYeU.png

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).

Next