Global training solutions for engineers creating the world's electronics

6-port Register File

Here we present a 6-port Register File model. The logical function of a register file is very simple, it is after all the identity function, but once you start adding multiple read and write ports the complexity of modelling such a device seems to grow at an alarming rate.

This register file has 3 write and 3 read ports and a depth of 32 8-bit registers.

When it comes to coding up the design, there are a couple of key choices to make - behavioural or structural coding style. I trod the structural path as this allowed me to play with a variety of VHDL coding techniques. It also seemed that a behavioural approach wouldn't be as challenging...

From the code, you can see that quite a few generate statements are used. Sometimes the generate loop uses an array attribute, sometimes it uses a constant for the loop parameter. Many of the internal signals required the definition of their own data type. This was a synthesis tool constraint rather than a modelling decision, but that's another story. I also decided to mix multi-dimensional array indexing approaches. The register file ports and the latch actual signals are 2-index arrays whereas most of the other signals are arrays of vectors.

To implement the register file in a reasonably efficient way, I opted to use latches as the storage elements rather than flip-flops. There is no write address port conflict arbitration as yet.

You are welcome to use the source code we provide but you must keep the copyright notice with the code (see the Notices page for details).

 

library IEEE;
  use IEEE.std_logic_1164.all;
  use work.reg_file_pkg.all;
  use work.components.all;

entity reg_file_32_8_6port is
generic (
  num_write_ports : integer := 1;
  num_read_ports  : integer := 1;
  num_bidirectional_ports : integer := 0
);
port (
  write    : in std_logic_vector(((num_write_ports-1) + num_bidirectional_ports) downto 0);
  read     : in std_logic_vector((( num_read_ports-1) + num_bidirectional_ports) downto 0);
  address_write : in std_logic_2D_array(0 to 2, 4 downto 0);
  address_read  : in std_logic_2D_array(0 to 2, 4 downto 0);
  data_in  : in  std_logic_2D_array(0 to 2, 7 downto 0);
  data_out : out std_logic_2D_array(0 to 2, 7 downto 0)
);
end reg_file_32_8_6port;

architecture modular of reg_file_32_8_6port is

  constant depth : integer := 32;
  constant data_width : integer := 8;

  constant num_input_ports  : integer := num_write_ports + num_bidirectional_ports;
  constant num_output_ports : integer := num_read_ports  + num_bidirectional_ports;

  type select_bus is array (0 to num_input_ports-1) of std_logic_vector(depth-1 downto 0);
  -- 3 busses, 32 bits wide
  type address_write_bus is array (0 to num_input_ports-1) of std_logic_vector(log_2(depth)-1 downto 0);
  type address_read_bus  is array (0 to num_output_ports-1) of std_logic_vector(log_2(depth)-1 downto 0);
  type data_write_bus is array (0 to num_input_ports-1) of std_logic_vector(data_width-1 downto 0);
  type data_read_bus is array (0 to num_output_ports-1) of std_logic_vector(data_width-1 downto 0);

  signal data_WR_select : select_bus;

  signal addr_WR : address_write_bus;
  signal addr_RD : address_read_bus;
  signal WE_WR : std_logic_vector(0 to num_input_ports-1);
  signal OE_RD : std_logic_vector(0 to num_output_ports-1);

  signal data_WR : data_write_bus;
  signal latch_array_in  : std_logic_2D_array(0 to depth-1, data_width-1 downto 0);
  signal latch_array_out : std_logic_2D_array(0 to depth-1, data_width-1 downto 0);
  signal mux_out : data_read_bus;
  signal en : std_logic_vector(0 to depth-1);

begin

  s2: WE_WR <= not write;
  s3: OE_RD <= read;

  g3: for i in 0 to num_input_ports-1 generate
    g4: for j in 0 to log_2(depth)-1 generate
      addr_WR(i)(j) <= address_write(i, j);
    end generate g4;
    decode_addr_WR: demux_generic generic map (
      in_width => log_2(depth)
    ) port map (
      a      => addr_WR(i),
      enable => WE_WR(i),
      y      => data_WR_select(i)

    );
  end generate g3;

  g5: for i in data_in'RANGE(1) generate
    g6: for j in 0 to data_width-1 generate
      data_WR(i)(j) <= data_in(i, j);
    end generate g6;
  end generate g5;

  data_mux_selects: process (data_WR, data_WR_select)
    variable enable : std_logic_vector(0 to depth-1);
  begin
    for k in 0 to depth-1 loop
      for i in 0 to data_width-1 loop
        latch_array_in(k,i) <= data_WR(0)(i);
      end loop;
      enable(k) := '0';
      for j in 0 to num_input_ports-1 loop
        enable(k) := data_WR_select(j)(k) or enable(k);
      end loop;
      en(k) <= not enable(k);
      for j in 0 to num_input_ports-1 loop
        if data_WR_select(j)(k) = '1' then
          for i in 0 to data_width-1 loop
            latch_array_in(k,i) <= data_WR(j)(i);
          end loop;
        end if;
      end loop;
    end loop;
  end process;

  g0: for i in 0 to depth-1 generate
    g1: for j in 0 to data_width-1 generate
      latch_instance: d_latch port map (
        d      => latch_array_in(i,j),
        enable => en(i),
        q      => latch_array_out(i,j)
      );
    end generate g1;
  end generate g0;

  g2: for i in 0 to num_output_ports-1 generate
    g8: for j in address_read'RANGE(1) generate
      addr_RD(i)(j) <= address_read(i, j);
    end generate g8;
    op_mux: mux_generic
    generic map (
      data_width => data_width,
      funnel_factor => depth
    )
    port map (
      a   => latch_array_out,
      sel => addr_RD(i),
      y   => mux_out(i)
    );
  end generate g2;

  gi_mux: for i in 0 to num_output_ports-1 generate
    gj_data: for j in 0 to data_width-1 generate
      data_out(i,j) <= mux_out(i)(j);
    end generate gj_data;
  end generate gi_mux;

end modular;

To download the VHDL source code for this model, click here.

Back to VHDL models.

Great training!! Excellent Instructor, Excellent facility ...Met all my expectations.
Henry Hastings
Lockheed Martin

View more references