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 : // $Id$
17 : //
18 : // Owner:
19 : // Function: AHB to AXI4 Bridge
20 : // Comments:
21 : //
22 : //********************************************************************************
23 : module ahb_to_axi4
24 : import el2_pkg::*;
25 : #(
26 : TAG = 1,
27 : CHECK_RANGES = 1,
28 : `include "el2_param.vh"
29 : )
30 : (
31 75475744 : input clk,
32 35 : input rst_l,
33 : /* pragma coverage off */
34 : input scan_mode,
35 : /* pragma coverage on */
36 23 : input bus_clk_en,
37 0 : input clk_override,
38 :
39 : // AXI signals
40 : // AXI Write Channels
41 247142 : output logic axi_awvalid,
42 247163 : input logic axi_awready,
43 : /* exclude signals that are tied to constant value in this file */
44 : /*pragma coverage off*/
45 : output logic [TAG-1:0] axi_awid,
46 : /*pragma coverage on*/
47 338210 : output logic [31:0] axi_awaddr,
48 185915 : output logic [2:0] axi_awsize,
49 : /* exclude signals that are tied to constant value in this file */
50 : /*pragma coverage off*/
51 : output logic [2:0] axi_awprot,
52 : output logic [7:0] axi_awlen,
53 : output logic [1:0] axi_awburst,
54 : /*pragma coverage on*/
55 :
56 247142 : output logic axi_wvalid,
57 247067 : input logic axi_wready,
58 49638 : output logic [63:0] axi_wdata,
59 205881 : output logic [7:0] axi_wstrb,
60 : /* exclude signals that are tied to constant value in this file */
61 : /*pragma coverage off*/
62 : output logic axi_wlast,
63 : /*pragma coverage on*/
64 :
65 247044 : input logic axi_bvalid,
66 : /* exclude signals that are tied to constant value in this file */
67 : /*pragma coverage off*/
68 : output logic axi_bready,
69 : /*pragma coverage on*/
70 2 : input logic [1:0] axi_bresp,
71 : /* Exclude unused AXI rid since it has no equivalent in AHB */
72 : /*pragma coverage off*/
73 : input logic [TAG-1:0] axi_bid,
74 : /*pragma coverage on*/
75 :
76 : // AXI Read Channels
77 537688 : output logic axi_arvalid,
78 537749 : input logic axi_arready,
79 : /* exclude signals that are tied to constant value in this file */
80 : /*pragma coverage off*/
81 : output logic [TAG-1:0] axi_arid,
82 : /*pragma coverage on*/
83 338210 : output logic [31:0] axi_araddr,
84 185915 : output logic [2:0] axi_arsize,
85 : /* exclude signals that are tied to constant value in this file */
86 : /*pragma coverage off*/
87 : output logic [2:0] axi_arprot,
88 : output logic [7:0] axi_arlen,
89 : output logic [1:0] axi_arburst,
90 : /*pragma coverage on*/
91 :
92 537686 : input logic axi_rvalid,
93 : /* exclude signals that are tied to constant value in this file */
94 : /*pragma coverage off*/
95 : output logic axi_rready,
96 : /*pragma coverage on*/
97 : /* Exclude unused AXI rid since it has no equivalent in AHB */
98 : /*pragma coverage off*/
99 : input logic [TAG-1:0] axi_rid,
100 : /*pragma coverage on*/
101 14595 : input logic [63:0] axi_rdata,
102 2 : input logic [1:0] axi_rresp,
103 :
104 : // AHB-Lite signals
105 339180 : input logic [31:0] ahb_haddr, // ahb bus address
106 : // Exclude input signals that are unused in this file (their AXI equivalents
107 : // are tied to constants)
108 : /*pragma coverage off*/
109 : input logic [2:0] ahb_hburst, // tied to 0
110 : input logic ahb_hmastlock, // tied to 0
111 : input logic [3:0] ahb_hprot, // tied to 4'b0011
112 : /*pragma coverage on*/
113 186275 : input logic [2:0] ahb_hsize, // size of bus transaction (possible values 0,1,2,3)
114 783453 : input logic [1:0] ahb_htrans, // Transaction type (possible values 0,2 only right now)
115 185255 : input logic ahb_hwrite, // ahb bus write
116 131450 : input logic [63:0] ahb_hwdata, // ahb bus write data
117 35 : input logic ahb_hsel, // this slave was selected
118 23 : input logic ahb_hreadyin, // previous hready was accepted or not
119 :
120 14578 : output logic [63:0] ahb_hrdata, // ahb bus read data
121 537714 : output logic ahb_hreadyout, // slave ready to accept transaction
122 0 : output logic ahb_hresp // slave response (high indicates erro)
123 :
124 : );
125 :
126 205881 : logic [7:0] master_wstrb;
127 :
128 : typedef enum logic [1:0] { IDLE = 2'b00, // Nothing in the buffer. No commands yet recieved
129 : WR = 2'b01, // Write Command recieved
130 : RD = 2'b10, // Read Command recieved
131 : PEND = 2'b11 // Waiting on Read Data from core
132 : } state_t;
133 969967 : state_t buf_state, buf_nxtstate;
134 1320523 : logic buf_state_en;
135 :
136 : // Buffer signals (one entry buffer)
137 0 : logic buf_read_error_in, buf_read_error;
138 14578 : logic [63:0] buf_rdata;
139 :
140 537714 : logic ahb_hready;
141 537724 : logic ahb_hready_q;
142 783453 : logic [1:0] ahb_htrans_in, ahb_htrans_q;
143 185915 : logic [2:0] ahb_hsize_q;
144 185252 : logic ahb_hwrite_q;
145 338210 : logic [31:0] ahb_haddr_q;
146 0 : logic ahb_hresp_q;
147 :
148 : // signals needed for the read data coming back from the core and to block any further commands as AHB is a blocking bus
149 537686 : logic buf_rdata_en;
150 :
151 784835 : logic ahb_addr_clk_en, buf_rdata_clk_en;
152 12224 : logic bus_clk, ahb_addr_clk, buf_rdata_clk;
153 : // Command buffer is the holding station where we convert to AXI and send to core
154 784834 : logic cmdbuf_wr_en, cmdbuf_rst;
155 206 : logic cmdbuf_full;
156 784830 : logic cmdbuf_vld, cmdbuf_write;
157 185915 : logic [1:0] cmdbuf_size;
158 205881 : logic [7:0] cmdbuf_wstrb;
159 338210 : logic [31:0] cmdbuf_addr;
160 49638 : logic [63:0] cmdbuf_wdata;
161 :
162 : // FSM to control the bus states and when to block the hready and load the command buffer
163 23719916 : always_comb begin
164 23719916 : buf_nxtstate = IDLE;
165 23719916 : buf_state_en = 1'b0;
166 23719916 : buf_rdata_en = 1'b0; // signal to load the buffer when the core sends read data back
167 23719916 : buf_read_error_in = 1'b0; // signal indicating that an error came back with the read from the core
168 23719916 : cmdbuf_wr_en = 1'b0; // all clear from the gasket to load the buffer with the command for reads, command/dat for writes
169 23719916 : case (buf_state)
170 22778942 : IDLE: begin // No commands recieved
171 22778942 : buf_nxtstate = ahb_hwrite ? WR : RD;
172 22778942 : buf_state_en = ahb_hready & ahb_htrans[1] & ahb_hsel; // only transition on a valid hrtans
173 : end
174 126516 : WR: begin // Write command recieved last cycle
175 126516 : buf_nxtstate = (ahb_hresp | (ahb_htrans[1:0] == 2'b0) | ~ahb_hsel) ? IDLE : ahb_hwrite ? WR : RD;
176 126516 : buf_state_en = (~cmdbuf_full | ahb_hresp) ;
177 126516 : cmdbuf_wr_en = ~cmdbuf_full & ~(ahb_hresp | ((ahb_htrans[1:0] == 2'b01) & ahb_hsel)); // Dont send command to the buffer in case of an error or when the master is not ready with the data now.
178 : end
179 270934 : RD: begin // Read command recieved last cycle.
180 270934 : buf_nxtstate = ahb_hresp ? IDLE :PEND; // If error go to idle, else wait for read data
181 270934 : buf_state_en = (~cmdbuf_full | ahb_hresp); // only when command can go, or if its an error
182 270934 : cmdbuf_wr_en = ~ahb_hresp & ~cmdbuf_full; // send command only when no error
183 : end
184 543524 : PEND: begin // Read Command has been sent. Waiting on Data.
185 543524 : buf_nxtstate = IDLE; // go back for next command and present data next cycle
186 543524 : buf_state_en = axi_rvalid & ~cmdbuf_write; // read data is back
187 543524 : buf_rdata_en = buf_state_en; // buffer the read data coming back from core
188 543524 : buf_read_error_in = buf_state_en & |axi_rresp[1:0]; // buffer error flag if return has Error ( ECC )
189 : end
190 : endcase
191 : end // always_comb begin
192 :
193 : rvdffs_fpga #($bits(state_t)) state_reg (.*, .din(buf_nxtstate), .dout({buf_state}), .en(buf_state_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk));
194 :
195 : assign master_wstrb[7:0] = ({8{ahb_hsize_q[2:0] == 3'b0}} & (8'b1 << ahb_haddr_q[2:0])) |
196 : ({8{ahb_hsize_q[2:0] == 3'b1}} & (8'b11 << ahb_haddr_q[2:0])) |
197 : ({8{ahb_hsize_q[2:0] == 3'b10}} & (8'b1111 << ahb_haddr_q[2:0])) |
198 : ({8{ahb_hsize_q[2:0] == 3'b11}} & 8'b1111_1111);
199 :
200 : // AHB signals
201 : assign ahb_hreadyout = ahb_hresp ? (ahb_hresp_q & ~ahb_hready_q) :
202 : ((~cmdbuf_full | (buf_state == IDLE)) & ~(buf_state == RD | buf_state == PEND) & ~buf_read_error);
203 :
204 : assign ahb_hready = ahb_hreadyout & ahb_hreadyin;
205 : assign ahb_htrans_in[1:0] = {2{ahb_hsel}} & ahb_htrans[1:0];
206 : assign ahb_hrdata[63:0] = buf_rdata[63:0];
207 :
208 : if (CHECK_RANGES) begin
209 : // Miscellaneous signals
210 : logic ahb_addr_in_dccm, ahb_addr_in_iccm, ahb_addr_in_pic;
211 : logic ahb_addr_in_dccm_region_nc, ahb_addr_in_iccm_region_nc, ahb_addr_in_pic_region_nc;
212 :
213 : assign ahb_hresp = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE) &
214 : ((~(ahb_addr_in_dccm | ahb_addr_in_iccm)) | // request not for ICCM or DCCM
215 : ((ahb_addr_in_iccm | (ahb_addr_in_dccm & ahb_hwrite_q)) & ~((ahb_hsize_q[1:0] == 2'b10) | (ahb_hsize_q[1:0] == 2'b11))) | // ICCM Rd/Wr OR DCCM Wr not the right size
216 : ((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) | // HW size but unaligned
217 : ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) | // W size but unaligned
218 : ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned
219 : buf_read_error | // Read ECC error
220 : (ahb_hresp_q & ~ahb_hready_q);
221 :
222 : // Address check dccm
223 : rvrangecheck #(.CCM_SADR(pt.DCCM_SADR),
224 : .CCM_SIZE(pt.DCCM_SIZE)) addr_dccm_rangecheck (
225 : .addr(ahb_haddr_q[31:0]),
226 : .in_range(ahb_addr_in_dccm),
227 : .in_region(ahb_addr_in_dccm_region_nc)
228 : );
229 :
230 : // Address check iccm
231 : if (pt.ICCM_ENABLE == 1) begin: GenICCM
232 : rvrangecheck #(.CCM_SADR(pt.ICCM_SADR),
233 : .CCM_SIZE(pt.ICCM_SIZE)) addr_iccm_rangecheck (
234 : .addr(ahb_haddr_q[31:0]),
235 : .in_range(ahb_addr_in_iccm),
236 : .in_region(ahb_addr_in_iccm_region_nc)
237 : );
238 : end else begin: GenNoICCM
239 : assign ahb_addr_in_iccm = '0;
240 : assign ahb_addr_in_iccm_region_nc = '0;
241 : end
242 :
243 : // PIC memory address check
244 : rvrangecheck #(.CCM_SADR(pt.PIC_BASE_ADDR),
245 : .CCM_SIZE(pt.PIC_SIZE)) addr_pic_rangecheck (
246 : .addr(ahb_haddr_q[31:0]),
247 : .in_range(ahb_addr_in_pic),
248 : .in_region(ahb_addr_in_pic_region_nc)
249 : );
250 : end else begin // !CHECK_RANGES
251 : assign ahb_hresp = ((ahb_htrans_q[1:0] != 2'b0) & (buf_state != IDLE) &
252 : (((ahb_hsize_q[2:0] == 3'h1) & ahb_haddr_q[0]) | // HW size but unaligned
253 : ((ahb_hsize_q[2:0] == 3'h2) & (|ahb_haddr_q[1:0])) | // W size but unaligned
254 : ((ahb_hsize_q[2:0] == 3'h3) & (|ahb_haddr_q[2:0])))) | // DW size but unaligned
255 : buf_read_error | // Read ECC error
256 : (ahb_hresp_q & ~ahb_hready_q);
257 : end // CHECK_RANGES
258 :
259 : // Buffer signals - needed for the read data and ECC error response
260 : rvdff_fpga #(.WIDTH(64)) buf_rdata_ff (.din(axi_rdata[63:0]), .dout(buf_rdata[63:0]), .clk(buf_rdata_clk), .clken(buf_rdata_clk_en), .rawclk(clk), .*);
261 : rvdff_fpga #(.WIDTH(1)) buf_read_error_ff(.din(buf_read_error_in), .dout(buf_read_error), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*); // buf_read_error will be high only one cycle
262 :
263 : // All the Master signals are captured before presenting it to the command buffer. We check for Hresp before sending it to the cmd buffer.
264 : rvdff_fpga #(.WIDTH(1)) hresp_ff (.din(ahb_hresp), .dout(ahb_hresp_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
265 : rvdff_fpga #(.WIDTH(1)) hready_ff (.din(ahb_hready), .dout(ahb_hready_q), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
266 : rvdff_fpga #(.WIDTH(2)) htrans_ff (.din(ahb_htrans_in[1:0]), .dout(ahb_htrans_q[1:0]), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
267 : rvdff_fpga #(.WIDTH(3)) hsize_ff (.din(ahb_hsize[2:0]), .dout(ahb_hsize_q[2:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
268 : rvdff_fpga #(.WIDTH(1)) hwrite_ff (.din(ahb_hwrite), .dout(ahb_hwrite_q), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
269 : rvdff_fpga #(.WIDTH(32)) haddr_ff (.din(ahb_haddr[31:0]), .dout(ahb_haddr_q[31:0]), .clk(ahb_addr_clk), .clken(ahb_addr_clk_en), .rawclk(clk), .*);
270 :
271 : // Command Buffer - Holding for the commands to be sent for the AXI. It will be converted to the AXI signals.
272 : assign cmdbuf_rst = (((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)) & ~cmdbuf_wr_en) | (ahb_hresp & ~cmdbuf_write);
273 : assign cmdbuf_full = (cmdbuf_vld & ~((axi_awvalid & axi_awready) | (axi_arvalid & axi_arready)));
274 :
275 : rvdffsc_fpga #(.WIDTH(1)) cmdbuf_vldff (.din(1'b1), .dout(cmdbuf_vld), .en(cmdbuf_wr_en), .clear(cmdbuf_rst), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
276 : rvdffs_fpga #(.WIDTH(1)) cmdbuf_writeff (.din(ahb_hwrite_q), .dout(cmdbuf_write), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
277 : rvdffs_fpga #(.WIDTH(2)) cmdbuf_sizeff (.din(ahb_hsize_q[1:0]), .dout(cmdbuf_size[1:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
278 : rvdffs_fpga #(.WIDTH(8)) cmdbuf_wstrbff (.din(master_wstrb[7:0]), .dout(cmdbuf_wstrb[7:0]), .en(cmdbuf_wr_en), .clk(bus_clk), .clken(bus_clk_en), .rawclk(clk), .*);
279 : rvdffe #(.WIDTH(32)) cmdbuf_addrff (.din(ahb_haddr_q[31:0]), .dout(cmdbuf_addr[31:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*);
280 : rvdffe #(.WIDTH(64)) cmdbuf_wdataff (.din(ahb_hwdata[63:0]), .dout(cmdbuf_wdata[63:0]), .en(cmdbuf_wr_en & bus_clk_en), .clk(clk), .*);
281 :
282 : // AXI Write Command Channel
283 : assign axi_awvalid = cmdbuf_vld & cmdbuf_write;
284 : assign axi_awid[TAG-1:0] = '0;
285 : assign axi_awaddr[31:0] = cmdbuf_addr[31:0];
286 : assign axi_awsize[2:0] = {1'b0, cmdbuf_size[1:0]};
287 : assign axi_awprot[2:0] = 3'b0;
288 : assign axi_awlen[7:0] = '0;
289 : assign axi_awburst[1:0] = 2'b01;
290 : // AXI Write Data Channel - This is tied to the command channel as we only write the command buffer once we have the data.
291 : assign axi_wvalid = cmdbuf_vld & cmdbuf_write;
292 : assign axi_wdata[63:0] = cmdbuf_wdata[63:0];
293 : assign axi_wstrb[7:0] = cmdbuf_wstrb[7:0];
294 : assign axi_wlast = 1'b1;
295 : // AXI Write Response - Always ready. AHB does not require a write response.
296 : assign axi_bready = 1'b1;
297 : // AXI Read Channels
298 : assign axi_arvalid = cmdbuf_vld & ~cmdbuf_write;
299 : assign axi_arid[TAG-1:0] = '0;
300 : assign axi_araddr[31:0] = cmdbuf_addr[31:0];
301 : assign axi_arsize[2:0] = {1'b0, cmdbuf_size[1:0]};
302 : assign axi_arprot = 3'b0;
303 : assign axi_arlen[7:0] = '0;
304 : assign axi_arburst[1:0] = 2'b01;
305 : // AXI Read Response Channel - Always ready as AHB reads are blocking and the the buffer is available for the read coming back always.
306 : assign axi_rready = 1'b1;
307 :
308 : // Clock header logic
309 : assign ahb_addr_clk_en = bus_clk_en & (ahb_hready & ahb_htrans[1]);
310 : assign buf_rdata_clk_en = bus_clk_en & buf_rdata_en;
311 :
312 : `ifdef RV_FPGA_OPTIMIZE
313 : assign bus_clk = 1'b0;
314 : assign ahb_addr_clk = 1'b0;
315 : assign buf_rdata_clk = 1'b0;
316 : `else
317 : rvclkhdr bus_cgc (.en(bus_clk_en), .l1clk(bus_clk), .*);
318 : rvclkhdr ahb_addr_cgc (.en(ahb_addr_clk_en), .l1clk(ahb_addr_clk), .*);
319 : rvclkhdr buf_rdata_cgc (.en(buf_rdata_clk_en), .l1clk(buf_rdata_clk), .*);
320 : `endif
321 :
322 : `ifdef RV_ASSERT_ON
323 : property ahb_error_protocol;
324 : @(posedge bus_clk) (ahb_hready & ahb_hresp) |-> (~$past(ahb_hready) & $past(ahb_hresp));
325 : endproperty
326 : assert_ahb_error_protocol: assert property (ahb_error_protocol) else
327 : $display("Bus Error with hReady isn't preceded with Bus Error without hready");
328 :
329 : `endif
330 :
331 : endmodule // ahb_to_axi4
|