fpga: lib: Add AXI4 (full) interface

Add a SystemVerilog interface for connecting AXI4 ports, and an
associated header file with helper macros.


Original-commit: 04d29e85b0c0698e3de96b54fd3f6e04eb439f74
This commit is contained in:
Andrew Moch
2021-06-03 11:26:54 -05:00
committed by Aaron Rossetto
parent d7acf31a38
commit 8cb9bdd331
4 changed files with 619 additions and 0 deletions
+329
View File
@@ -0,0 +1,329 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Interface: AxiIf
// Description:
// AXI4 is an ARM standard for bursting memory mapped transfers
// For more information on the spec see
// - https://developer.arm.com/docs/ihi0022/d
//
// The interface contains methods for
// (1) Writing an address
// (2) Reading an address
//
// Parameters:
// - DATA_WIDTH - Width of the data on AXI4 bus
// - ADDR_WIDTH - Width of the address on AXI4 bus
//
//-----------------------------------------------------------------------------
// AXI4 interface
//-----------------------------------------------------------------------------
interface AxiIf #(
int DATA_WIDTH = 64,
int ADDR_WIDTH = 1
) (
input logic clk,
input logic rst = 1'b0
);
import PkgAxi::*;
localparam BYTES_PER_WORD = DATA_WIDTH/8;
// local type defs
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [BYTES_PER_WORD-1:0] strb_t;
typedef logic [7:0] len_t;
typedef logic [2:0] size_t;
typedef logic [1:0] burst_t;
typedef logic [0:0] lock_t;
typedef logic [3:0] cache_t;
typedef logic [2:0] prot_t;
typedef logic [3:0] qos_t;
// Signals that make up an Axi interface
// Write Address Channel
addr_t awaddr;
len_t awlen;
size_t awsize;
burst_t awburst;
lock_t awlock;
cache_t awcache;
prot_t awprot;
qos_t awqos;
logic awvalid;
logic awready;
// Write Data Channel
data_t wdata;
strb_t wstrb = '1;
logic wlast;
logic wvalid;
logic wready;
// Write Response Channel
axi_resp_t bresp;
logic bvalid;
logic bready;
// Read Address Channel
addr_t araddr;
len_t arlen;
size_t arsize;
burst_t arburst;
lock_t arlock;
cache_t arcache;
prot_t arprot;
qos_t arqos;
logic arvalid;
logic arready;
// Read Data Channel
data_t rdata;
axi_resp_t rresp;
logic rlast;
logic rvalid;
logic rready;
// Master Functions
task automatic drive_aw(input addr_t addr,
input len_t len,
input size_t size,
input burst_t burst,
input lock_t lock,
input cache_t cache,
input prot_t prot,
input qos_t qos);
awaddr = addr;
awlen = len;
awsize = size;
awburst = burst;
awlock = lock;
awcache = cache;
awprot = prot;
awqos = qos;
awvalid = 1;
endtask
task automatic drive_w(input data_t data,
input logic last,
input strb_t strb = '1);
wdata = data;
wstrb = strb;
wlast = last;
wvalid = 1;
endtask
task automatic drive_aw_idle();
awaddr = 'X;
awlen = 'X;
awsize = 'X;
awburst = 'X;
awlock = 'X;
awcache = 'X;
awprot = 'X;
awqos = 'X;
awvalid = 0;
endtask
task automatic drive_w_idle();
wdata = 'X;
wstrb = 'X;
wlast = 1'bX;
wvalid = 0;
endtask
task automatic drive_read(input addr_t addr,
input len_t len,
input size_t size,
input burst_t burst,
input lock_t lock,
input cache_t cache,
input prot_t prot,
input qos_t qos);
araddr = addr;
arlen = len;
arsize = size;
arburst = burst;
arlock = lock;
arcache = cache;
arprot = prot;
arqos = qos;
arvalid = 1;
endtask
task automatic drive_read_idle();
araddr = 'X;
araddr = 'X;
arlen = 'X;
arsize = 'X;
arburst = 'X;
arlock = 'X;
arcache = 'X;
arprot = 'X;
arqos = 'X;
arvalid = 0;
endtask
// Slave Functions
task automatic drive_write_resp(input axi_resp_t resp=OKAY);
bresp = resp;
bvalid = 1;
endtask
task automatic drive_write_resp_idle();
bresp = OKAY;
bvalid = 0;
endtask
task automatic drive_read_resp(input data_t data,
input logic last,
input axi_resp_t resp=OKAY);
rdata = data;
rresp = resp;
rlast = last;
rvalid = 1;
endtask
task automatic drive_read_resp_idle();
rdata = 'X;
rresp = OKAY;
rlast = 1'bX;
rvalid = 0;
endtask
// View from the master side
modport master (
input clk, rst,
output awaddr,awlen,awsize,awburst,awlock,awcache,awprot,awqos,awvalid,
wdata,wstrb,wlast,wvalid,
bready,
araddr,arlen,arsize,arburst,arlock,arcache,arprot,arqos,arvalid,
rready,
input awready,wready,bresp,bvalid,arready,rdata,rresp,rlast,rvalid,
import drive_aw,
import drive_w,
import drive_w_idle,
import drive_aw_idle,
import drive_read,
import drive_read_idle
);
// View from the slave side
modport slave (
input clk, rst,
input awaddr,awlen,awsize,awburst,awlock,awcache,awprot,awqos,awvalid,
wdata,wstrb,wlast,wvalid,
bready,
araddr,arlen,arsize,arburst,arlock,arcache,arprot,arqos,arvalid,
rready,
output awready,wready,bresp,bvalid,arready,rdata,rresp,rlast,rvalid,
import drive_write_resp,
import drive_write_resp_idle,
import drive_read_resp,
import drive_read_resp_idle
);
endinterface : AxiIf
// The _v version of the interface does not assign any signals so it may be used
// in a continuous context. The most common example is when associating members
// to a regular verilog output port.
interface AxiIf_v #(
int DATA_WIDTH = 64,
int ADDR_WIDTH = 1
) (
input logic clk,
input logic rst = 1'b0
);
import PkgAxi::*;
localparam BYTES_PER_WORD = DATA_WIDTH/8;
// local type defs
typedef logic [DATA_WIDTH-1:0] data_t;
typedef logic [ADDR_WIDTH-1:0] addr_t;
typedef logic [BYTES_PER_WORD-1:0] strb_t;
typedef logic [7:0] len_t;
typedef logic [2:0] size_t;
typedef logic [1:0] burst_t;
typedef logic [0:0] lock_t;
typedef logic [3:0] cache_t;
typedef logic [2:0] prot_t;
typedef logic [3:0] qos_t;
// Signals that make up an Axi interface
// Write Address Channel
addr_t awaddr;
len_t awlen;
size_t awsize;
burst_t awburst;
lock_t awlock;
cache_t awcache;
prot_t awprot;
qos_t awqos;
logic awvalid;
logic awready;
// Write Data Channel
data_t wdata;
strb_t wstrb;
logic wlast;
logic wvalid;
logic wready;
// Write Response Channel
axi_resp_t bresp;
logic bvalid;
logic bready;
// Read Address Channel
addr_t araddr;
len_t arlen;
size_t arsize;
burst_t arburst;
lock_t arlock;
cache_t arcache;
prot_t arprot;
qos_t arqos;
logic arvalid;
logic arready;
// Read Data Channel
data_t rdata;
axi_resp_t rresp;
logic rlast;
logic rvalid;
logic rready;
// View from the master side
modport master (
input clk, rst,
output awaddr,awlen,awsize,awburst,awlock,awcache,awprot,awqos,awvalid,
wdata,wstrb,wlast,wvalid,
bready,
araddr,arlen,arsize,arburst,arlock,arcache,arprot,arqos,arvalid,
rready,
input awready,wready,bresp,bvalid,arready,rdata,rresp,rlast,rvalid
);
// View from the slave side
modport slave (
input clk, rst,
input awaddr,awlen,awsize,awburst,awlock,awcache,awprot,awqos,awvalid,
wdata,wstrb,wlast,wvalid,
bready,
araddr,arlen,arsize,arburst,arlock,arcache,arprot,arqos,arvalid,
rready,
output awready,wready,bresp,bvalid,arready,rdata,rresp,rlast,rvalid
);
endinterface : AxiIf_v
+13
View File
@@ -0,0 +1,13 @@
#
# Copyright 2021 Ettus Research, A National Instruments Brand
#
# SPDX-License-Identifier: LGPL-3.0-or-later
#
##################################################
# RFNoC Utility Sources
##################################################
AXI4_SV_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/axi4_sv/, \
PkgAxi.sv \
AxiIf.sv \
))
+30
View File
@@ -0,0 +1,30 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Package: PkgAxi
// Description:
// AXI4 is an ARM standard for memory mapped burst transfers
// For more information on the spec see
// - https://developer.arm.com/docs/ihi0022/d
//
// This package contains types used for AxiIf.
//
//-----------------------------------------------------------------------------
// AXI4 Package
//-----------------------------------------------------------------------------
package PkgAxi;
typedef enum logic [1:0] {OKAY=0,SLVERR=2,DECERR=3} axi_resp_t;
// Len - Burst Length = LEN+1
// Size - Bytes in transfer = 2**SIZE
typedef enum logic [1:0] {FIXED=0,INCR=1,WRAP=2} axi_burst_t;
// Cache - just see the docs. (too tangled!)
// Prot[0] - Privleged
// Prot[1] - Secure
// Prot[2] - 0=Data / 1=Instruction
// QOS - 0 = no protocol - Others not specified in spec
endpackage : PkgAxi
+247
View File
@@ -0,0 +1,247 @@
//
// Copyright 2021 Ettus Research, A National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Header File: AxiIf.vh
// Description: Macros for use with AXI4(FULL)
//
//-----------------------------------------------------------------------------
// AXI4 (FULL)
//-----------------------------------------------------------------------------
//
// Difference between AXILITE and AXI(FULL)
// Address channels contain
// LEN, SIZE, BURST, LOCK, CACHE, PROT, QOS
// Data Channels contain
// LAST
// Macro that drives o from i for all fields. Of course ready runs in the
// counter direction.
`define AXI4_ASSIGN(O,I) \
/* write address channel */\
``O.awaddr = ``I.awaddr;\
``O.awlen = ``I.awlen;\
``O.awsize = ``I.awsize;\
``O.awburst = ``I.awburst;\
``O.awlock = ``I.awlock;\
``O.awcache = ``I.awcache;\
``O.awprot = ``I.awprot;\
``O.awqos = ``I.awqos;\
``O.awvalid = ``I.awvalid;\
``I.awready = ``O.awready;\
/* write data channel */\
``O.wdata = ``I.wdata;\
``O.wstrb = ``I.wstrb;\
``O.wlast = ``I.wlast;\
``O.wvalid = ``I.wvalid;\
``I.wready = ``O.wready;\
/* write resp channel */\
``I.bresp = ``O.bresp;\
``I.bvalid = ``O.bvalid;\
``O.bready = ``I.bready;\
/* read address channel */\
``O.araddr = ``I.araddr;\
``O.arlen = ``I.arlen;\
``O.arsize = ``I.arsize;\
``O.arburst = ``I.arburst;\
``O.arlock = ``I.arlock;\
``O.arcache = ``I.arcache;\
``O.arprot = ``I.arprot;\
``O.arqos = ``I.arqos;\
``O.arvalid = ``I.arvalid;\
``I.arready = ``O.arready;\
/* read resp channel */\
``I.rdata = ``O.rdata;\
``I.rresp = ``O.rresp;\
``I.rlast = ``O.rlast;\
``I.rvalid = ``O.rvalid;\
``O.rready = ``I.rready;
`define AXI4_PORT_ASSIGN(FORMAL,ACTUAL) \
.``FORMAL``_aclk(``ACTUAL``.clk),\
.``FORMAL``_sreset(``ACTUAL``.rst),\
.``FORMAL``_araddr(``ACTUAL``.araddr),\
.``FORMAL``_arlen(``ACTUAL``.arlen),\
.``FORMAL``_arsize(``ACTUAL``.arsize),\
.``FORMAL``_arburst(``ACTUAL``.arburst),\
.``FORMAL``_arlock(``ACTUAL``.arlock),\
.``FORMAL``_arcache(``ACTUAL``.arcache),\
.``FORMAL``_arprot(``ACTUAL``.arprot),\
.``FORMAL``_arqos(``ACTUAL``.arqos),\
.``FORMAL``_arready(``ACTUAL``.arready),\
.``FORMAL``_arvalid(``ACTUAL``.arvalid),\
.``FORMAL``_awaddr(``ACTUAL``.awaddr),\
.``FORMAL``_awlen(``ACTUAL``.awlen),\
.``FORMAL``_awsize(``ACTUAL``.awsize),\
.``FORMAL``_awburst(``ACTUAL``.awburst),\
.``FORMAL``_awlock(``ACTUAL``.awlock),\
.``FORMAL``_awcache(``ACTUAL``.awcache),\
.``FORMAL``_awprot(``ACTUAL``.awprot),\
.``FORMAL``_awqos(``ACTUAL``.awqos),\
.``FORMAL``_awready(``ACTUAL``.awready),\
.``FORMAL``_awvalid(``ACTUAL``.awvalid),\
.``FORMAL``_bready(``ACTUAL``.bready),\
.``FORMAL``_bresp(``ACTUAL``.bresp[1:0]),\
.``FORMAL``_bvalid(``ACTUAL``.bvalid),\
.``FORMAL``_rdata(``ACTUAL``.rdata),\
.``FORMAL``_rready(``ACTUAL``.rready),\
.``FORMAL``_rresp(``ACTUAL``.rresp[1:0]),\
.``FORMAL``_rlast(``ACTUAL``.rlast),\
.``FORMAL``_rvalid(``ACTUAL``.rvalid),\
.``FORMAL``_wdata(``ACTUAL``.wdata),\
.``FORMAL``_wready(``ACTUAL``.wready),\
.``FORMAL``_wstrb(``ACTUAL``.wstrb),\
.``FORMAL``_wlast(``ACTUAL``.wlast),\
.``FORMAL``_wvalid(``ACTUAL``.wvalid),
`define AXI4_PORT_ASSIGN_NR(FORMAL,ACTUAL) \
.``FORMAL``_araddr(``ACTUAL``.araddr),\
.``FORMAL``_arlen(``ACTUAL``.arlen),\
.``FORMAL``_arsize(``ACTUAL``.arsize),\
.``FORMAL``_arburst(``ACTUAL``.arburst),\
.``FORMAL``_arlock(``ACTUAL``.arlock),\
.``FORMAL``_arcache(``ACTUAL``.arcache),\
.``FORMAL``_arprot(``ACTUAL``.arprot),\
.``FORMAL``_arqos(``ACTUAL``.arqos),\
.``FORMAL``_arready(``ACTUAL``.arready),\
.``FORMAL``_arvalid(``ACTUAL``.arvalid),\
.``FORMAL``_awaddr(``ACTUAL``.awaddr),\
.``FORMAL``_awlen(``ACTUAL``.awlen),\
.``FORMAL``_awsize(``ACTUAL``.awsize),\
.``FORMAL``_awburst(``ACTUAL``.awburst),\
.``FORMAL``_awlock(``ACTUAL``.awlock),\
.``FORMAL``_awcache(``ACTUAL``.awcache),\
.``FORMAL``_awprot(``ACTUAL``.awprot),\
.``FORMAL``_awqos(``ACTUAL``.awqos),\
.``FORMAL``_awready(``ACTUAL``.awready),\
.``FORMAL``_awvalid(``ACTUAL``.awvalid),\
.``FORMAL``_bready(``ACTUAL``.bready),\
.``FORMAL``_bresp(``ACTUAL``.bresp[1:0]),\
.``FORMAL``_bvalid(``ACTUAL``.bvalid),\
.``FORMAL``_rdata(``ACTUAL``.rdata),\
.``FORMAL``_rready(``ACTUAL``.rready),\
.``FORMAL``_rresp(``ACTUAL``.rresp[1:0]),\
.``FORMAL``_rlast(``ACTUAL``.rlast),\
.``FORMAL``_rvalid(``ACTUAL``.rvalid),\
.``FORMAL``_wdata(``ACTUAL``.wdata),\
.``FORMAL``_wready(``ACTUAL``.wready),\
.``FORMAL``_wstrb(``ACTUAL``.wstrb),\
.``FORMAL``_wlast(``ACTUAL``.wlast),\
.``FORMAL``_wvalid(``ACTUAL``.wvalid),
`define AXI4_DEBUG_ASSIGN(O,I) \
(* mark_debug = "true" *) logic [``I.ADDR_WIDTH-1:0] ``I``_debug_awaddr;\
(* mark_debug = "true" *) logic [7:0] ``I``_debug_awlen;\
(* mark_debug = "true" *) logic [2:0] ``I``_debug_awsize;\
(* mark_debug = "true" *) logic [1:0] ``I``_debug_awburst;\
(* mark_debug = "true" *) logic [0:0] ``I``_debug_awlock;\
(* mark_debug = "true" *) logic [3:0] ``I``_debug_awcache;\
(* mark_debug = "true" *) logic [2:0] ``I``_debug_awprot;\
(* mark_debug = "true" *) logic [3:0] ``I``_debug_awqos;\
(* mark_debug = "true" *) logic ``I``_debug_awvalid;\
(* mark_debug = "true" *) logic ``I``_debug_awready;\
(* mark_debug = "true" *) logic [``I.DATA_WIDTH-1:0] ``I``_debug_wdata;\
(* mark_debug = "true" *) logic [``I.BYTES_PER_WORD-1:0] ``I``_debug_wstrb;\
(* mark_debug = "true" *) logic ``I``_debug_wlast;\
(* mark_debug = "true" *) logic ``I``_debug_wvalid;\
(* mark_debug = "true" *) logic ``I``_debug_wready;\
(* mark_debug = "true" *) logic [1:0] ``I``_debug_bresp;\
(* mark_debug = "true" *) logic ``I``_debug_bvalid;\
(* mark_debug = "true" *) logic ``I``_debug_bready;\
(* mark_debug = "true" *) logic [``I.ADDR_WIDTH-1:0] ``I``_debug_araddr;\
(* mark_debug = "true" *) logic [7:0] ``I``_debug_arlen;\
(* mark_debug = "true" *) logic [2:0] ``I``_debug_arsize;\
(* mark_debug = "true" *) logic [1:0] ``I``_debug_arburst;\
(* mark_debug = "true" *) logic [0:0] ``I``_debug_arlock;\
(* mark_debug = "true" *) logic [3:0] ``I``_debug_arcache;\
(* mark_debug = "true" *) logic [2:0] ``I``_debug_arprot;\
(* mark_debug = "true" *) logic [3:0] ``I``_debug_arqos;\
(* mark_debug = "true" *) logic ``I``_debug_arvalid;\
(* mark_debug = "true" *) logic ``I``_debug_arready;\
(* mark_debug = "true" *) logic [``I.DATA_WIDTH-1:0] ``I``_debug_rdata;\
(* mark_debug = "true" *) logic [1:0] ``I``_debug_rresp;\
(* mark_debug = "true" *) logic ``I``_debug_rlast;\
(* mark_debug = "true" *) logic ``I``_debug_rvalid;\
(* mark_debug = "true" *) logic ``I``_debug_rready;\
always_comb begin\
/* write address channel */\
``I``_debug_awaddr = ``I.awaddr;\
``I``_debug_awlen = ``I.awlen;\
``I``_debug_awsize = ``I.awsize;\
``I``_debug_awburst = ``I.awburst;\
``I``_debug_awlock = ``I.awlock;\
``I``_debug_awcache = ``I.awcache;\
``I``_debug_awprot = ``I.awprot;\
``I``_debug_awqos = ``I.awqos;\
``I``_debug_awvalid = ``I.awvalid;\
``I.awready = ``I``_debug_awready;\
/* write data channel */\
``I``_debug_wdata = ``I.wdata;\
``I``_debug_wstrb = ``I.wstrb;\
``I``_debug_wlast = ``I.wlast;\
``I``_debug_wvalid = ``I.wvalid;\
``I.wready = ``I``_debug_wready;\
/* write resp channel */\
``I.bresp = ``I``_debug_bresp;\
``I.bvalid = ``I``_debug_bvalid;\
``I``_debug_bready = ``I.bready;\
/* read address channel */\
``I``_debug_araddr = ``I.araddr;\
``I``_debug_arlen = ``I.arlen;\
``I``_debug_arsize = ``I.arsize;\
``I``_debug_arburst = ``I.arburst;\
``I``_debug_arlock = ``I.arlock;\
``I``_debug_arcache = ``I.arcache;\
``I``_debug_arprot = ``I.arprot;\
``I``_debug_arqos = ``I.arqos;\
``I``_debug_arvalid = ``I.arvalid;\
``I.arready = ``I``_debug_arready;\
/* read resp channel */\
``I.rdata = ``I``_debug_rdata;\
``I.rresp = ``I``_debug_rresp;\
``I.rlast = ``I``_debug_rlast;\
``I.rvalid = ``I``_debug_rvalid;\
``I``_debug_rready = ``I.rready;\
end\
always_comb begin\
/* write address channel */\
``O.awaddr = ``I``_debug_awaddr;\
``O.awlen = ``I``_debug_awlen;\
``O.awsize = ``I``_debug_awsize;\
``O.awburst = ``I``_debug_awburst;\
``O.awlock = ``I``_debug_awlock;\
``O.awcache = ``I``_debug_awcache;\
``O.awprot = ``I``_debug_awprot;\
``O.awqos = ``I``_debug_awqos;\
``O.awvalid = ``I``_debug_awvalid;\
``I``_debug_awready = ``O.awready;\
/* write data channel */\
``O.wdata = ``I``_debug_wdata;\
``O.wstrb = ``I``_debug_wstrb;\
``O.wlast = ``I``_debug_wlast;\
``O.wvalid = ``I``_debug_wvalid;\
``I``_debug_wready = ``O.wready;\
/* write resp channel */\
``I``_debug_bresp = ``O.bresp;\
``I``_debug_bvalid = ``O.bvalid;\
``O.bready = ``I``_debug_bready;\
/* read address channel */\
``O.araddr = ``I``_debug_araddr;\
``O.arlen = ``I``_debug_arlen;\
``O.arsize = ``I``_debug_arsize;\
``O.arburst = ``I``_debug_arburst;\
``O.arlock = ``I``_debug_arlock;\
``O.arcache = ``I``_debug_arcache;\
``O.arprot = ``I``_debug_arprot;\
``O.arqos = ``I``_debug_arqos;\
``O.arvalid = ``I``_debug_arvalid;\
``I``_debug_arready = ``O.arready;\
/* read resp channel */\
``I``_debug_rdata = ``O.rdata;\
``I``_debug_rresp = ``O.rresp;\
``I``_debug_rvlast = ``O.rlast;\
``I``_debug_rvalid = ``O.rvalid;\
``O.rready = ``I``_debug_rready;\
end