Search code examples
vhdlcpu-registers

VHDL - Writing to FPGA Register


I have an FPGA with four push buttons - the two left most ones should cycle up and down the 16 registers, while the two right most ones should increment and decrement the value stored in this register. Here is my attempt at the code to do this:

entity raminfr is   --inferring the RAM here
    port (
        clk : in std_logic;
        we : in std_logic;
        a : in unsigned(3 downto 0);
        di : in unsigned(7 downto 0);
        do : out unsigned(7 downto 0)
    );
end raminfr;

architecture rtl of raminfr is

type ram_type is array (0 to 15) of unsigned(7 downto 0);
signal RAM : ram_type;
signal read_a : unsigned(3 downto 0);

begin
  U1: entity work.lab1 port map (  --ERROR ON THIS LINE
    register_counter => a,
    value_counter => di
  );
process (clk)
begin
    if rising_edge(clk) then
        if we = '1' then
            RAM(to_integer(a)) <= di;
        end if;
        read_a <= a;
    end if;
end process;
do <= RAM(to_integer(read_a));
end rtl;




--lab1 starts here
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity lab1 is 
    port(
        clock : in std_logic;
        key : in std_logic_vector(3 downto 0); 
        value_counter   : out unsigned(7 downto 0) ; --value to be written to register
        register_counter : out unsigned(3 downto 0) --register to write value to

        );
end lab1;

architecture up_and_down of lab1 is --actual button logic here
        begin
    process(clock)
        begin
            if rising_edge(clock) then
                if (key(3)='0' and key(2)='0' and key(1)='1' and key(0)='0') then
                    value_counter <= value_counter + "1";   
                elsif (key(3)='0' and key(2)='0' and key(1)='0' and key(0)='1') then  
                    value_counter <= value_counter - "1";
                elsif (key(3)='1' and key(2)='0' and key(1)='0' and key(0)='0') then
                    register_counter<= register_counter + "1";
                elsif (key(3)='0' and key(2)='1' and key(1)='0' and key(0)='0') then
                    register_counter<= register_counter - "1";
                end if;
            end if;
    end process;
end architecture up_and_down;

I get the error Error (10577): VHDL error at DE2_TOP.vhd(312): actual port "a" of mode "in" cannot be associated with formal port "register_counter" of mode "out"on the line indicated above. It is obvious this is not how I would go about doing what I want to do. Can someone shed some light on this?


Solution

  • Change your point of view: Put the RAM under the Pushbutton-FSM. Not vice versa.

    This RAM description should be synthesiable. If not take a look in the Synthesis Guide of your tool vendor.

    entity raminfr is   --inferring the RAM here
        port (
            clk : in  std_logic;
            we  : in  std_logic;
            a   : in  unsigned(3 downto 0);
            di  : in  unsigned(7 downto 0);
            do  : out unsigned(7 downto 0)
        );
    end entity raminfr;
    
    architecture rtl of raminfr is
    
    type ram_type is array (0 to 15) of unsigned(7 downto 0);
    signal RAM : ram_type;
    
    begin
      process (clk)
      begin
        if rising_edge(clk) then
            if we = '1' then
                RAM(to_integer(a)) <= di;
            end if;
            do <= RAM(to_integer(a));
        end if;
      end process;
    end architecture rtl;
    

    You also forgot to activate the write enable for the RAM. Maybe you try this code (Always do a simulation first!):

    --lab1 starts here
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    
    entity lab1 is 
      port(
        clock            : in std_logic;
        key              : in std_logic_vector(3 downto 0); 
        value_counter    : out unsigned(7 downto 0); --value to be written to register
        ram_data         : out unsigned(7 downto 0); --value from 'RAM-register'
        register_counter : out unsigned(3 downto 0) --register to write value to
      );
    end lab1;
    
    architecture up_and_down of lab1 is --actual button logic here
      signal value    : unsigned(7 downto 0) := (others => '0');
      signal ram_a    : unsigned(3 downto 0) := (others => '0');
      signal ram_we   : std_logic;
    
    begin
    
      -- infer your RAM
      your_ram:  entity work.raminfr
        port map (
          clk => clock,   --: in  std_logic;
          we  => ram_we,  --: in  std_logic;
          a   => ram_a,   --: in  unsigned(3 downto 0);
          di  => value,   --: in  unsigned(7 downto 0);
          do  => ram_data --: out unsigned(7 downto 0)
        );
    
      process(clock)
      begin
        if rising_edge(clock) then
          -- default
          ram_we <= '0';
    
          -- change value
          if key(1) = '1' then
            value <= value + 1;
          end if;
    
          -- change value
          if key(0) = '1' then
            value <= value - 1;
          end if;
    
          -- change 'register'
          if key(3) = '1' then
            ram_a  <= ram_a + 1;
          end if;
    
          -- write value to register
          if key(2) = '1' then
            ram_we <= '1';
          end if;
        end if;
      end process;
    
      value_counter    <= value;
      register_counter <= ram_a;
    
    end architecture up_and_down;