aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/vivado_ipi/axi_regfile/axi_regfile.vhd
blob: 3ec84543f83ac9f6ac6e4debfc58a9cbfbfb700e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity axi_regfile is
generic (
	NUM_REGS : integer := 16
);
port (
	regs : out std_logic_vector(NUM_REGS*32-1 downto 0);

	S_AXI_ACLK	: in std_logic;
	S_AXI_ARESETN	: in std_logic;
	S_AXI_AWADDR	: in std_logic_vector(11 downto 0);
	S_AXI_AWVALID	: in std_logic;
	S_AXI_AWREADY	: out std_logic;
	S_AXI_WDATA	: in std_logic_vector(31 downto 0);
	S_AXI_WSTRB	: in std_logic_vector(3 downto 0);
	S_AXI_WVALID	: in std_logic;
	S_AXI_WREADY	: out std_logic;
	S_AXI_BRESP	: out std_logic_vector(1 downto 0);
	S_AXI_BVALID	: out std_logic;
	S_AXI_BREADY	: in std_logic;
	S_AXI_ARADDR	: in std_logic_vector(11 downto 0);
	S_AXI_ARVALID	: in std_logic;
	S_AXI_ARREADY	: out std_logic;
	S_AXI_RDATA	: out std_logic_vector(31 downto 0);
	S_AXI_RRESP	: out std_logic_vector(1 downto 0);
	S_AXI_RVALID	: out std_logic;
	S_AXI_RREADY	: in std_logic
);
end axi_regfile;

architecture arch of axi_regfile is
	type regfile_t is array (integer range <>) of std_logic_vector(31 downto 0);
	signal read_token : std_logic;
	signal write_addr : std_logic_vector(S_AXI_AWADDR'left downto S_AXI_AWADDR'right);
	signal write_strb : std_logic_vector(3 downto 0);
	signal write_addr_token : std_logic;
	signal write_data : std_logic_vector(31 downto 0);
	signal write_data_token : std_logic;
	signal soft_reset : std_logic;
	signal regs_r     : regfile_t(NUM_REGS-1 downto 0);
begin

	S_AXI_ARREADY <= not read_token;
	S_AXI_RVALID <= read_token;
	S_AXI_RRESP <= "00";

	S_AXI_AWREADY <= not write_addr_token;
	S_AXI_WREADY <= not write_data_token;
	S_AXI_BVALID <= write_addr_token and write_data_token;
	S_AXI_BRESP <= "00";

	--Port assignment from registers
	reg_distribution : process (regs_r)
	begin
		for i in 0 to NUM_REGS-1 loop
			regs(32*(i+1)-1 downto 32*i) <= regs_r(i);
		end loop;
	end process reg_distribution;

	--Register reads
	read_proc : process (S_AXI_ACLK)
		variable read_addr : integer; 
	begin
	if rising_edge(S_AXI_ACLK) then
		read_addr := to_integer(unsigned(S_AXI_ARADDR(S_AXI_ARADDR'left downto S_AXI_ARADDR'right+2)));

		if (S_AXI_ARESETN = '0') then
			read_token <= '0';
		elsif (S_AXI_ARVALID = '1') and (read_token = '0') then
			read_token <= '1';
		elsif (S_AXI_RREADY = '1') and (read_token = '1') then
			read_token <= '0';
		end if;

		if (S_AXI_ARVALID = '1') and (read_token = '0') then
			S_AXI_RDATA <= (others => '0');
			for i in 0 to NUM_REGS-1 loop
				if (read_addr = i) then
					S_AXI_RDATA <= regs_r(i);
				end if;
			end loop;
		end if;
	end if;
	end process read_proc;

	write_proc : process (S_AXI_ACLK)
	begin
	if rising_edge(S_AXI_ACLK) then
		if (S_AXI_ARESETN = '0') then
			write_addr_token <= '0';
			write_data_token <= '0';
			write_strb <= (others => '0');
		else
			if (S_AXI_AWVALID = '1') and (write_addr_token = '0') then
				write_addr_token <= '1';
			elsif (S_AXI_BREADY = '1') and (write_addr_token = '1') and (write_data_token = '1') then
				write_addr_token <= '0';
			end if;

			if (S_AXI_WVALID = '1') and (write_data_token = '0') then
				write_data_token <= '1';
			elsif (S_AXI_BREADY = '1') and (write_addr_token = '1') and (write_data_token = '1') then
				write_data_token <= '0';
			end if;
		end if;

		if (S_AXI_AWVALID = '1') and (write_addr_token = '0') then
			write_addr <= S_AXI_AWADDR;
		end if;

		if (S_AXI_WVALID = '1') and (write_data_token = '0') then
			write_data <= S_AXI_WDATA;
			write_strb <= S_AXI_WSTRB;
		end if;
	end if;
	end process write_proc;

	-- Update registers on write
	write_reg : process (S_AXI_ACLK)
		variable write_addr_int : integer;
	begin
	if rising_edge(S_AXI_ACLK) then
		write_addr_int := to_integer(unsigned(write_addr(write_addr'left downto 2)));

		if (S_AXI_ARESETN = '0') or (soft_reset = '1') then
			--Initial states for each signal
			soft_reset <= '0';
		elsif (write_addr_token = '1') and (write_data_token = '1') then
			for i in 0 to NUM_REGS-1 loop
				if (write_addr_int = i) then
					for j in write_strb'left downto write_strb'right loop
						regs_r(i)(j*8+7 downto j*8) <= write_data(j*8+7 downto j*8);
					end loop;
				end if;
			end loop;
		end if;
	end if;
	end process write_reg;

end arch;