model library icon

 

Model of the Month

   
  We can update you automatically when this page changes.
To receive regular notification of updates to our Model of the Month section, click here.
   
 

6-port Register File

This month, 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 modeling such a device seems to grow at an alarming rate.

This register file has 3 wite and 3 read ports. I was planning to add a bidirectional port capability too, but figured this could wait until I developed a fully parameterizable register file model (just don’t hold your breath!). So this model has a depth of 32 registers, each register being 8 bits wide.

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 this month, 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 modeling 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 Acknowledgements page for more details).

The VFP Library is required for simulating this month's Model of the Month.
To download the VFP files, click here.

-- register_file_32_8_6port
--
-- +-----------------------------+
-- | Copyright 1998 DOULOS       |
-- | Library: register_file      |
-- | designer : Tim Pagden       |
-- | opened: 11 Jul 1998         |
-- +-----------------------------+

library IEEE;
library vfp;
  use IEEE.std_logic_1164.all;
  use vfp.hardware_specifications.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_ulogic_vector(((num_write_ports-1) +
    num_bidirectional_ports) downto 0);
  read     : in std_ulogic_vector((( num_read_ports-1) +
    num_bidirectional_ports) downto 0);
  address_write : in std_ulogic_2D_array(0 to 2, 4 downto 0);
  address_read  : in std_ulogic_2D_array(0 to 2, 4 downto 0);
  data_in  : in  std_ulogic_2D_array(0 to 2, 7 downto 0);
  data_out : out std_ulogic_2D_array(0 to 2, 7 downto 0)
);
end reg_file_32_8_6port;
  
-- Architectures:
-- 11.07.98 behaviour

library IEEE;
  use IEEE.std_logic_1164.all;

library vfp;
library FF;
library multiplexer;

architecture modular of reg_file_32_8_6port is
  use vfp.integer_class.all;
  use FF.d_latch_cmpt.all;
  use multiplexer.demux_gen_cmpt.all;
  use multiplexer.mux_gen_cmpt.all;

  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_ulogic_vector(depth-1 downto 0);
  type address_write_bus is array (0 to num_input_ports-1) of 
    std_ulogic_vector(log_2(depth)-1 downto 0);
  type address_read_bus  is array (0 to num_output_ports-1) of 
    std_ulogic_vector(log_2(depth)-1 downto 0);
  type data_write_bus is array (0 to num_input_ports-1) of 
    std_ulogic_vector(data_width-1 downto 0);
  type data_read_bus is array (0 to num_output_ports-1) of 
    std_ulogic_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_ulogic_vector(0 to num_input_ports-1);
  signal OE_RD : std_ulogic_vector(0 to num_output_ports-1);

  signal data_WR : data_write_bus;
  signal latch_array_in  : std_ulogic_2D_array(0 to depth-1, 
    data_width-1 downto 0);
  signal latch_array_out : std_ulogic_2D_array(0 to depth-1, 
    data_width-1 downto 0);
  signal mux_out : data_read_bus; 
  signal en : std_ulogic_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_ulogic_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(0) 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 month's
Model of the Month, click here.

VHDL source code for other Models of the Month
can be downloaded from here.

 

accumulator diagramFPGA / ASIC Design and Project Services
wand iconDoulos Training Courses

river sceneDoulos Home Page

Copyright 1995-1998 Doulos
This page was last updated 4th July 1998.

mail iconWe welcome your e-mail comments. Please contact us at: webmaster@doulos.co.uk