-
Notifications
You must be signed in to change notification settings - Fork 9
/
sha256_ctrl_axi.vhd
295 lines (266 loc) · 10.4 KB
/
sha256_ctrl_axi.vhd
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
use work.sha256_pkg.all;
use work.axi_pkg.all;
entity sha256_ctrl_axi is
port(
aclk: in std_ulogic;
aresetn: in std_ulogic;
s0_axi_araddr: in std_ulogic_vector(11 downto 0);
s0_axi_arprot: in std_ulogic_vector(2 downto 0);
s0_axi_arvalid: in std_ulogic;
s0_axi_rready: in std_ulogic;
s0_axi_awaddr: in std_ulogic_vector(11 downto 0);
s0_axi_awprot: in std_ulogic_vector(2 downto 0);
s0_axi_awvalid: in std_ulogic;
s0_axi_wdata: in std_ulogic_vector(31 downto 0);
s0_axi_wstrb: in std_ulogic_vector(3 downto 0);
s0_axi_wvalid: in std_ulogic;
s0_axi_bready: in std_ulogic;
s0_axi_arready: out std_ulogic;
s0_axi_rdata: out std_ulogic_vector(31 downto 0);
s0_axi_rresp: out std_ulogic_vector(1 downto 0);
s0_axi_rvalid: out std_ulogic;
s0_axi_awready: out std_ulogic;
s0_axi_wready: out std_ulogic;
s0_axi_bresp: out std_ulogic_vector(1 downto 0);
s0_axi_bvalid: out std_ulogic
);
end entity sha256_ctrl_axi;
architecture fsm of sha256_ctrl_axi is
type read_state_type is (read_idle, reading, read_waiting_ack, read_error);
signal read_current_state, read_next_state: read_state_type;
type write_state_type is (write_idle, write_ro_error, write_error, writing, write_waiting_ack);
signal write_current_state, write_next_state: write_state_type;
type reg_type is array (0 to 9) of std_ulogic_vector(31 downto 0); -- array of 10 32-bit registers
signal reg : reg_type;
signal data_out, next_data_out: std_ulogic_vector(31 downto 0);
signal read_resp, write_resp, next_read_resp, next_write_resp: std_ulogic_vector(1 downto 0);
signal msg_valid, msg_last, hash_ack, msg_ready, hash_valid, data_reg_addr : std_ulogic;
signal data, next_data, msg_word, data_reg, status_reg : word;
signal hash : sha_hash;
begin
sha256_hw : entity work.sha256(struct) port map (aclk, aresetn, msg_valid, msg_last, hash_ack, msg_word, msg_ready, hash_valid, hash);
next_data_out <= reg(to_integer(unsigned(s0_axi_araddr(11 downto 2)))) when (read_next_state = reading) else
(others => '0') when (read_next_state=read_error) else
data_out;
-- choose read response code
next_read_resp <= axi_resp_okay when (read_next_state = reading) else
axi_resp_decerr when (read_next_state = read_error) else
read_resp;
-- chose write response code
next_write_resp <= axi_resp_okay when (write_next_state = writing) else
axi_resp_decerr when (write_next_state = write_error) else
axi_resp_slverr when (write_next_state = write_ro_error) else
write_resp;
next_data(7 downto 0) <= s0_axi_wdata(7 downto 0) when s0_axi_wstrb(0)='1' else data(7 downto 0);
next_data(15 downto 8) <= s0_axi_wdata(15 downto 8) when s0_axi_wstrb(1)='1' else data(15 downto 8);
next_data(23 downto 16) <= s0_axi_wdata(23 downto 16) when s0_axi_wstrb(2)='1' else data(23 downto 16);
next_data(31 downto 24) <= s0_axi_wdata(31 downto 24) when s0_axi_wstrb(3)='1' else data(31 downto 24);
data <= status_reg when (s0_axi_awaddr(11 downto 2) = "0000000001") else
data_reg when (s0_axi_awaddr(11 downto 2) = "0000000000") else
(others => '0');
reg(0) <= data_reg;
reg(1) <= status_reg;
reg(2) <= hash(255 downto 224);
reg(3) <= hash(223 downto 192);
reg(4) <= hash(191 downto 160);
reg(5) <= hash(159 downto 128);
reg(6) <= hash(127 downto 96);
reg(7) <= hash(95 downto 64);
reg(8) <= hash(63 downto 32);
reg(9) <= hash(31 downto 0);
data_reg_addr <= '1' when (s0_axi_awaddr >= "000000000000" and s0_axi_awaddr <= "000000000011") else '0';
msg_word <= reg(0);
msg_last <= reg(1)(3);
hash_ack <= reg(1)(2);
msg_valid_proc : process(aclk)
begin
if(aclk='1' and aclk'event) then
if(aresetn = '0') then
msg_valid <= '0';
else
if(write_current_state = writing and data_reg_addr = '1') then
msg_valid <= '1';
else
msg_valid <= '0';
end if;
end if;
end if;
end process msg_valid_proc;
status_proc : process(aclk)
begin
if(aclk='1' and aclk'event) then
if(aresetn='0') then
status_reg <= (others => '0');
else
status_reg(0) <= msg_ready;
status_reg(1) <= hash_valid;
if(s0_axi_awaddr(11 downto 2) = "0000000001" and s0_axi_wvalid = '1' and s0_axi_awvalid = '1') then
status_reg(3 downto 2) <= next_data(3 downto 2);
end if;
end if;
end if;
end process status_proc;
data_proc : process(aclk)
begin
if(aclk='1' and aclk'event) then
if(aresetn='0') then
data_reg <= (others => '0');
elsif(s0_axi_awaddr(11 downto 2) = "0000000000" and s0_axi_wvalid = '1' and s0_axi_awvalid= '1') then
data_reg <= next_data;
end if;
end if;
end process data_proc;
read_sync_proc: process(aclk)
begin
if(aclk='1' and aclk'event) then
if(aresetn = '0') then --synchronous active low
read_current_state <= read_idle;
data_out <= (others => '0');
read_resp <= (others => '0');
else
read_current_state <= read_next_state;
data_out <= next_data_out;
read_resp <= next_read_resp;
end if;
end if;
end process read_sync_proc;
-- process to assign output values according to current state
read_output_proc: process(read_current_state, data_out, read_resp)
begin
s0_axi_arready <= '0';
s0_axi_rvalid <= '1';
s0_axi_rdata <= data_out;
s0_axi_rresp <= read_resp;
case(read_current_state) is
when read_idle =>
s0_axi_rvalid <= '0';
when reading =>
s0_axi_arready <= '1';
when read_waiting_ack =>
when read_error =>
s0_axi_arready <= '1';
when others =>
s0_axi_arready <= '0';
s0_axi_rvalid <= '1';
end case;
end process read_output_proc;
--process to define next state according to inputs and current state
read_next_state_proc: process(reg, read_current_state, s0_axi_arvalid, s0_axi_rready, s0_axi_araddr, s0_axi_arprot)
begin
case(read_current_state) is
when read_idle =>
if(s0_axi_arvalid = '1' and ("000000000000" <= s0_axi_araddr and s0_axi_araddr < "000001010000")) then -- valid address
read_next_state <= reading;
elsif(s0_axi_arvalid = '1' and (s0_axi_araddr < "000000000000" or s0_axi_araddr >= "000001010000")) then
read_next_state <= read_error;
else
read_next_state <= read_idle;
end if;
when reading =>
if(s0_axi_rready = '1') then -- if rready is already = 1 go back to idle, otherwise move to read_waiting_ack and wait for rready
read_next_state <= read_idle;
else
read_next_state <= read_waiting_ack;
end if;
when read_waiting_ack => -- wait in here until rready is asserted then go back to idle
if(s0_axi_rready = '1') then
read_next_state <= read_idle;
else
read_next_state <= read_waiting_ack;
end if;
when read_error => -- if rready is already = 1 go back to idle, otherwise move to read_waiting_ack and wait for rready
if(s0_axi_rready = '1') then
read_next_state <= read_idle;
else
read_next_state <= read_waiting_ack;
end if;
when others =>
read_next_state <= read_idle;
end case;
end process read_next_state_proc;
-- process to handle reset and next state assignment is write fsm
write_sync_proc: process(aclk)
begin
if(aclk='1' and aclk'event) then
if(aresetn='0') then
write_current_state <= write_idle;
write_resp <= (others => '0');
else
write_current_state <= write_next_state;
write_resp <= next_write_resp;
end if;
end if;
end process write_sync_proc;
-- process to assign output values according to current state
write_output_proc: process(write_current_state, write_resp)
begin
s0_axi_awready <= '0';
s0_axi_wready <= '0';
s0_axi_bvalid <= '1';
s0_axi_bresp <= write_resp;
case(write_current_state) is
when write_idle =>
s0_axi_bvalid <= '0';
when write_error =>
s0_axi_wready <= '1';
s0_axi_awready <= '1';
when write_ro_error =>
s0_axi_wready <= '1';
s0_axi_awready <= '1';
when writing =>
s0_axi_awready <= '1';
s0_axi_wready <= '1';
when write_waiting_ack =>
when others =>
s0_axi_awready <= '0';
s0_axi_wready <= '0';
s0_axi_bvalid <= '1';
end case;
end process write_output_proc;
--process to define next state according to inputs and current state
write_next_state_proc: process(write_current_state, s0_axi_wstrb, s0_axi_awvalid, s0_axi_bready, s0_axi_wvalid, s0_axi_awaddr, s0_axi_awprot, s0_axi_wdata)
begin
case(write_current_state) is
when write_idle =>
if(s0_axi_awvalid = '1' and s0_axi_wvalid = '1' and (s0_axi_awaddr < "000000000000" or s0_axi_awaddr >= "000001010000")) then
write_next_state <= write_error;
elsif(s0_axi_awvalid = '1' and s0_axi_wvalid = '1' and ("000000001000"<=s0_axi_awaddr and s0_axi_awaddr<"000001010000")) then -- read-only register
write_next_state <= write_ro_error;
elsif (s0_axi_awvalid = '1' and s0_axi_wvalid = '1') then -- valid address
write_next_state <= writing;
else
write_next_state <= write_idle;
end if;
when write_error => -- if bready is already = 1 go back to idle otherwise move to write_waiting_ack and wait for bready
if(s0_axi_bready = '0') then
write_next_state <= write_waiting_ack;
else
write_next_state <= write_idle;
end if;
when write_ro_error => -- if bready is already = 1 go back to idle otherwise move to write_waiting_ack and wait for bready
if(s0_axi_bready = '0') then
write_next_state <= write_waiting_ack;
else
write_next_state <= write_idle;
end if;
when writing => -- if bready is already = 1 go back to idle otherwise move to write_waiting_ack and wait for bready
if(s0_axi_bready = '0') then
write_next_state <= write_waiting_ack;
else
write_next_state <= write_idle;
end if;
when write_waiting_ack => -- wait here until bready is asserted then go back to idle
if(s0_axi_bready = '1') then
write_next_state <= write_idle;
else
write_next_state <= write_waiting_ack;
end if;
when others =>
write_next_state <= write_idle;
end case;
end process write_next_state_proc;
end architecture fsm;