Free Online Training Events
Free Technical Resources
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.