--
-- Project: pAVR (pipelined AVR). It's a deep pipeline implementation of
-- Atmel's AVR microcontroller architecture. pAVR's 6 pipeline stages make
-- it run about 3 times faster than the Atmel's core - in terms of clock
-- frequency and MIPS.
-- Version: 0.50
-- Date: 29 Dec 2004
-- Author: Doru Cuturela, doruu@yahoo.com, geocities.com/doruu
-- License: GNU GPL
--
--
-- This defines pAVR's Register File.
-- The Register File has 3 ports: 2 for reading and 1 for writing. All these
-- access all 32 locations in the register file. Apart from these 3 ports,
-- there are 3 special ports that access 16 bit pointer registers X, Y, Z, for
-- both reading and writing. The pointer registers are mapped on the register
-- file, at addresses 26-27 (pointer register X), 28-29 (Y) and 30-31 (Z).
-- Physically, the register file consists of a memory-like entity with 26 8 bit
-- locations, and 3 16 bit registers. Together, these form the 32 locations
-- of the register file. The physical separation of locations <26 and >=26 is
-- is invisible from outside.
-- Writing on the write port and on every pointer register port can be done
-- in parallel. However, if writing at the same time a location via the write
-- port and one of the pointer registers, writing via pointer register port
-- has priority.
--
--
library work;
use work.std_util.all;
use work.pavr_util.all;
use work.pavr_constants.all;
library IEEE;
use IEEE.std_logic_1164.all;
entity pavr_rf is
port(
pavr_rf_clk: in std_logic;
pavr_rf_res: in std_logic;
pavr_rf_syncres: in std_logic;
-- Read port 1
pavr_rf_rd1_addr: in std_logic_vector(4 downto 0);
pavr_rf_rd1_rd: in std_logic;
pavr_rf_rd1_do: out std_logic_vector(7 downto 0);
-- Read port 2
pavr_rf_rd2_addr: in std_logic_vector(4 downto 0);
pavr_rf_rd2_rd: in std_logic;
pavr_rf_rd2_do: out std_logic_vector(7 downto 0);
-- Write port
pavr_rf_wr_addr: in std_logic_vector(4 downto 0);
pavr_rf_wr_wr: in std_logic;
pavr_rf_wr_di: in std_logic_vector(7 downto 0);
-- Pointer registers
pavr_rf_x: out std_logic_vector(15 downto 0);
pavr_rf_x_wr: in std_logic;
pavr_rf_x_di: in std_logic_vector(15 downto 0);
pavr_rf_y: out std_logic_vector(15 downto 0);
pavr_rf_y_wr: in std_logic;
pavr_rf_y_di: in std_logic_vector(15 downto 0);
pavr_rf_z: out std_logic_vector(15 downto 0);
pavr_rf_z_wr: in std_logic;
pavr_rf_z_di: in std_logic_vector(15 downto 0)
);
end;
architecture pavr_rf_arch of pavr_rf is
signal pavr_rf_x_int: std_logic_vector(15 downto 0);
signal pavr_rf_y_int: std_logic_vector(15 downto 0);
signal pavr_rf_z_int: std_logic_vector(15 downto 0);
type t_pavr_rf_data_array is array (0 to 25) of std_logic_vector(7 downto 0);
signal pavr_rf_data_array: t_pavr_rf_data_array;
begin
-- Read port 1
read_port_1:
process
variable is_x, is_y, is_z: std_logic;
variable tv_rd1: std_logic_vector(2 downto 0);
begin
-- Wait for clock.
wait until pavr_rf_clk'event and pavr_rf_clk = '1';
-- Default tmp signals.
tv_rd1 := int_to_std_logic_vector(0, 3);
-- Default output to zero.
pavr_rf_rd1_do <= int_to_std_logic_vector(0, pavr_rf_rd1_do'length);
if (pavr_rf_rd1_addr(4 downto 1) = "1101") then
is_x := '1';
else
is_x := '0';
end if;
if (pavr_rf_rd1_addr(4 downto 1) = "1110") then
is_y := '1';
else
is_y := '0';
end if;
if (pavr_rf_rd1_addr(4 downto 1) = "1111") then
is_z := '1';
else
is_z := '0';
end if;
if (pavr_rf_rd1_rd = '1') then
tv_rd1 := is_x & is_y & is_z;
case tv_rd1 is
when "000" =>
pavr_rf_rd1_do <= pavr_rf_data_array(std_logic_vector_to_nat(pavr_rf_rd1_addr));
when "100" =>
if (pavr_rf_rd1_addr(0) = '0') then
pavr_rf_rd1_do <= pavr_rf_x_int(7 downto 0);
else
pavr_rf_rd1_do <= pavr_rf_x_int(15 downto 8);
end if;
when "010" =>
if (pavr_rf_rd1_addr(0) = '0') then
pavr_rf_rd1_do <= pavr_rf_y_int(7 downto 0);
else
pavr_rf_rd1_do <= pavr_rf_y_int(15 downto 8);
end if;
when others =>
if (pavr_rf_rd1_addr(0) = '0') then
pavr_rf_rd1_do <= pavr_rf_z_int(7 downto 0);
else
pavr_rf_rd1_do <= pavr_rf_z_int(15 downto 8);
end if;
end case;
end if;
end process read_port_1;
-- Read port 2
read_port_2:
process
variable is_x, is_y, is_z: std_logic;
variable tv_rd2: std_logic_vector(2 downto 0);
begin
-- Wait for clock.
wait until pavr_rf_clk'event and pavr_rf_clk='1';
-- Default tmp signals.
tv_rd2 := int_to_std_logic_vector(0, 3);
-- Default output to zero.
pavr_rf_rd2_do <= int_to_std_logic_vector(0, pavr_rf_rd2_do'length);
if (pavr_rf_rd2_addr(4 downto 1) = "1101") then
is_x := '1';
else
is_x := '0';
end if;
if (pavr_rf_rd2_addr(4 downto 1) = "1110") then
is_y := '1';
else
is_y := '0';
end if;
if (pavr_rf_rd2_addr(4 downto 1) = "1111") then
is_z := '1';
else
is_z := '0';
end if;
if (pavr_rf_rd2_rd = '1') then
tv_rd2 := is_x & is_y & is_z;
case tv_rd2 is
when "000" =>
pavr_rf_rd2_do <= pavr_rf_data_array(std_logic_vector_to_nat(pavr_rf_rd2_addr));
when "100" =>
if (pavr_rf_rd2_addr(0) = '0') then
pavr_rf_rd2_do <= pavr_rf_x_int(7 downto 0);
else
pavr_rf_rd2_do <= pavr_rf_x_int(15 downto 8);
end if;
when "010" =>
if (pavr_rf_rd2_addr(0) = '0') then
pavr_rf_rd2_do <= pavr_rf_y_int(7 downto 0);
else
pavr_rf_rd2_do <= pavr_rf_y_int(15 downto 8);
end if;
when others =>
if (pavr_rf_rd2_addr(0) = '0') then
pavr_rf_rd2_do <= pavr_rf_z_int(7 downto 0);
else
pavr_rf_rd2_do <= pavr_rf_z_int(15 downto 8);
end if;
end case;
end if;
end process read_port_2;
-- Write port and pointer registers
write_port:
process(pavr_rf_clk, pavr_rf_res, pavr_rf_syncres,
pavr_rf_wr_wr, pavr_rf_wr_di, pavr_rf_wr_addr)
variable is_x, is_y, is_z: std_logic;
variable tv_wr: std_logic_vector(2 downto 0);
begin
-- Detect access to pointer registers.
if (pavr_rf_wr_addr(4 downto 1) = "1101") then
is_x := '1';
else
is_x := '0';
end if;
if (pavr_rf_wr_addr(4 downto 1) = "1110") then
is_y := '1';
else
is_y := '0';
end if;
if (pavr_rf_wr_addr(4 downto 1) = "1111") then
is_z := '1';
else
is_z := '0';
end if;
tv_wr := is_x & is_y & is_z;
-- Manage write requests.
if pavr_rf_res='1' then
-- Asynchronous reset
pavr_rf_x_int <= int_to_std_logic_vector(0, 16);
pavr_rf_y_int <= int_to_std_logic_vector(0, 16);
pavr_rf_z_int <= int_to_std_logic_vector(0, 16);
reset_registers:
for i in 0 to 25 loop
pavr_rf_data_array(i) <= int_to_std_logic_vector(0, 8);
end loop reset_registers;
elsif pavr_rf_clk'event and pavr_rf_clk='1' then
-- Write port
if (pavr_rf_wr_wr = '1') then
case tv_wr is
when "000" =>
pavr_rf_data_array(std_logic_vector_to_nat(pavr_rf_wr_addr)) <= pavr_rf_wr_di;
when "100" =>
if (pavr_rf_wr_addr(0) = '0') then
pavr_rf_x_int(7 downto 0) <= pavr_rf_wr_di;
else
pavr_rf_x_int(15 downto 8) <= pavr_rf_wr_di;
end if;
when "010" =>
if (pavr_rf_wr_addr(0) = '0') then
pavr_rf_y_int(7 downto 0) <= pavr_rf_wr_di;
else
pavr_rf_y_int(15 downto 8) <= pavr_rf_wr_di;
end if;
when others =>
if (pavr_rf_wr_addr(0) = '0') then
pavr_rf_z_int(7 downto 0) <= pavr_rf_wr_di;
else
pavr_rf_z_int(15 downto 8) <= pavr_rf_wr_di;
end if;
end case;
end if;
-- Write pointer registers. Possibly overwrite the above write.
if (pavr_rf_x_wr = '1') then
pavr_rf_x_int <= pavr_rf_x_di;
end if;
if (pavr_rf_y_wr = '1') then
pavr_rf_y_int <= pavr_rf_y_di;
end if;
if (pavr_rf_z_wr = '1') then
pavr_rf_z_int <= pavr_rf_z_di;
end if;
if pavr_rf_syncres='1' then
-- Synchronous reset
pavr_rf_x_int <= int_to_std_logic_vector(0, 16);
pavr_rf_y_int <= int_to_std_logic_vector(0, 16);
pavr_rf_z_int <= int_to_std_logic_vector(0, 16);
syncreset_registers:
for i in 0 to 25 loop
pavr_rf_data_array(i) <= int_to_std_logic_vector(0, 8);
end loop syncreset_registers;
end if;
end if;
end process write_port;
-- Zero-level assignments
pavr_rf_x <= pavr_rf_x_int;
pavr_rf_y <= pavr_rf_y_int;
pavr_rf_z <= pavr_rf_z_int;
end;
--