Line data Source code
1 : // SPDX-License-Identifier: Apache-2.0
2 : // Copyright 2020 Western Digital Corporation or its affiliates.
3 : //
4 : // Licensed under the Apache License, Version 2.0 (the "License");
5 : // you may not use this file except in compliance with the License.
6 : // You may obtain a copy of the License at
7 : //
8 : // http://www.apache.org/licenses/LICENSE-2.0
9 : //
10 : // Unless required by applicable law or agreed to in writing, software
11 : // distributed under the License is distributed on an "AS IS" BASIS,
12 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 : // See the License for the specific language governing permissions and
14 : // limitations under the License.
15 :
16 : //********************************************************************************
17 : // $Id$
18 : //
19 : // Owner:
20 : // Function: AXI4 -> AHB Bridge
21 : // Comments:
22 : //
23 : //********************************************************************************
24 : module axi4_to_ahb
25 : import el2_pkg::*;
26 : #(
27 : `include "el2_param.vh"
28 : ,parameter TAG = 1) (
29 :
30 28524335 : input clk,
31 28524335 : input free_clk,
32 23 : input rst_l,
33 : // Excluding scan_mode from coverage as its usage is determined by the integrator of the VeeR core.
34 : /*verilator coverage_off*/
35 : input scan_mode,
36 : /*verilator coverage_on*/
37 23 : input bus_clk_en,
38 0 : input clk_override,
39 0 : input dec_tlu_force_halt,
40 :
41 : // AXI signals
42 : // AXI Write Channels
43 106 : input logic axi_awvalid,
44 343 : output logic axi_awready,
45 50 : input logic [TAG-1:0] axi_awid,
46 2 : input logic [31:0] axi_awaddr,
47 0 : input logic [2:0] axi_awsize,
48 0 : input logic [2:0] axi_awprot,
49 :
50 106 : input logic axi_wvalid,
51 241 : output logic axi_wready,
52 4 : input logic [63:0] axi_wdata,
53 310 : input logic [7:0] axi_wstrb,
54 122 : input logic axi_wlast,
55 :
56 224 : output logic axi_bvalid,
57 122 : input logic axi_bready,
58 0 : output logic [1:0] axi_bresp,
59 27 : output logic [TAG-1:0] axi_bid,
60 :
61 : // AXI Read Channels
62 110 : input logic axi_arvalid,
63 241 : output logic axi_arready,
64 0 : input logic [TAG-1:0] axi_arid,
65 2 : input logic [31:0] axi_araddr,
66 0 : input logic [2:0] axi_arsize,
67 0 : input logic [2:0] axi_arprot,
68 :
69 122 : output logic axi_rvalid,
70 110 : input logic axi_rready,
71 27 : output logic [TAG-1:0] axi_rid,
72 6 : output logic [63:0] axi_rdata,
73 0 : output logic [1:0] axi_rresp,
74 23 : output logic axi_rlast,
75 :
76 : // AHB-Lite signals
77 2 : output logic [31:0] ahb_haddr, // ahb bus address
78 : /* exclude signals that are tied to constant value in this file */
79 : /*verilator coverage_off*/
80 : output logic [2:0] ahb_hburst, // tied to 0
81 : output logic ahb_hmastlock, // tied to 0
82 : /*verilator coverage_on*/
83 0 : output logic [3:0] ahb_hprot, // [3:1] are tied to 3'b001
84 0 : output logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3)
85 1198 : output logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now)
86 135 : output logic ahb_hwrite, // ahb bus write
87 7 : output logic [63:0] ahb_hwdata, // ahb bus write data
88 :
89 6 : input logic [63:0] ahb_hrdata, // ahb bus read data
90 194 : input logic ahb_hready, // slave ready to accept transaction
91 0 : input logic ahb_hresp // slave response (high indicates erro)
92 :
93 : );
94 :
95 : localparam ID = 1;
96 : localparam PRTY = 1;
97 : typedef enum logic [3:0] {
98 : IDLE = 4'b0000,
99 : CMD_RD = 4'b0001,
100 : CMD_WR = 4'b1001,
101 : DATA_RD = 4'b0010,
102 : DATA_WR = 4'b1010,
103 : DONE_RD = 4'b0011,
104 : DONE_WR = 4'b1011,
105 : STREAM_RD = 4'b0101,
106 : STREAM_ERR_RD = 4'b0110
107 : } state_t;
108 :
109 212 : state_t buf_state, buf_nxtstate;
110 :
111 234 : logic slave_valid;
112 27 : logic [TAG-1:0] slave_tag;
113 6 : logic [63:0] slave_rdata;
114 135 : logic [3:0] slave_opc;
115 :
116 106 : logic wrbuf_en, wrbuf_data_en;
117 224 : logic wrbuf_cmd_sent, wrbuf_rst;
118 224 : logic wrbuf_vld;
119 224 : logic wrbuf_data_vld;
120 23 : logic [TAG-1:0] wrbuf_tag;
121 0 : logic [2:0] wrbuf_size;
122 2 : logic [31:0] wrbuf_addr;
123 30 : logic [63:0] wrbuf_data;
124 59 : logic [7:0] wrbuf_byteen;
125 :
126 216 : logic master_valid;
127 241 : logic master_ready;
128 50 : logic [TAG-1:0] master_tag;
129 2 : logic [31:0] master_addr;
130 30 : logic [63:0] master_wdata;
131 0 : logic [2:0] master_size;
132 0 : logic [2:0] master_opc;
133 59 : logic [7:0] master_byteen;
134 :
135 : // Buffer signals (one entry buffer)
136 2 : logic [31:0] buf_addr;
137 6 : logic [1:0] buf_size;
138 135 : logic buf_write;
139 59 : logic [7:0] buf_byteen;
140 5 : logic buf_aligned;
141 7 : logic [63:0] buf_data;
142 27 : logic [TAG-1:0] buf_tag;
143 :
144 : //Miscellaneous signals
145 0 : logic buf_rst;
146 50 : logic [TAG-1:0] buf_tag_in;
147 2 : logic [31:0] buf_addr_in;
148 59 : logic [7:0] buf_byteen_in;
149 7 : logic [63:0] buf_data_in;
150 224 : logic buf_write_in;
151 23 : logic buf_aligned_in;
152 0 : logic [2:0] buf_size_in;
153 :
154 522 : logic buf_state_en;
155 216 : logic buf_wr_en;
156 216 : logic buf_data_wr_en;
157 216 : logic slvbuf_error_en;
158 224 : logic wr_cmd_vld;
159 :
160 1198 : logic cmd_done_rst, cmd_done, cmd_doneQ;
161 224 : logic trxn_done;
162 0 : logic [2:0] buf_cmd_byte_ptr, buf_cmd_byte_ptrQ, buf_cmd_nxtbyte_ptr;
163 318 : logic buf_cmd_byte_ptr_en;
164 0 : logic found;
165 :
166 234 : logic slave_valid_pre;
167 194 : logic ahb_hready_q;
168 0 : logic ahb_hresp_q;
169 1198 : logic [1:0] ahb_htrans_q;
170 135 : logic ahb_hwrite_q;
171 6 : logic [63:0] ahb_hrdata_q;
172 :
173 :
174 135 : logic slvbuf_write;
175 0 : logic slvbuf_error;
176 27 : logic [TAG-1:0] slvbuf_tag;
177 :
178 0 : logic slvbuf_error_in;
179 234 : logic slvbuf_wr_en;
180 216 : logic bypass_en;
181 110 : logic rd_bypass_idle;
182 :
183 224 : logic last_addr_en;
184 2 : logic [31:0] last_bus_addr;
185 :
186 : // Clocks
187 426 : logic buf_clken;
188 216 : logic ahbm_data_clken;
189 :
190 474 : logic buf_clk;
191 4143 : logic bus_clk;
192 1490 : logic ahbm_data_clk;
193 :
194 0 : logic dec_tlu_force_halt_bus, dec_tlu_force_halt_bus_ns, dec_tlu_force_halt_bus_q;
195 :
196 : // Function to get the length from byte enable
197 306 : function automatic logic [1:0] get_write_size;
198 : input logic [7:0] byteen;
199 :
200 : logic [1:0] size;
201 :
202 306 : size[1:0] = (2'b11 & {2{(byteen[7:0] == 8'hff)}}) |
203 306 : (2'b10 & {2{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h0f))}}) |
204 306 : (2'b01 & {2{((byteen[7:0] == 8'hc0) | (byteen[7:0] == 8'h30) | (byteen[7:0] == 8'h0c) | (byteen[7:0] == 8'h03))}});
205 :
206 306 : return size[1:0];
207 : endfunction // get_write_size
208 :
209 : // Function to get the length from byte enable
210 345 : function automatic logic [2:0] get_write_addr;
211 : input logic [7:0] byteen;
212 :
213 : logic [2:0] addr;
214 :
215 345 : addr[2:0] = (3'h0 & {3{((byteen[7:0] == 8'hff) | (byteen[7:0] == 8'h0f) | (byteen[7:0] == 8'h03))}}) |
216 345 : (3'h2 & {3{(byteen[7:0] == 8'h0c)}}) |
217 345 : (3'h4 & {3{((byteen[7:0] == 8'hf0) | (byteen[7:0] == 8'h03))}}) |
218 345 : (3'h6 & {3{(byteen[7:0] == 8'hc0)}});
219 :
220 345 : return addr[2:0];
221 : endfunction // get_write_addr
222 :
223 : // Function to get the next byte pointer
224 2229 : function automatic logic [2:0] get_nxtbyte_ptr (logic [2:0] current_byte_ptr, logic [7:0] byteen, logic get_next);
225 : logic [2:0] start_ptr;
226 : logic found;
227 2229 : found = '0;
228 2229 : get_nxtbyte_ptr[2:0] = 3'd0;
229 2229 : start_ptr[2:0] = get_next ? (current_byte_ptr[2:0] + 3'b1) : current_byte_ptr[2:0];
230 3867 : for (int j=0; j<8; j++) begin
231 5021 : if (~found) begin
232 5137 : get_nxtbyte_ptr[2:0] = 3'(j);
233 5137 : found |= (byteen[j] & (3'(j) >= start_ptr[2:0])) ;
234 : end
235 : end
236 : endfunction // get_nextbyte_ptr
237 :
238 : // Create bus synchronized version of force halt
239 : assign dec_tlu_force_halt_bus = dec_tlu_force_halt | dec_tlu_force_halt_bus_q;
240 : assign dec_tlu_force_halt_bus_ns = ~bus_clk_en & dec_tlu_force_halt_bus;
241 : rvdff #(.WIDTH(1)) force_halt_busff(.din(dec_tlu_force_halt_bus_ns), .dout(dec_tlu_force_halt_bus_q), .clk(free_clk), .*);
242 :
243 : // Write buffer
244 : assign wrbuf_en = axi_awvalid & axi_awready & master_ready;
245 : assign wrbuf_data_en = axi_wvalid & axi_wready & master_ready;
246 : assign wrbuf_cmd_sent = master_valid & master_ready & (master_opc[2:1] == 2'b01);
247 : assign wrbuf_rst = (wrbuf_cmd_sent & ~wrbuf_en) | dec_tlu_force_halt_bus;
248 :
249 : assign axi_awready = ~(wrbuf_vld & ~wrbuf_cmd_sent) & master_ready;
250 : assign axi_wready = ~(wrbuf_data_vld & ~wrbuf_cmd_sent) & master_ready;
251 : assign axi_arready = ~(wrbuf_vld & wrbuf_data_vld) & master_ready;
252 : assign axi_rlast = 1'b1;
253 :
254 : assign wr_cmd_vld = (wrbuf_vld & wrbuf_data_vld);
255 : assign master_valid = wr_cmd_vld | axi_arvalid;
256 : assign master_tag[TAG-1:0] = wr_cmd_vld ? wrbuf_tag[TAG-1:0] : axi_arid[TAG-1:0];
257 : assign master_opc[2:0] = wr_cmd_vld ? 3'b011 : 3'b0;
258 : assign master_addr[31:0] = wr_cmd_vld ? wrbuf_addr[31:0] : axi_araddr[31:0];
259 : assign master_size[2:0] = wr_cmd_vld ? wrbuf_size[2:0] : axi_arsize[2:0];
260 : assign master_byteen[7:0] = wrbuf_byteen[7:0];
261 : assign master_wdata[63:0] = wrbuf_data[63:0];
262 :
263 : // AXI response channel signals
264 : assign axi_bvalid = slave_valid & slave_opc[3];
265 : assign axi_bresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0);
266 : assign axi_bid[TAG-1:0] = slave_tag[TAG-1:0];
267 :
268 : assign axi_rvalid = slave_valid & (slave_opc[3:2] == 2'b0);
269 : assign axi_rresp[1:0] = slave_opc[0] ? 2'b10 : (slave_opc[1] ? 2'b11 : 2'b0);
270 : assign axi_rid[TAG-1:0] = slave_tag[TAG-1:0];
271 : assign axi_rdata[63:0] = slave_rdata[63:0];
272 :
273 : // FIFO state machine
274 23 : always_comb begin
275 23 : buf_nxtstate = IDLE;
276 23 : buf_state_en = 1'b0;
277 23 : buf_wr_en = 1'b0;
278 23 : buf_data_wr_en = 1'b0;
279 23 : slvbuf_error_in = 1'b0;
280 23 : slvbuf_error_en = 1'b0;
281 23 : buf_write_in = 1'b0;
282 23 : cmd_done = 1'b0;
283 23 : trxn_done = 1'b0;
284 23 : buf_cmd_byte_ptr_en = 1'b0;
285 23 : buf_cmd_byte_ptr[2:0] = '0;
286 23 : slave_valid_pre = 1'b0;
287 23 : master_ready = 1'b0;
288 23 : ahb_htrans[1:0] = 2'b0;
289 23 : slvbuf_wr_en = 1'b0;
290 23 : bypass_en = 1'b0;
291 23 : rd_bypass_idle = 1'b0;
292 :
293 23 : case (buf_state)
294 8871247 : IDLE: begin
295 8871247 : master_ready = 1'b1;
296 8871247 : buf_write_in = (master_opc[2:1] == 2'b01);
297 8871247 : buf_nxtstate = buf_write_in ? CMD_WR : CMD_RD;
298 8871247 : buf_state_en = master_valid & master_ready;
299 8871247 : buf_wr_en = buf_state_en;
300 8871247 : buf_data_wr_en = buf_state_en & (buf_nxtstate == CMD_WR);
301 8871247 : buf_cmd_byte_ptr_en = buf_state_en;
302 8871247 : buf_cmd_byte_ptr[2:0] = buf_write_in ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) : master_addr[2:0];
303 8871247 : bypass_en = buf_state_en;
304 8871247 : rd_bypass_idle = bypass_en & (buf_nxtstate == CMD_RD);
305 8871247 : ahb_htrans[1:0] = {2{bypass_en}} & 2'b10;
306 : end
307 1900 : CMD_RD: begin
308 1900 : buf_nxtstate = (master_valid & (master_opc[2:0] == 3'b000))? STREAM_RD : DATA_RD;
309 1900 : buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q;
310 1900 : cmd_done = buf_state_en & ~master_valid;
311 1900 : slvbuf_wr_en = buf_state_en;
312 1900 : master_ready = buf_state_en & (buf_nxtstate == STREAM_RD);
313 1900 : buf_wr_en = master_ready;
314 1900 : bypass_en = master_ready & master_valid;
315 1900 : buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0];
316 1900 : ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en | bypass_en}};
317 : end
318 0 : STREAM_RD: begin
319 0 : master_ready = (ahb_hready_q & ~ahb_hresp_q) & ~(master_valid & master_opc[2:1] == 2'b01);
320 0 : buf_wr_en = (master_valid & master_ready & (master_opc[2:0] == 3'b000)); // update the fifo if we are streaming the read commands
321 0 : buf_nxtstate = ahb_hresp_q ? STREAM_ERR_RD : (buf_wr_en ? STREAM_RD : DATA_RD); // assuming that the master accpets the slave response right away.
322 0 : buf_state_en = (ahb_hready_q | ahb_hresp_q);
323 0 : buf_data_wr_en = buf_state_en;
324 0 : slvbuf_error_in = ahb_hresp_q;
325 0 : slvbuf_error_en = buf_state_en;
326 0 : slave_valid_pre = buf_state_en & ~ahb_hresp_q; // send a response right away if we are not going through an error response.
327 0 : cmd_done = buf_state_en & ~master_valid; // last one of the stream should not send a htrans
328 0 : bypass_en = master_ready & master_valid & (buf_nxtstate == STREAM_RD) & buf_state_en;
329 0 : buf_cmd_byte_ptr[2:0] = bypass_en ? master_addr[2:0] : buf_addr[2:0];
330 0 : ahb_htrans[1:0] = 2'b10 & {2{~((buf_nxtstate != STREAM_RD) & buf_state_en)}};
331 0 : slvbuf_wr_en = buf_wr_en; // shifting the contents from the buf to slv_buf for streaming cases
332 : end // case: STREAM_RD
333 0 : STREAM_ERR_RD: begin
334 0 : buf_nxtstate = DATA_RD;
335 0 : buf_state_en = ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) & ~ahb_hwrite_q;
336 0 : slave_valid_pre = buf_state_en;
337 0 : slvbuf_wr_en = buf_state_en; // Overwrite slvbuf with buffer
338 0 : buf_cmd_byte_ptr[2:0] = buf_addr[2:0];
339 0 : ahb_htrans[1:0] = 2'b10 & {2{~buf_state_en}};
340 : end
341 280 : DATA_RD: begin
342 280 : buf_nxtstate = DONE_RD;
343 280 : buf_state_en = (ahb_hready_q | ahb_hresp_q);
344 280 : buf_data_wr_en = buf_state_en;
345 280 : slvbuf_error_in= ahb_hresp_q;
346 280 : slvbuf_error_en= buf_state_en;
347 280 : slvbuf_wr_en = buf_state_en;
348 :
349 : end
350 963 : CMD_WR: begin
351 963 : buf_nxtstate = DATA_WR;
352 963 : trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0);
353 963 : buf_state_en = trxn_done;
354 963 : buf_cmd_byte_ptr_en = buf_state_en;
355 963 : slvbuf_wr_en = buf_state_en;
356 963 : buf_cmd_byte_ptr = trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ;
357 963 : cmd_done = trxn_done & (buf_aligned | (buf_cmd_byte_ptrQ == 3'b111) |
358 963 : (buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0));
359 963 : ahb_htrans[1:0] = {2{~(cmd_done | cmd_doneQ)}} & 2'b10;
360 : end
361 345 : DATA_WR: begin
362 345 : buf_state_en = (cmd_doneQ & ahb_hready_q) | ahb_hresp_q;
363 345 : master_ready = buf_state_en & ~ahb_hresp_q & axi_bready; // Ready to accept new command if current command done and no error
364 345 : buf_nxtstate = (ahb_hresp_q | ~axi_bready) ? DONE_WR :
365 345 : ((master_valid & master_ready) ? ((master_opc[2:1] == 2'b01) ? CMD_WR : CMD_RD) : IDLE);
366 345 : slvbuf_error_in = ahb_hresp_q;
367 345 : slvbuf_error_en = buf_state_en;
368 :
369 345 : buf_write_in = (master_opc[2:1] == 2'b01);
370 345 : buf_wr_en = buf_state_en & ((buf_nxtstate == CMD_WR) | (buf_nxtstate == CMD_RD));
371 345 : buf_data_wr_en = buf_wr_en;
372 :
373 345 : cmd_done = (ahb_hresp_q | (ahb_hready_q & (ahb_htrans_q[1:0] != 2'b0) &
374 345 : ((buf_cmd_byte_ptrQ == 3'b111) | (buf_byteen[get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1)] == 1'b0))));
375 345 : bypass_en = buf_state_en & buf_write_in & (buf_nxtstate == CMD_WR); // Only bypass for writes for the time being
376 345 : ahb_htrans[1:0] = {2{(~(cmd_done | cmd_doneQ) | bypass_en)}} & 2'b10;
377 345 : slave_valid_pre = buf_state_en & (buf_nxtstate != DONE_WR);
378 :
379 345 : trxn_done = ahb_hready_q & ahb_hwrite_q & (ahb_htrans_q[1:0] != 2'b0);
380 345 : buf_cmd_byte_ptr_en = trxn_done | bypass_en;
381 345 : buf_cmd_byte_ptr = bypass_en ? get_nxtbyte_ptr(3'b0,buf_byteen_in[7:0],1'b0) :
382 345 : trxn_done ? get_nxtbyte_ptr(buf_cmd_byte_ptrQ[2:0],buf_byteen[7:0],1'b1) : buf_cmd_byte_ptrQ;
383 : end
384 0 : DONE_WR: begin
385 0 : buf_nxtstate = IDLE;
386 0 : buf_state_en = axi_bvalid & axi_bready;
387 0 : slvbuf_error_en = 1'b1;
388 0 : slave_valid_pre = 1'b1;
389 : end
390 1090 : DONE_RD: begin
391 1090 : buf_nxtstate = IDLE;
392 1090 : buf_state_en = axi_rvalid & axi_rready; // axi_rlast == 1
393 1090 : slvbuf_error_en = 1'b1;
394 1090 : slave_valid_pre = 1'b1;
395 : end
396 0 : default: begin
397 0 : buf_nxtstate = IDLE;
398 0 : buf_state_en = 1'b1;
399 : end
400 : endcase
401 : end
402 :
403 : assign buf_rst = dec_tlu_force_halt_bus;
404 : assign cmd_done_rst = slave_valid_pre;
405 : assign buf_addr_in[31:3] = master_addr[31:3];
406 : assign buf_addr_in[2:0] = (buf_aligned_in & (master_opc[2:1] == 2'b01)) ? get_write_addr(master_byteen[7:0]) : master_addr[2:0];
407 : assign buf_tag_in[TAG-1:0] = master_tag[TAG-1:0];
408 : assign buf_byteen_in[7:0] = wrbuf_byteen[7:0];
409 : assign buf_data_in[63:0] = (buf_state == DATA_RD) ? ahb_hrdata_q[63:0] : master_wdata[63:0];
410 : assign buf_size_in[1:0] = (buf_aligned_in & (master_size[1:0] == 2'b11) & (master_opc[2:1] == 2'b01)) ? get_write_size(master_byteen[7:0]) : master_size[1:0];
411 : assign buf_aligned_in = (master_opc[2:0] == 3'b0) | // reads are always aligned since they are either DW or sideeffects
412 : (master_size[1:0] == 2'b0) | (master_size[1:0] == 2'b01) | (master_size[1:0] == 2'b10) | // Always aligned for Byte/HW/Word since they can be only for non-idempotent. IFU/SB are always aligned
413 : ((master_size[1:0] == 2'b11) &
414 : ((master_byteen[7:0] == 8'h3) | (master_byteen[7:0] == 8'hc) | (master_byteen[7:0] == 8'h30) | (master_byteen[7:0] == 8'hc0) |
415 : (master_byteen[7:0] == 8'hf) | (master_byteen[7:0] == 8'hf0) | (master_byteen[7:0] == 8'hff)));
416 :
417 : // Generate the ahb signals
418 : assign ahb_haddr[31:3] = bypass_en ? master_addr[31:3] : buf_addr[31:3];
419 : assign ahb_haddr[2:0] = {3{(ahb_htrans == 2'b10)}} & buf_cmd_byte_ptr[2:0]; // Trxn should be aligned during IDLE
420 : assign ahb_hsize[2:0] = bypass_en ? {1'b0, ({2{buf_aligned_in}} & buf_size_in[1:0])} :
421 : {1'b0, ({2{buf_aligned}} & buf_size[1:0])}; // Send the full size for aligned trxn
422 : assign ahb_hburst[2:0] = 3'b0;
423 : assign ahb_hmastlock = 1'b0;
424 : assign ahb_hprot[3:0] = {3'b001,~axi_arprot[2]};
425 : assign ahb_hwrite = bypass_en ? (master_opc[2:1] == 2'b01) : buf_write;
426 : assign ahb_hwdata[63:0] = buf_data[63:0];
427 :
428 : assign slave_valid = slave_valid_pre;// & (~slvbuf_posted_write | slvbuf_error);
429 : assign slave_opc[3:2] = slvbuf_write ? 2'b11 : 2'b00;
430 : assign slave_opc[1:0] = {2{slvbuf_error}} & 2'b10;
431 : assign slave_rdata[63:0] = slvbuf_error ? {2{last_bus_addr[31:0]}} : ((buf_state == DONE_RD) ? buf_data[63:0] : ahb_hrdata_q[63:0]);
432 : assign slave_tag[TAG-1:0] = slvbuf_tag[TAG-1:0];
433 :
434 : assign last_addr_en = (ahb_htrans[1:0] != 2'b0) & ahb_hready & ahb_hwrite ;
435 :
436 :
437 : rvdffsc_fpga #(.WIDTH(1)) wrbuf_vldff (.din(1'b1), .dout(wrbuf_vld), .en(wrbuf_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
438 : rvdffsc_fpga #(.WIDTH(1)) wrbuf_data_vldff(.din(1'b1), .dout(wrbuf_data_vld), .en(wrbuf_data_en), .clear(wrbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
439 : rvdffs_fpga #(.WIDTH(TAG)) wrbuf_tagff (.din(axi_awid[TAG-1:0]), .dout(wrbuf_tag[TAG-1:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
440 : rvdffs_fpga #(.WIDTH(3)) wrbuf_sizeff (.din(axi_awsize[2:0]), .dout(wrbuf_size[2:0]), .en(wrbuf_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
441 : rvdffe #(.WIDTH(32)) wrbuf_addrff (.din(axi_awaddr[31:0]), .dout(wrbuf_addr[31:0]), .en(wrbuf_en & bus_clk_en), .clk(clk), .*);
442 : rvdffe #(.WIDTH(64)) wrbuf_dataff (.din(axi_wdata[63:0]), .dout(wrbuf_data[63:0]), .en(wrbuf_data_en & bus_clk_en), .clk(clk), .*);
443 : rvdffs_fpga #(.WIDTH(8)) wrbuf_byteenff (.din(axi_wstrb[7:0]), .dout(wrbuf_byteen[7:0]), .en(wrbuf_data_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
444 :
445 : rvdffs_fpga #(.WIDTH(32)) last_bus_addrff (.din(ahb_haddr[31:0]), .dout(last_bus_addr[31:0]), .en(last_addr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
446 :
447 : rvdffsc_fpga #(.WIDTH($bits(state_t))) buf_state_ff (.din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clear(buf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
448 : rvdffs_fpga #(.WIDTH(1)) buf_writeff (.din(buf_write_in), .dout(buf_write), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
449 : rvdffs_fpga #(.WIDTH(TAG)) buf_tagff (.din(buf_tag_in[TAG-1:0]), .dout(buf_tag[TAG-1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
450 : rvdffe #(.WIDTH(32)) buf_addrff (.din(buf_addr_in[31:0]), .dout(buf_addr[31:0]), .en(buf_wr_en & bus_clk_en), .clk(clk), .*);
451 : rvdffs_fpga #(.WIDTH(2)) buf_sizeff (.din(buf_size_in[1:0]), .dout(buf_size[1:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
452 : rvdffs_fpga #(.WIDTH(1)) buf_alignedff (.din(buf_aligned_in), .dout(buf_aligned), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
453 : rvdffs_fpga #(.WIDTH(8)) buf_byteenff (.din(buf_byteen_in[7:0]), .dout(buf_byteen[7:0]), .en(buf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
454 : rvdffe #(.WIDTH(64)) buf_dataff (.din(buf_data_in[63:0]), .dout(buf_data[63:0]), .en(buf_data_wr_en & bus_clk_en), .clk(clk), .*);
455 :
456 :
457 : rvdffs_fpga #(.WIDTH(1)) slvbuf_writeff (.din(buf_write), .dout(slvbuf_write), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
458 : rvdffs_fpga #(.WIDTH(TAG)) slvbuf_tagff (.din(buf_tag[TAG-1:0]), .dout(slvbuf_tag[TAG-1:0]), .en(slvbuf_wr_en), .clk(buf_clk), .clken(buf_clken), .rawclk(clk), .*);
459 : rvdffs_fpga #(.WIDTH(1)) slvbuf_errorff (.din(slvbuf_error_in), .dout(slvbuf_error), .en(slvbuf_error_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
460 :
461 : rvdffsc_fpga #(.WIDTH(1)) buf_cmd_doneff (.din(1'b1), .dout(cmd_doneQ), .en(cmd_done), .clear(cmd_done_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
462 : rvdffs_fpga #(.WIDTH(3)) buf_cmd_byte_ptrff (.din(buf_cmd_byte_ptr[2:0]), .dout(buf_cmd_byte_ptrQ[2:0]), .en(buf_cmd_byte_ptr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
463 :
464 : rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
465 : rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
466 : rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
467 : rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
468 : rvdff_fpga #(.WIDTH(64)) hrdata_ff (.din(ahb_hrdata[63:0]), .dout(ahb_hrdata_q[63:0]), .clk(ahbm_data_clk), .clken(ahbm_data_clken), .rawclk(clk), .*);
469 :
470 : // Clock headers
471 : // clock enables for ahbm addr/data
472 : assign buf_clken = bus_clk_en & (buf_wr_en | slvbuf_wr_en | clk_override);
473 : assign ahbm_data_clken = bus_clk_en & ((buf_state != IDLE) | clk_override);
474 :
475 : `ifdef RV_FPGA_OPTIMIZE
476 : assign bus_clk = 1'b0;
477 : assign buf_clk = 1'b0;
478 : assign ahbm_data_clk = 1'b0;
479 : `else
480 : rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
481 : rvclkhdr buf_cgc (.en(buf_clken), .l1clk(buf_clk), .*);
482 : rvclkhdr ahbm_data_cgc (.en(ahbm_data_clken), .l1clk(ahbm_data_clk), .*);
483 : `endif
484 :
485 : `ifdef RV_ASSERT_ON
486 : property ahb_trxn_aligned;
487 : @(posedge bus_clk) ahb_htrans[1] |-> ((ahb_hsize[2:0] == 3'h0) |
488 : ((ahb_hsize[2:0] == 3'h1) & (ahb_haddr[0] == 1'b0)) |
489 : ((ahb_hsize[2:0] == 3'h2) & (ahb_haddr[1:0] == 2'b0)) |
490 : ((ahb_hsize[2:0] == 3'h3) & (ahb_haddr[2:0] == 3'b0)));
491 : endproperty
492 : assert_ahb_trxn_aligned: assert property (ahb_trxn_aligned) else
493 : $display("Assertion ahb_trxn_aligned failed: ahb_htrans=2'h%h, ahb_hsize=3'h%h, ahb_haddr=32'h%h",ahb_htrans[1:0], ahb_hsize[2:0], ahb_haddr[31:0]);
494 :
495 : property ahb_error_protocol;
496 : @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
497 : endproperty
498 : assert_ahb_error_protocol: assert property (ahb_error_protocol) else
499 : $display("Bus Error with hReady isn't preceded with Bus Error without hready");
500 : `endif
501 :
502 : endmodule // axi4_to_ahb
|