2 Copyright (c) 2013, IIT Madras
5 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
9 * Neither the name of IIT Madras nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
11 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
12 ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
14 // Copyright (c) 2017 Bluespec, Inc. All Rights Reserved
18 // ================================================================
19 // Facilities for ARM AXI4-Lite, consisting of 5 independent channels:
20 // Write Address, Write Data, Write Response, Read Address and Read Data
23 // AMBA AXI and ACE Protocol Specification
24 // AXI3, AXI4, and AXI4-Lite
26 // ARM IHI 0022E (ID022613)
27 // Issue E, 22 Feb 2013
29 // See export list below
31 // ================================================================
36 // RTL-level interfaces (signals/buses)
40 // Dummy slave that accepts no requests and generates no response
41 // Used for tying-off unused slave interfaces on fabrics.
44 // Higher-level enums and structs for the 5 AXI4 channel payloads
53 // Higher-level FIFO-like interfaces for the 5 AXI4 channels,
54 AXI4_Master_Xactor_IFC (..),
55 AXI4_Slave_Xactor_IFC (..),
57 // Transactors from RTL-level interfacecs to FIFO-like interfaces.
61 // ================================================================
62 // BSV library imports
65 import Connectable :: *;
68 // BSV additional libs
70 import Semi_FIFOF :: *;
72 // ****************************************************************
73 // ****************************************************************
74 // Section: RTL-level interfaces
75 // ****************************************************************
76 // ****************************************************************
78 // ================================================================
79 // These are the signal-level interfaces for an AXI4-Lite master.
80 // The (*..*) attributes ensure that when bsc compiles this to Verilog,
81 // we get exactly the signals specified in the ARM spec.
83 interface AXI4_Master_IFC #(numeric type wd_addr,
85 numeric type wd_user);
87 (* always_ready, result="awvalid" *) method Bool m_awvalid; // out
88 (* always_ready, result="awaddr" *) method Bit #(wd_addr) m_awaddr; // out
89 (* always_ready, result="awuser" *) method Bit #(wd_user) m_awuser; // out
90 (* always_ready, result="awlen" *) method Bit #(8) m_awlen; // out
91 (* always_ready, result="awsize" *) method Bit #(3) m_awsize; // out
92 (* always_ready, result="awburst" *) method Bit #(2) m_awburst; // out
93 (* always_ready, result="awid" *) method Bit #(4) m_awid; // out
94 (* always_ready, always_enabled *) method Action m_awready ((* port="awready" *) Bool awready); // in
97 (* always_ready, result="wvalid" *) method Bool m_wvalid; // out
98 (* always_ready, result="wdata" *) method Bit #(wd_data) m_wdata; // out
99 (* always_ready, result="wstrb" *) method Bit #(TDiv #(wd_data, 8)) m_wstrb; // out
100 (* always_ready, result="wlast" *) method Bool m_wlast; // out
101 (* always_ready, result="wid" *) method Bit #(4) m_wid; // out
102 (* always_ready, always_enabled *) method Action m_wready ((* port="wready" *) Bool wready); // in
104 // Wr Response channel
105 (* always_ready, always_enabled *)
106 method Action m_bvalid ((* port="bvalid" *) Bool bvalid, // in
107 (* port="bresp" *) Bit #(2) bresp, // in
108 (* port="buser" *) Bit #(wd_user) buser, // in
109 (* port="bid"*) Bit#(4) bid); // in
110 (* always_ready, result="bready" *)
111 method Bool m_bready; // out
114 (* always_ready, result="arvalid" *) method Bool m_arvalid; // out
115 (* always_ready, result="araddr" *) method Bit #(wd_addr) m_araddr; // out
116 (* always_ready, result="aruser" *) method Bit #(wd_user) m_aruser; // out
117 (* always_ready, result="arlen" *) method Bit #(8) m_arlen; // out
118 (* always_ready, result="arsize" *) method Bit #(3) m_arsize; // out
119 (* always_ready, result="arburst" *) method Bit #(2) m_arburst; // out
120 (* always_ready, result="arid" *) method Bit #(4) m_arid; // out
121 (* always_ready, always_enabled *) method Action m_arready ((* port="arready" *) Bool arready); // in
124 (* always_ready, always_enabled *)
125 method Action m_rvalid ((* port="rvalid" *) Bool rvalid, // in
126 (* port="rresp" *) Bit #(2) rresp, // in
127 (* port="rdata" *) Bit #(wd_data) rdata, // in
128 (* port="rlast" *) Bool rlast, // in
129 (* port="ruser" *) Bit #(wd_user) ruser, // in
130 (* port="rid" *) Bit #(4) rid); // in
131 (* always_ready, result="rready" *)
132 method Bool m_rready; // out
133 endinterface: AXI4_Master_IFC
135 // ================================================================
136 // These are the signal-level interfaces for an AXI4-Lite slave.
137 // The (*..*) attributes ensure that when bsc compiles this to Verilog,
138 // we get exactly the signals specified in the ARM spec.
140 interface AXI4_Slave_IFC #(numeric type wd_addr,
141 numeric type wd_data,
142 numeric type wd_user);
144 (* always_ready, always_enabled *)
145 method Action m_awvalid ((* port="awvalid" *) Bool awvalid, // in
146 (* port="awaddr" *) Bit #(wd_addr) awaddr, // in
147 (* port="awsize" *) Bit #(3) awsize, // in
148 (* port="awuser" *) Bit #(wd_user) awuser, // in
149 (* port="awlen" *) Bit #(8) awlen, // in
150 (* port="awburst" *) Bit #(2) awburst, // in
151 (* port="awid" *) Bit#(4) awid);
152 (* always_ready, result="awready" *)
153 method Bool m_awready; // out
156 (* always_ready, always_enabled *)
157 method Action m_wvalid ((* port="wvalid" *) Bool wvalid, // in
158 (* port="wdata" *) Bit #(wd_data) wdata, // in
159 (* port="wstrb" *) Bit #(TDiv #(wd_data,8)) wstrb, // in
160 (* port="wlast" *) Bool wlast,
161 (* port="wid" *) Bit#(4) wid);
162 (* always_ready, result="wready" *)
163 method Bool m_wready; // out
165 // Wr Response channel
166 (* always_ready, result="bvalid" *) method Bool m_bvalid; // out
167 (* always_ready, result="bresp" *) method Bit #(2) m_bresp; // out
168 (* always_ready, result="buser" *) method Bit #(wd_user) m_buser; // out
169 (* always_ready, result="bid" *) method Bit #(4) m_bid; // out
170 (* always_ready, always_enabled *) method Action m_bready ((* port="bready" *) Bool bready); // in
173 (* always_ready, always_enabled *)
174 method Action m_arvalid ((* port="arvalid" *) Bool arvalid, // in
175 (* port="araddr" *) Bit #(wd_addr) araddr, // in
176 (* port="arsize" *) Bit #(3) arsize, // in
177 (* port="aruser" *) Bit #(wd_user) aruser, // in
178 (* port="arlen" *) Bit #(8) arlen, // in
179 (* port="arburst" *) Bit #(2) arburst, // in
180 (* port="arid" *) Bit#(4) arid
182 (* always_ready, result="arready" *)
183 method Bool m_arready; // out
186 (* always_ready, result="rvalid" *) method Bool m_rvalid; // out
187 (* always_ready, result="rresp" *) method Bit #(2) m_rresp; // out
188 (* always_ready, result="rdata" *) method Bit #(wd_data) m_rdata; // out
189 (* always_ready, result="rlast" *) method Bool m_rlast; // out
190 (* always_ready, result="ruser" *) method Bit #(wd_user) m_ruser; // out
191 (* always_ready, result="rid" *) method Bit #(4) m_rid; // out
192 (* always_ready, always_enabled *) method Action m_rready ((* port="rready" *) Bool rready); // in
193 endinterface: AXI4_Slave_IFC
195 // ================================================================
196 // Connecting signal-level interfaces
198 instance Connectable #(AXI4_Master_IFC #(wd_addr, wd_data, wd_user),
199 AXI4_Slave_IFC #(wd_addr, wd_data, wd_user));
201 module mkConnection #(AXI4_Master_IFC #(wd_addr, wd_data, wd_user) axim,
202 AXI4_Slave_IFC #(wd_addr, wd_data, wd_user) axis)
205 (* fire_when_enabled, no_implicit_conditions *)
206 rule rl_wr_addr_channel;
207 axis.m_awvalid (axim.m_awvalid, axim.m_awaddr, axim.m_awsize, axim.m_awuser, axim.m_awlen, axim.m_awburst, axim.m_awid);
208 axim.m_awready (axis.m_awready);
211 (* fire_when_enabled, no_implicit_conditions *)
212 rule rl_wr_data_channel;
213 axis.m_wvalid (axim.m_wvalid, axim.m_wdata, axim.m_wstrb, axim.m_wlast, axim.m_wid);
214 axim.m_wready (axis.m_wready);
217 (* fire_when_enabled, no_implicit_conditions *)
218 rule rl_wr_response_channel;
219 axim.m_bvalid (axis.m_bvalid, axis.m_bresp, axis.m_buser, axis.m_bid);
220 axis.m_bready (axim.m_bready);
223 (* fire_when_enabled, no_implicit_conditions *)
224 rule rl_rd_addr_channel;
225 axis.m_arvalid (axim.m_arvalid, axim.m_araddr, axim.m_arsize, axim.m_aruser, axim.m_arlen, axim.m_arburst, axim.m_arid);
226 axim.m_arready (axis.m_arready);
229 (* fire_when_enabled, no_implicit_conditions *)
230 rule rl_rd_data_channel;
231 axim.m_rvalid (axis.m_rvalid, axis.m_rresp, axis.m_rdata, axis.m_rlast, axis.m_ruser, axis.m_rid);
232 axis.m_rready (axim.m_rready);
237 // ================================================================
238 // AXI4-Lite dummy slave: never accepts requests, never produces responses
240 AXI4_Slave_IFC #(wd_addr, wd_data, wd_user)
241 dummy_AXI4_Slave_ifc = interface AXI4_Slave_IFC
243 method Action m_awvalid (Bool awvalid,
244 Bit #(wd_addr) awaddr,
246 Bit #(wd_user) awuser,
253 method Bool m_awready;
258 method Action m_wvalid (Bool wvalid,
259 Bit #(wd_data) wdata,
260 Bit #(TDiv #(wd_data,8)) wstrb,
266 method Bool m_wready;
270 // Wr Response channel
271 method Bool m_bvalid;
275 method Bit #(2) m_bresp;
279 method Bit #(wd_user) m_buser;
282 method Bit #(4) m_bid;
286 method Action m_bready (Bool bready);
291 method Action m_arvalid (Bool arvalid,
292 Bit #(wd_addr) araddr,
294 Bit #(wd_user) aruser,
301 method Bool m_arready;
306 method Bool m_rvalid;
310 method Bit #(2) m_rresp;
314 method Bit #(wd_data) m_rdata;
321 method Bit #(wd_user) m_ruser;
325 method Action m_rready (Bool rready);
330 // ****************************************************************
331 // ****************************************************************
332 // Section: Higher-level FIFO-like interfaces and transactors
333 // ****************************************************************
334 // ****************************************************************
336 // ================================================================
337 // Higher-level types for payloads (rather than just bits)
339 typedef enum { AXI4_OKAY, AXI4_EXOKAY, AXI4_SLVERR, AXI4_DECERR } AXI4_Resp
340 deriving (Bits, Eq, FShow);
342 // Write Address channel
345 Bit #(wd_addr) awaddr;
346 Bit #(wd_user) awuser;
351 } AXI4_Wr_Addr #(numeric type wd_addr, numeric type wd_user)
352 deriving (Bits, FShow);
354 // Write Data channel
357 Bit #(wd_data) wdata;
358 Bit #(TDiv #(wd_data, 8)) wstrb;
361 } AXI4_Wr_Data #(numeric type wd_data)
362 deriving (Bits, FShow);
364 // Write Response channel
368 Bit #(wd_user) buser;
370 } AXI4_Wr_Resp #(numeric type wd_user)
371 deriving (Bits, FShow);
373 // Read Address channel
376 Bit #(wd_addr) araddr;
377 Bit #(wd_user) aruser;
382 } AXI4_Rd_Addr #(numeric type wd_addr, numeric type wd_user)
383 deriving (Bits, FShow);
389 Bit #(wd_data) rdata;
391 Bit #(wd_user) ruser;
393 } AXI4_Rd_Data #(numeric type wd_data, numeric type wd_user)
394 deriving (Bits, FShow);
396 // ================================================================
397 // Master transactor interface
399 interface AXI4_Master_Xactor_IFC #(numeric type wd_addr,
400 numeric type wd_data,
401 numeric type wd_user);
405 interface AXI4_Master_IFC #(wd_addr, wd_data, wd_user) axi_side;
408 interface FIFOF_I #(AXI4_Wr_Addr #(wd_addr, wd_user)) i_wr_addr;
409 interface FIFOF_I #(AXI4_Wr_Data #(wd_data)) i_wr_data;
410 interface FIFOF_O #(AXI4_Wr_Resp #(wd_user)) o_wr_resp;
412 interface FIFOF_I #(AXI4_Rd_Addr #(wd_addr, wd_user)) i_rd_addr;
413 interface FIFOF_O #(AXI4_Rd_Data #(wd_data, wd_user)) o_rd_data;
414 endinterface: AXI4_Master_Xactor_IFC
416 // ----------------------------------------------------------------
419 module mkAXI4_Master_Xactor (AXI4_Master_Xactor_IFC #(wd_addr, wd_data, wd_user));
421 Bool unguarded = True;
422 Bool guarded = False;
424 // These FIFOs are guarded on BSV side, unguarded on AXI side
425 FIFOF #(AXI4_Wr_Addr #(wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (guarded, unguarded);
426 FIFOF #(AXI4_Wr_Data #(wd_data)) f_wr_data <- mkGFIFOF (guarded, unguarded);
427 FIFOF #(AXI4_Wr_Resp #(wd_user)) f_wr_resp <- mkGFIFOF (unguarded, guarded);
429 FIFOF #(AXI4_Rd_Addr #(wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (guarded, unguarded);
430 FIFOF #(AXI4_Rd_Data #(wd_data, wd_user)) f_rd_data <- mkGFIFOF (unguarded, guarded);
432 // ----------------------------------------------------------------
444 interface axi_side = interface AXI4_Master_IFC;
446 method Bool m_awvalid = f_wr_addr.notEmpty;
447 method Bit #(wd_addr) m_awaddr = f_wr_addr.first.awaddr;
448 method Bit #(wd_user) m_awuser = f_wr_addr.first.awuser;
449 method Bit #(8) m_awlen = f_wr_addr.first.awlen;
450 method Bit #(3) m_awsize = f_wr_addr.first.awsize;
451 method Bit #(2) m_awburst = f_wr_addr.first.awburst;
452 method Bit #(4) m_awid = f_wr_addr.first.awid;
453 method Action m_awready (Bool awready);
454 if (f_wr_addr.notEmpty && awready) f_wr_addr.deq;
458 method Bool m_wvalid = f_wr_data.notEmpty;
459 method Bit #(wd_data) m_wdata = f_wr_data.first.wdata;
460 method Bit #(TDiv #(wd_data, 8)) m_wstrb = f_wr_data.first.wstrb;
461 method Bool m_wlast = f_wr_data.first.wlast;
462 method Bit#(4) m_wid = f_wr_data.first.wid;
463 method Action m_wready (Bool wready);
464 if (f_wr_data.notEmpty && wready) f_wr_data.deq;
467 // Wr Response channel
468 method Action m_bvalid (Bool bvalid, Bit #(2) bresp, Bit #(wd_user) buser, Bit#(4) bid);
469 if (bvalid && f_wr_resp.notFull)
470 f_wr_resp.enq (AXI4_Wr_Resp {bresp: unpack (bresp), buser: buser, bid:bid});
473 method Bool m_bready;
474 return f_wr_resp.notFull;
478 method Bool m_arvalid = f_rd_addr.notEmpty;
479 method Bit #(wd_addr) m_araddr = f_rd_addr.first.araddr;
480 method Bit #(wd_user) m_aruser = f_rd_addr.first.aruser;
481 method Bit #(3) m_arsize = f_rd_addr.first.arsize;
482 method Bit #(8) m_arlen = f_rd_addr.first.arlen;
483 method Bit #(2) m_arburst = f_rd_addr.first.arburst;
484 method Bit #(4) m_arid = f_rd_addr.first.arid;
485 method Action m_arready (Bool arready);
486 if (f_rd_addr.notEmpty && arready) f_rd_addr.deq;
490 method Action m_rvalid (Bool rvalid,
492 Bit #(wd_data) rdata,
494 Bit #(wd_user) ruser,
496 if (rvalid && f_rd_data.notFull)
497 f_rd_data.enq (AXI4_Rd_Data {rresp: unpack (rresp),
504 method Bool m_rready;
505 return f_rd_data.notFull;
511 interface i_wr_addr = to_FIFOF_I (f_wr_addr);
512 interface i_wr_data = to_FIFOF_I (f_wr_data);
513 interface o_wr_resp = to_FIFOF_O (f_wr_resp);
515 interface i_rd_addr = to_FIFOF_I (f_rd_addr);
516 interface o_rd_data = to_FIFOF_O (f_rd_data);
517 endmodule: mkAXI4_Master_Xactor
519 // ================================================================
520 // Slave transactor interface
522 interface AXI4_Slave_Xactor_IFC #(numeric type wd_addr,
523 numeric type wd_data,
524 numeric type wd_user);
528 interface AXI4_Slave_IFC #(wd_addr, wd_data, wd_user) axi_side;
531 interface FIFOF_O #(AXI4_Wr_Addr #(wd_addr, wd_user)) o_wr_addr;
532 interface FIFOF_O #(AXI4_Wr_Data #(wd_data)) o_wr_data;
533 interface FIFOF_I #(AXI4_Wr_Resp #(wd_user)) i_wr_resp;
535 interface FIFOF_O #(AXI4_Rd_Addr #(wd_addr, wd_user)) o_rd_addr;
536 interface FIFOF_I #(AXI4_Rd_Data #(wd_data, wd_user)) i_rd_data;
537 endinterface: AXI4_Slave_Xactor_IFC
539 // ----------------------------------------------------------------
542 module mkAXI4_Slave_Xactor (AXI4_Slave_Xactor_IFC #(wd_addr, wd_data, wd_user));
544 Bool unguarded = True;
545 Bool guarded = False;
547 // These FIFOs are guarded on BSV side, unguarded on AXI side
548 FIFOF #(AXI4_Wr_Addr #(wd_addr, wd_user)) f_wr_addr <- mkGFIFOF (unguarded, guarded);
549 FIFOF #(AXI4_Wr_Data #(wd_data)) f_wr_data <- mkGFIFOF (unguarded, guarded);
550 FIFOF #(AXI4_Wr_Resp #(wd_user)) f_wr_resp <- mkGFIFOF (guarded, unguarded);
552 FIFOF #(AXI4_Rd_Addr #(wd_addr, wd_user)) f_rd_addr <- mkGFIFOF (unguarded, guarded);
553 FIFOF #(AXI4_Rd_Data #(wd_data, wd_user)) f_rd_data <- mkGFIFOF (guarded, unguarded);
555 // ----------------------------------------------------------------
567 interface axi_side = interface AXI4_Slave_IFC;
569 method Action m_awvalid (Bool awvalid,
570 Bit #(wd_addr) awaddr,
572 Bit #(wd_user) awuser,
576 if (awvalid && f_wr_addr.notFull)
577 f_wr_addr.enq (AXI4_Wr_Addr {awaddr: awaddr,
585 method Bool m_awready;
586 return f_wr_addr.notFull;
590 method Action m_wvalid (Bool wvalid,
591 Bit #(wd_data) wdata,
592 Bit #(TDiv #(wd_data, 8)) wstrb,
595 if (wvalid && f_wr_data.notFull)
596 f_wr_data.enq (AXI4_Wr_Data {wdata: wdata, wstrb: wstrb, wlast:wlast, wid:wid});
599 method Bool m_wready;
600 return f_wr_data.notFull;
603 // Wr Response channel
604 method Bool m_bvalid = f_wr_resp.notEmpty;
605 method Bit #(2) m_bresp = pack (f_wr_resp.first.bresp);
606 method Bit #(wd_user) m_buser = f_wr_resp.first.buser;
607 method Bit #(4) m_bid = f_wr_resp.first.bid;
608 method Action m_bready (Bool bready);
609 if (bready && f_wr_resp.notEmpty)
614 method Action m_arvalid (Bool arvalid,
615 Bit #(wd_addr) araddr,
617 Bit #(wd_user) aruser,
621 if (arvalid && f_rd_addr.notFull)
622 f_rd_addr.enq (AXI4_Rd_Addr {araddr: araddr,
630 method Bool m_arready;
631 return f_rd_addr.notFull;
635 method Bool m_rvalid = f_rd_data.notEmpty;
636 method Bit #(2) m_rresp = pack (f_rd_data.first.rresp);
637 method Bit #(wd_data) m_rdata = f_rd_data.first.rdata;
638 method Bool m_rlast = f_rd_data.first.rlast;
639 method Bit #(wd_user) m_ruser = f_rd_data.first.ruser;
640 method Bit#(4) m_rid=f_rd_data.first.rid;
641 method Action m_rready (Bool rready);
642 if (rready && f_rd_data.notEmpty)
648 interface o_wr_addr = to_FIFOF_O (f_wr_addr);
649 interface o_wr_data = to_FIFOF_O (f_wr_data);
650 interface i_wr_resp = to_FIFOF_I (f_wr_resp);
652 interface o_rd_addr = to_FIFOF_O (f_rd_addr);
653 interface i_rd_data = to_FIFOF_I (f_rd_data);
654 endmodule: mkAXI4_Slave_Xactor
656 // ================================================================