summaryrefslogtreecommitdiff
path: root/rtl/wb2axip/demofull.v
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
committerAlejandro Soto <alejandro@34project.org>2024-03-06 02:38:24 -0600
commit3038edc09a2eb15762f2e58533f429489107520b (patch)
treef7a45e424d39e6fef0d59e329c1bf6ea206e2886 /rtl/wb2axip/demofull.v
parent3b62399f92e9faa2602ac30865e5fc3c7c4e12b8 (diff)
rtl/wb2axip: add to version control
Diffstat (limited to 'rtl/wb2axip/demofull.v')
-rw-r--r--rtl/wb2axip/demofull.v1285
1 files changed, 1285 insertions, 0 deletions
diff --git a/rtl/wb2axip/demofull.v b/rtl/wb2axip/demofull.v
new file mode 100644
index 0000000..5d0c604
--- /dev/null
+++ b/rtl/wb2axip/demofull.v
@@ -0,0 +1,1285 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// Filename: demofull.v
+// {{{
+// Project: WB2AXIPSP: bus bridges and other odds and ends
+//
+// Purpose: Demonstrate a formally verified AXI4 core with a (basic)
+// interface. This interface is explained below.
+//
+// Performance: This core has been designed for a total throughput of one beat
+// per clock cycle. Both read and write channels can achieve
+// this. The write channel will also introduce two clocks of latency,
+// assuming no other latency from the master. This means it will take
+// a minimum of 3+AWLEN clock cycles per transaction of (1+AWLEN) beats,
+// including both address and acknowledgment cycles. The read channel
+// will introduce a single clock of latency, requiring 2+ARLEN cycles
+// per transaction of 1+ARLEN beats.
+//
+// Creator: Dan Gisselquist, Ph.D.
+// Gisselquist Technology, LLC
+//
+////////////////////////////////////////////////////////////////////////////////
+// }}}
+// Copyright (C) 2019-2024, Gisselquist Technology, LLC
+// {{{
+// This file is part of the WB2AXIP project.
+//
+// The WB2AXIP project contains free software and gateware, licensed under the
+// Apache License, Version 2.0 (the "License"). You may not use this project,
+// or this file, except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations
+// under the License.
+//
+////////////////////////////////////////////////////////////////////////////////
+//
+`default_nettype none
+// }}}
+module demofull #(
+ // {{{
+ parameter integer C_S_AXI_ID_WIDTH = 2,
+ parameter integer C_S_AXI_DATA_WIDTH = 32,
+ parameter integer C_S_AXI_ADDR_WIDTH = 6,
+ parameter [0:0] OPT_LOCK = 1'b0,
+ parameter [0:0] OPT_LOCKID = 1'b1,
+ parameter [0:0] OPT_LOWPOWER = 1'b0,
+ // Some useful short-hand definitions
+ localparam LSB = $clog2(C_S_AXI_DATA_WIDTH)-3
+ // }}}
+ ) (
+ // {{{
+ // User ports
+ // {{{
+ // A very basic protocol-independent peripheral interface
+ // 1. A value will be written any time o_we is true
+ // 2. A value will be read any time o_rd is true
+ // 3. Such a slave might just as easily be written as:
+ //
+ // always @(posedge S_AXI_ACLK)
+ // if (o_we)
+ // begin
+ // for(k=0; k<C_S_AXI_DATA_WIDTH/8; k=k+1)
+ // begin
+ // if (o_wstrb[k])
+ // mem[o_waddr[AW-1:LSB]][k*8+:8] <= o_wdata[k*8+:8]
+ // end
+ // end
+ //
+ // always @(posedge S_AXI_ACLK)
+ // if (o_rd)
+ // i_rdata <= mem[o_raddr[AW-1:LSB]];
+ //
+ // 4. The rule on the input is that i_rdata must be registered,
+ // and that it must only change if o_rd is true. Violating
+ // this rule will cause this core to violate the AXI
+ // protocol standard, as this value is not registered within
+ // this core
+ output reg o_we,
+ output reg [C_S_AXI_ADDR_WIDTH-LSB-1:0] o_waddr,
+ output reg [C_S_AXI_DATA_WIDTH-1:0] o_wdata,
+ output reg [C_S_AXI_DATA_WIDTH/8-1:0] o_wstrb,
+ //
+ output reg o_rd,
+ output reg [C_S_AXI_ADDR_WIDTH-LSB-1:0] o_raddr,
+ input wire [C_S_AXI_DATA_WIDTH-1:0] i_rdata,
+ //
+ // User ports ends
+ // }}}
+ // Do not modify the ports beyond this line
+ // AXI signals
+ // {{{
+ // Global Clock Signal
+ input wire S_AXI_ACLK,
+ // Global Reset Signal. This Signal is Active LOW
+ input wire S_AXI_ARESETN,
+
+ // Write address channel
+ // {{{
+ // Write Address ID
+ input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_AWID,
+ // Write address
+ input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_AWADDR,
+ // Burst length. The burst length gives the exact number of
+ // transfers in a burst
+ input wire [7 : 0] S_AXI_AWLEN,
+ // Burst size. This signal indicates the size of each transfer
+ // in the burst
+ input wire [2 : 0] S_AXI_AWSIZE,
+ // Burst type. The burst type and the size information,
+ // determine how the address for each transfer within the burst
+ // is calculated.
+ input wire [1 : 0] S_AXI_AWBURST,
+ // Lock type. Provides additional information about the
+ // atomic characteristics of the transfer.
+ input wire S_AXI_AWLOCK,
+ // Memory type. This signal indicates how transactions
+ // are required to progress through a system.
+ input wire [3 : 0] S_AXI_AWCACHE,
+ // Protection type. This signal indicates the privilege
+ // and security level of the transaction, and whether
+ // the transaction is a data access or an instruction access.
+ input wire [2 : 0] S_AXI_AWPROT,
+ // Quality of Service, QoS identifier sent for each
+ // write transaction.
+ input wire [3 : 0] S_AXI_AWQOS,
+ // Region identifier. Permits a single physical interface
+ // on a slave to be used for multiple logical interfaces.
+ // Write address valid. This signal indicates that
+ // the channel is signaling valid write address and
+ // control information.
+ input wire S_AXI_AWVALID,
+ // Write address ready. This signal indicates that
+ // the slave is ready to accept an address and associated
+ // control signals.
+ output wire S_AXI_AWREADY,
+ // }}}
+ // Write data channel
+ // {{{
+ // Write Data
+ input wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_WDATA,
+ // Write strobes. This signal indicates which byte
+ // lanes hold valid data. There is one write strobe
+ // bit for each eight bits of the write data bus.
+ input wire [(C_S_AXI_DATA_WIDTH/8)-1 : 0] S_AXI_WSTRB,
+ // Write last. This signal indicates the last transfer
+ // in a write burst.
+ input wire S_AXI_WLAST,
+ // Optional User-defined signal in the write data channel.
+ // Write valid. This signal indicates that valid write
+ // data and strobes are available.
+ input wire S_AXI_WVALID,
+ // Write ready. This signal indicates that the slave
+ // can accept the write data.
+ output wire S_AXI_WREADY,
+ // }}}
+ // Write response channel
+ // {{{
+ // Response ID tag. This signal is the ID tag of the
+ // write response.
+ output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_BID,
+ // Write response. This signal indicates the status
+ // of the write transaction.
+ output wire [1 : 0] S_AXI_BRESP,
+ // Optional User-defined signal in the write response channel.
+ // Write response valid. This signal indicates that the
+ // channel is signaling a valid write response.
+ output wire S_AXI_BVALID,
+ // Response ready. This signal indicates that the master
+ // can accept a write response.
+ input wire S_AXI_BREADY,
+ // }}}
+ // Read address channel
+ // {{{
+ // Read address ID. This signal is the identification
+ // tag for the read address group of signals.
+ input wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_ARID,
+ // Read address. This signal indicates the initial
+ // address of a read burst transaction.
+ input wire [C_S_AXI_ADDR_WIDTH-1 : 0] S_AXI_ARADDR,
+ // Burst length. The burst length gives the exact number of
+ // transfers in a burst
+ input wire [7 : 0] S_AXI_ARLEN,
+ // Burst size. This signal indicates the size of each transfer
+ // in the burst
+ input wire [2 : 0] S_AXI_ARSIZE,
+ // Burst type. The burst type and the size information,
+ // determine how the address for each transfer within the
+ // burst is calculated.
+ input wire [1 : 0] S_AXI_ARBURST,
+ // Lock type. Provides additional information about the
+ // atomic characteristics of the transfer.
+ input wire S_AXI_ARLOCK,
+ // Memory type. This signal indicates how transactions
+ // are required to progress through a system.
+ input wire [3 : 0] S_AXI_ARCACHE,
+ // Protection type. This signal indicates the privilege
+ // and security level of the transaction, and whether
+ // the transaction is a data access or an instruction access.
+ input wire [2 : 0] S_AXI_ARPROT,
+ // Quality of Service, QoS identifier sent for each
+ // read transaction.
+ input wire [3 : 0] S_AXI_ARQOS,
+ // Region identifier. Permits a single physical interface
+ // on a slave to be used for multiple logical interfaces.
+ // Optional User-defined signal in the read address channel.
+ // Write address valid. This signal indicates that
+ // the channel is signaling valid read address and
+ // control information.
+ input wire S_AXI_ARVALID,
+ // Read address ready. This signal indicates that
+ // the slave is ready to accept an address and associated
+ // control signals.
+ output wire S_AXI_ARREADY,
+ // }}}
+ // Read data (return) channel
+ // {{{
+ // Read ID tag. This signal is the identification tag
+ // for the read data group of signals generated by the slave.
+ output wire [C_S_AXI_ID_WIDTH-1 : 0] S_AXI_RID,
+ // Read Data
+ output wire [C_S_AXI_DATA_WIDTH-1 : 0] S_AXI_RDATA,
+ // Read response. This signal indicates the status of
+ // the read transfer.
+ output wire [1 : 0] S_AXI_RRESP,
+ // Read last. This signal indicates the last transfer
+ // in a read burst.
+ output wire S_AXI_RLAST,
+ // Optional User-defined signal in the read address channel.
+ // Read valid. This signal indicates that the channel
+ // is signaling the required read data.
+ output wire S_AXI_RVALID,
+ // Read ready. This signal indicates that the master can
+ // accept the read data and response information.
+ input wire S_AXI_RREADY
+ // }}}
+ // }}}
+ // }}}
+ );
+
+ // Local declarations
+ // {{{
+ // More useful shorthand definitions
+ localparam AW = C_S_AXI_ADDR_WIDTH;
+ localparam DW = C_S_AXI_DATA_WIDTH;
+ localparam IW = C_S_AXI_ID_WIDTH;
+ // Double buffer the write response channel only
+ reg [IW-1 : 0] r_bid;
+ reg r_bvalid;
+ reg [IW-1 : 0] axi_bid;
+ reg axi_bvalid;
+
+ reg axi_awready, axi_wready;
+ reg [AW-1:0] waddr;
+ wire [AW-1:0] next_wr_addr;
+
+ // Vivado will warn about wlen only using 4-bits. This is
+ // to be expected, since the axi_addr module only needs to use
+ // the bottom four bits of wlen to determine address increments
+ reg [7:0] wlen;
+ // Vivado will also warn about the top bit of wsize being unused.
+ // This is also to be expected for a DATA_WIDTH of 32-bits.
+ reg [2:0] wsize;
+ reg [1:0] wburst;
+
+ wire m_awvalid, m_awlock;
+ reg m_awready;
+ wire [AW-1:0] m_awaddr;
+ wire [1:0] m_awburst;
+ wire [2:0] m_awsize;
+ wire [7:0] m_awlen;
+ wire [IW-1:0] m_awid;
+
+ wire [AW-1:0] next_rd_addr;
+
+ // Vivado will warn about rlen only using 4-bits. This is
+ // to be expected, since for a DATA_WIDTH of 32-bits, the axi_addr
+ // module only uses the bottom four bits of rlen to determine
+ // address increments
+ reg [7:0] rlen;
+ // Vivado will also warn about the top bit of wsize being unused.
+ // This is also to be expected for a DATA_WIDTH of 32-bits.
+ reg [2:0] rsize;
+ reg [1:0] rburst;
+ reg [IW-1:0] rid;
+ reg rlock;
+ reg axi_arready;
+ reg [8:0] axi_rlen;
+ reg [AW-1:0] raddr;
+
+ // Read skid buffer
+ reg rskd_valid, rskd_last, rskd_lock;
+ wire rskd_ready;
+ reg [IW-1:0] rskd_id;
+
+ // Exclusive address register checking
+ reg exclusive_write, block_write;
+ wire write_lock_valid;
+ reg axi_exclusive_write;
+
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AW Skid buffer
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ skidbuffer #(
+ // {{{
+ .DW(AW+2+3+1+8+IW),
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_OUTREG(1'b0)
+ // }}}
+ ) awbuf(
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(S_AXI_AWVALID), .o_ready(S_AXI_AWREADY),
+ .i_data({ S_AXI_AWADDR, S_AXI_AWBURST, S_AXI_AWSIZE,
+ S_AXI_AWLOCK, S_AXI_AWLEN, S_AXI_AWID }),
+ .o_valid(m_awvalid), .i_ready(m_awready),
+ .o_data({ m_awaddr, m_awburst, m_awsize,
+ m_awlock, m_awlen, m_awid })
+ // }}}
+ );
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Write processing
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // axi_awready, axi_wready
+ // {{{
+ initial axi_awready = 1;
+ initial axi_wready = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ begin
+ axi_awready <= 1;
+ axi_wready <= 0;
+ end else if (m_awvalid && m_awready)
+ begin
+ axi_awready <= 0;
+ axi_wready <= 1;
+ end else if (S_AXI_WVALID && S_AXI_WREADY)
+ begin
+ axi_awready <= (S_AXI_WLAST)&&(!S_AXI_BVALID || S_AXI_BREADY);
+ axi_wready <= (!S_AXI_WLAST);
+ end else if (!axi_awready)
+ begin
+ if (S_AXI_WREADY)
+ axi_awready <= 1'b0;
+ else if (r_bvalid && !S_AXI_BREADY)
+ axi_awready <= 1'b0;
+ else
+ axi_awready <= 1'b1;
+ end
+ // }}}
+
+ // Exclusive write calculation
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !OPT_LOCK)
+ begin
+ exclusive_write <= 0;
+ block_write <= 0;
+ end else if (m_awvalid && m_awready)
+ begin
+ exclusive_write <= 1'b0;
+ block_write <= 1'b0;
+ if (write_lock_valid)
+ exclusive_write <= 1'b1;
+ else if (m_awlock)
+ block_write <= 1'b1;
+ end else if (m_awready)
+ begin
+ exclusive_write <= 1'b0;
+ block_write <= 1'b0;
+ end
+
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !OPT_LOCK)
+ axi_exclusive_write <= 0;
+ else if (!S_AXI_BVALID || S_AXI_BREADY)
+ begin
+ axi_exclusive_write <= exclusive_write;
+ if (OPT_LOWPOWER && (!S_AXI_WVALID || !S_AXI_WREADY || !S_AXI_WLAST)
+ && !r_bvalid)
+ axi_exclusive_write <= 0;
+ end
+ // }}}
+
+ // Next write address calculation
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (m_awready)
+ begin
+ waddr <= m_awaddr;
+ wburst <= m_awburst;
+ wsize <= m_awsize;
+ wlen <= m_awlen;
+ end else if (S_AXI_WVALID)
+ waddr <= next_wr_addr;
+
+ axi_addr #(
+ // {{{
+ .AW(AW), .DW(DW)
+ // }}}
+ ) get_next_wr_addr(
+ // {{{
+ waddr, wsize, wburst, wlen,
+ next_wr_addr
+ // }}}
+ );
+ // }}}
+
+ // o_w*
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ begin
+ o_we <= (S_AXI_WVALID && S_AXI_WREADY);
+ o_waddr <= waddr[AW-1:LSB];
+ o_wdata <= S_AXI_WDATA;
+ if (block_write)
+ o_wstrb <= 0;
+ else
+ o_wstrb <= S_AXI_WSTRB;
+
+ if (!S_AXI_ARESETN)
+ o_we <= 0;
+ if (OPT_LOWPOWER && (!S_AXI_ARESETN || !S_AXI_WVALID
+ || !S_AXI_WREADY))
+ begin
+ o_waddr <= 0;
+ o_wdata <= 0;
+ o_wstrb <= 0;
+ end
+ end
+ // }}}
+
+ //
+ // Write return path
+ // {{{
+ // r_bvalid
+ // {{{
+ initial r_bvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ r_bvalid <= 1'b0;
+ else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST
+ &&(S_AXI_BVALID && !S_AXI_BREADY))
+ r_bvalid <= 1'b1;
+ else if (S_AXI_BREADY)
+ r_bvalid <= 1'b0;
+ // }}}
+
+ // r_bid, axi_bid
+ // {{{
+ initial r_bid = 0;
+ initial axi_bid = 0;
+ always @(posedge S_AXI_ACLK)
+ begin
+ if (m_awready && (!OPT_LOWPOWER || m_awvalid))
+ r_bid <= m_awid;
+
+ if (!S_AXI_BVALID || S_AXI_BREADY)
+ axi_bid <= r_bid;
+
+ if (OPT_LOWPOWER && !S_AXI_ARESETN)
+ begin
+ r_bid <= 0;
+ axi_bid <= 0;
+ end
+ end
+ // }}}
+
+ // axi_bvalid
+ // {{{
+ initial axi_bvalid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ axi_bvalid <= 0;
+ else if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST)
+ axi_bvalid <= 1;
+ else if (S_AXI_BREADY)
+ axi_bvalid <= r_bvalid;
+ // }}}
+
+ // m_awready
+ // {{{
+ always @(*)
+ begin
+ m_awready = axi_awready;
+ if (S_AXI_WVALID && S_AXI_WREADY && S_AXI_WLAST
+ && (!S_AXI_BVALID || S_AXI_BREADY))
+ m_awready = 1;
+ end
+ // }}}
+
+ // At one time, axi_awready was the same as S_AXI_AWREADY. Now, though,
+ // with the extra write address skid buffer, this is no longer the case.
+ // S_AXI_AWREADY is handled/created/managed by the skid buffer.
+ //
+ // assign S_AXI_AWREADY = axi_awready;
+ //
+ // The rest of these signals can be set according to their registered
+ // values above.
+ assign S_AXI_WREADY = axi_wready;
+ assign S_AXI_BVALID = axi_bvalid;
+ assign S_AXI_BID = axi_bid;
+ //
+ // This core does not produce any bus errors, nor does it support
+ // exclusive access, so 2'b00 will always be the correct response.
+ assign S_AXI_BRESP = { 1'b0, axi_exclusive_write };
+ // }}}
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Read processing
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // axi_arready
+ // {{{
+ initial axi_arready = 1;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ axi_arready <= 1;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY)
+ axi_arready <= (S_AXI_ARLEN==0)&&(o_rd);
+ else if (o_rd)
+ axi_arready <= (axi_rlen <= 1);
+ // }}}
+
+ // axi_rlen
+ // {{{
+ initial axi_rlen = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ axi_rlen <= 0;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY)
+ axi_rlen <= S_AXI_ARLEN + (o_rd ? 0:1);
+ else if (o_rd)
+ axi_rlen <= axi_rlen - 1;
+ // }}}
+
+ // Next read address calculation
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (o_rd)
+ raddr <= next_rd_addr;
+ else if (S_AXI_ARREADY)
+ begin
+ raddr <= S_AXI_ARADDR;
+ if (OPT_LOWPOWER && !S_AXI_ARVALID)
+ raddr <= 0;
+ end
+
+ // r*
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (S_AXI_ARREADY)
+ begin
+ rburst <= S_AXI_ARBURST;
+ rsize <= S_AXI_ARSIZE;
+ rlen <= S_AXI_ARLEN;
+ rid <= S_AXI_ARID;
+ rlock <= S_AXI_ARLOCK && S_AXI_ARVALID && OPT_LOCK;
+
+ if (OPT_LOWPOWER && !S_AXI_ARVALID)
+ begin
+ rburst <= 0;
+ rsize <= 0;
+ rlen <= 0;
+ rid <= 0;
+ rlock <= 0;
+ end
+ end
+ // }}}
+
+ axi_addr #(
+ // {{{
+ .AW(AW), .DW(DW)
+ // }}}
+ ) get_next_rd_addr(
+ // {{{
+ (S_AXI_ARREADY ? S_AXI_ARADDR : raddr),
+ (S_AXI_ARREADY ? S_AXI_ARSIZE : rsize),
+ (S_AXI_ARREADY ? S_AXI_ARBURST: rburst),
+ (S_AXI_ARREADY ? S_AXI_ARLEN : rlen),
+ next_rd_addr
+ // }}}
+ );
+ // }}}
+
+ // o_rd, o_raddr
+ // {{{
+ always @(*)
+ begin
+ o_rd = (S_AXI_ARVALID || !S_AXI_ARREADY);
+ if (S_AXI_RVALID && !S_AXI_RREADY)
+ o_rd = 0;
+ if (rskd_valid && !rskd_ready)
+ o_rd = 0;
+ o_raddr = (S_AXI_ARREADY ? S_AXI_ARADDR[AW-1:LSB] : raddr[AW-1:LSB]);
+ end
+ // }}}
+
+ // rskd_valid
+ // {{{
+ initial rskd_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ rskd_valid <= 0;
+ else if (o_rd)
+ rskd_valid <= 1;
+ else if (rskd_ready)
+ rskd_valid <= 0;
+ // }}}
+
+ // rskd_id
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!rskd_valid || rskd_ready)
+ begin
+ if (S_AXI_ARVALID && S_AXI_ARREADY)
+ rskd_id <= S_AXI_ARID;
+ else
+ rskd_id <= rid;
+ end
+ // }}}
+
+ // rskd_last
+ // {{{
+ initial rskd_last = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!rskd_valid || rskd_ready)
+ begin
+ rskd_last <= 0;
+ if (o_rd && axi_rlen == 1)
+ rskd_last <= 1;
+ if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 0)
+ rskd_last <= 1;
+ end
+ // }}}
+
+ // rskd_lock
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !OPT_LOCK)
+ rskd_lock <= 1'b0;
+ else if (!rskd_valid || rskd_ready)
+ begin
+ rskd_lock <= 0;
+ if (!OPT_LOWPOWER || o_rd)
+ begin
+ if (S_AXI_ARVALID && S_AXI_ARREADY)
+ rskd_lock <= S_AXI_ARLOCK;
+ else
+ rskd_lock <= rlock;
+ end
+ end
+ // }}}
+
+
+ // Outgoing read skidbuffer
+ // {{{
+ skidbuffer #(
+ // {{{
+ .OPT_LOWPOWER(OPT_LOWPOWER),
+ .OPT_OUTREG(1),
+ .DW(IW+2+DW)
+ // }}}
+ ) rskid (
+ // {{{
+ .i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN),
+ .i_valid(rskd_valid), .o_ready(rskd_ready),
+ .i_data({ rskd_id, rskd_lock, rskd_last, i_rdata }),
+ .o_valid(S_AXI_RVALID), .i_ready(S_AXI_RREADY),
+ .o_data({ S_AXI_RID, S_AXI_RRESP[0], S_AXI_RLAST,
+ S_AXI_RDATA })
+ // }}}
+ );
+ // }}}
+
+ assign S_AXI_RRESP[1] = 1'b0;
+ assign S_AXI_ARREADY = axi_arready;
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Exclusive address caching
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ generate if (OPT_LOCK && !OPT_LOCKID)
+ begin : EXCLUSIVE_ACCESS_BLOCK
+ // {{{
+ // The AXI4 specification requires that we check one address
+ // per ID. This isn't that. This algorithm checks one ID,
+ // whichever the last ID was. It's designed to be lighter on
+ // the logic requirements, and (unnoticably) not (fully) spec
+ // compliant. (The difference, if noticed at all, will be in
+ // performance when multiple masters try to perform an exclusive
+ // transaction at once.)
+
+ // Local declarations
+ // {{{
+ reg w_valid_lock_request, w_cancel_lock,
+ w_lock_request,
+ lock_valid, returned_lock_valid;
+ reg [AW-LSB-1:0] lock_start, lock_end;
+ reg [3:0] lock_len;
+ reg [1:0] lock_burst;
+ reg [2:0] lock_size;
+ reg [IW-1:0] lock_id;
+ reg w_write_lock_valid;
+ // }}}
+
+ // w_lock_request
+ // {{{
+ always @(*)
+ begin
+ w_lock_request = 0;
+ if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLOCK)
+ w_lock_request = 1;
+ end
+ // }}}
+
+ // w_valid_lock_request
+ // {{{
+ always @(*)
+ begin
+ w_valid_lock_request = 0;
+ if (w_lock_request)
+ w_valid_lock_request = 1;
+ if (o_we && o_waddr == S_AXI_ARADDR[AW-1:LSB])
+ w_valid_lock_request = 0;
+ end
+ // }}}
+
+ // returned_lock_valid
+ // {{{
+ initial returned_lock_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ returned_lock_valid <= 0;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY
+ && S_AXI_ARLOCK && S_AXI_ARID== lock_id)
+ returned_lock_valid <= 0;
+ else if (w_cancel_lock)
+ returned_lock_valid <= 0;
+ else if (rskd_valid && rskd_lock && rskd_ready)
+ returned_lock_valid <= lock_valid;
+ // }}}
+
+ // w_cancel_lock
+ // {{{
+ always @(*)
+ w_cancel_lock = (lock_valid && w_lock_request)
+ || (lock_valid && o_we
+ && o_waddr >= lock_start
+ && o_waddr <= lock_end
+ && o_wstrb != 0);
+ // }}}
+
+ // lock_valid
+ // {{{
+ initial lock_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !OPT_LOCK)
+ lock_valid <= 0;
+ else begin
+ if (S_AXI_ARVALID && S_AXI_ARREADY
+ && S_AXI_ARLOCK && S_AXI_ARID== lock_id)
+ lock_valid <= 0;
+ if (w_cancel_lock)
+ lock_valid <= 0;
+ if (w_valid_lock_request)
+ lock_valid <= 1;
+ end
+ // }}}
+
+ // lock_start, lock_end, lock_len, lock_size, lock_id
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (w_valid_lock_request)
+ begin
+ lock_start <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH-1:LSB];
+ lock_end <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH-1:LSB]
+ + ((S_AXI_ARBURST == 2'b00) ? 0 : S_AXI_ARLEN[3:0]);
+ lock_len <= S_AXI_ARLEN[3:0];
+ lock_burst <= S_AXI_ARBURST;
+ lock_size <= S_AXI_ARSIZE;
+ lock_id <= S_AXI_ARID;
+ end
+ // }}}
+
+ // w_write_lock_valid
+ // {{{
+ always @(*)
+ begin
+ w_write_lock_valid = returned_lock_valid;
+ if (!m_awvalid || !m_awready || !m_awlock || !lock_valid)
+ w_write_lock_valid = 0;
+ if (m_awaddr[C_S_AXI_ADDR_WIDTH-1:LSB] != lock_start)
+ w_write_lock_valid = 0;
+ if (m_awid != lock_id)
+ w_write_lock_valid = 0;
+ if (m_awlen[3:0] != lock_len) // MAX transfer size is 16 beats
+ w_write_lock_valid = 0;
+ if (m_awburst != 2'b01 && lock_len != 0)
+ w_write_lock_valid = 0;
+ if (m_awsize != lock_size)
+ w_write_lock_valid = 0;
+ end
+ // }}}
+
+ assign write_lock_valid = w_write_lock_valid;
+ // }}}
+ end else if (OPT_LOCK) // && OPT_LOCKID
+ begin : EXCLUSIVE_ACCESS_PER_ID
+ // {{{
+
+ genvar gk;
+ wire [(1<<IW)-1:0] write_lock_valid_per_id;
+
+ for(gk=0; gk<(1<<IW); gk=gk+1)
+ begin : PER_ID_LOGIC
+ // {{{
+ // Local declarations
+ // {{{
+ reg w_valid_lock_request,
+ w_cancel_lock,
+ lock_valid, returned_lock_valid;
+ reg [1:0] lock_burst;
+ reg [2:0] lock_size;
+ reg [3:0] lock_len;
+ reg [AW-LSB-1:0] lock_start, lock_end;
+ reg w_write_lock_valid;
+ // }}}
+
+ // valid_lock_request
+ // {{{
+ always @(*)
+ begin
+ w_valid_lock_request = 0;
+ if (S_AXI_ARVALID && S_AXI_ARREADY
+ && S_AXI_ARID == gk[IW-1:0]
+ && S_AXI_ARLOCK)
+ w_valid_lock_request = 1;
+ if (o_we && o_waddr == S_AXI_ARADDR[AW-1:LSB])
+ w_valid_lock_request = 0;
+ end
+ // }}}
+
+ // returned_lock_valid
+ // {{{
+ initial returned_lock_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ returned_lock_valid <= 0;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY
+ &&S_AXI_ARLOCK&&S_AXI_ARID== gk[IW-1:0])
+ returned_lock_valid <= 0;
+ else if (w_cancel_lock)
+ returned_lock_valid <= 0;
+ else if (rskd_valid && rskd_lock && rskd_ready
+ && rskd_id == gk[IW-1:0])
+ returned_lock_valid <= lock_valid;
+ // }}}
+
+ // w_cancel_lock
+ // {{{
+ always @(*)
+ w_cancel_lock=(lock_valid&&w_valid_lock_request)
+ || (lock_valid && o_we
+ && o_waddr >= lock_start
+ && o_waddr <= lock_end
+ && o_wstrb != 0);
+ // }}}
+
+ // lock_valid
+ // {{{
+ initial lock_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN || !OPT_LOCK)
+ lock_valid <= 0;
+ else begin
+ if (S_AXI_ARVALID && S_AXI_ARREADY
+ && S_AXI_ARLOCK
+ && S_AXI_ARID == gk[IW-1:0])
+ lock_valid <= 0;
+ if (w_cancel_lock)
+ lock_valid <= 0;
+ if (w_valid_lock_request)
+ lock_valid <= 1;
+ end
+ // }}}
+
+ // lock_start, lock_end, lock_len, lock_size
+ // {{{
+ always @(posedge S_AXI_ACLK)
+ if (w_valid_lock_request)
+ begin
+ lock_start <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH-1:LSB];
+ // Verilator lint_off WIDTH
+ lock_end <= S_AXI_ARADDR[C_S_AXI_ADDR_WIDTH-1:LSB]
+ + ((S_AXI_ARBURST == 2'b00) ? 4'h0 : S_AXI_ARLEN[3:0]);
+ // Verilator lint_on WIDTH
+ lock_len <= S_AXI_ARLEN[3:0];
+ lock_size <= S_AXI_ARSIZE;
+ lock_burst <= S_AXI_ARBURST;
+ end
+ // }}}
+
+ // w_write_lock_valid
+ // {{{
+ always @(*)
+ begin
+ w_write_lock_valid = returned_lock_valid;
+ if (!m_awvalid || !m_awready || !m_awlock || !lock_valid)
+ w_write_lock_valid = 0;
+ if (m_awaddr[C_S_AXI_ADDR_WIDTH-1:LSB] != lock_start)
+ w_write_lock_valid = 0;
+ if (m_awid[IW-1:0] != gk[IW-1:0])
+ w_write_lock_valid = 0;
+ if (m_awlen[3:0] != lock_len) // MAX transfer size is 16 beats
+ w_write_lock_valid = 0;
+ if (m_awburst != 2'b01 && lock_len != 0)
+ w_write_lock_valid = 0;
+ if (m_awsize != lock_size)
+ w_write_lock_valid = 0;
+ end
+ // }}}
+
+ assign write_lock_valid_per_id[gk]= w_write_lock_valid;
+ // }}}
+ end
+
+ assign write_lock_valid = |write_lock_valid_per_id;
+ // }}}
+ end else begin : NO_LOCKING
+ // {{{
+
+ assign write_lock_valid = 1'b0;
+ // Verilator lint_off UNUSED
+ wire unused_lock;
+ assign unused_lock = &{ 1'b0, S_AXI_ARLOCK, S_AXI_AWLOCK };
+ // Verilator lint_on UNUSED
+ // }}}
+ end endgenerate
+ // }}}
+
+ // Make Verilator happy
+ // {{{
+ // Verilator lint_off UNUSED
+ wire unused;
+ assign unused = &{ 1'b0, S_AXI_AWCACHE, S_AXI_AWPROT, S_AXI_AWQOS,
+ S_AXI_ARCACHE, S_AXI_ARPROT, S_AXI_ARQOS };
+ // Verilator lint_on UNUSED
+ // }}}
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+//
+// Formal properties
+// {{{
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+`ifdef FORMAL
+ //
+ // The following properties are only some of the properties used
+ // to verify this core
+ //
+ // Local (formal) register declarations
+ // {{{
+ reg f_past_valid;
+ initial f_past_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ f_past_valid <= 1;
+
+ always @(*)
+ if (!f_past_valid)
+ assume(!S_AXI_ARESETN);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // AXI slave properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ faxi_slave #(
+ // {{{
+ .C_AXI_ID_WIDTH(C_S_AXI_ID_WIDTH),
+ .C_AXI_DATA_WIDTH(C_S_AXI_DATA_WIDTH),
+ .C_AXI_ADDR_WIDTH(C_S_AXI_ADDR_WIDTH))
+ // ...
+ // }}}
+ f_slave(
+ // {{{
+ .i_clk(S_AXI_ACLK),
+ .i_axi_reset_n(S_AXI_ARESETN),
+ //
+ // Address write channel
+ // {{{
+ .i_axi_awvalid(m_awvalid),
+ .i_axi_awready(m_awready),
+ .i_axi_awid( m_awid),
+ .i_axi_awaddr( m_awaddr),
+ .i_axi_awlen( m_awlen),
+ .i_axi_awsize( m_awsize),
+ .i_axi_awburst(m_awburst),
+ .i_axi_awlock( m_awlock),
+ .i_axi_awcache(4'h0),
+ .i_axi_awprot( 3'h0),
+ .i_axi_awqos( 4'h0),
+ // }}}
+ // Write Data Channel
+ // {{{
+ // Write Data
+ .i_axi_wdata(S_AXI_WDATA),
+ .i_axi_wstrb(S_AXI_WSTRB),
+ .i_axi_wlast(S_AXI_WLAST),
+ .i_axi_wvalid(S_AXI_WVALID),
+ .i_axi_wready(S_AXI_WREADY),
+ // }}}
+ // Write response
+ // {{{
+ .i_axi_bvalid(S_AXI_BVALID),
+ .i_axi_bready(S_AXI_BREADY),
+ .i_axi_bid( S_AXI_BID),
+ .i_axi_bresp( S_AXI_BRESP),
+ // }}}
+ // Read address channel
+ // {{{
+ .i_axi_arvalid(S_AXI_ARVALID),
+ .i_axi_arready(S_AXI_ARREADY),
+ .i_axi_arid( S_AXI_ARID),
+ .i_axi_araddr( S_AXI_ARADDR),
+ .i_axi_arlen( S_AXI_ARLEN),
+ .i_axi_arsize( S_AXI_ARSIZE),
+ .i_axi_arburst(S_AXI_ARBURST),
+ .i_axi_arlock( S_AXI_ARLOCK),
+ .i_axi_arcache(S_AXI_ARCACHE),
+ .i_axi_arprot( S_AXI_ARPROT),
+ .i_axi_arqos( S_AXI_ARQOS),
+ // }}}
+ // Read data return channel
+ // {{{
+ .i_axi_rvalid(S_AXI_RVALID),
+ .i_axi_rready(S_AXI_RREADY),
+ .i_axi_rid(S_AXI_RID),
+ .i_axi_rdata(S_AXI_RDATA),
+ .i_axi_rresp(S_AXI_RRESP),
+ .i_axi_rlast(S_AXI_RLAST),
+ // }}}
+ //
+ // ...
+ // }}}
+ );
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Write induction properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+
+ //
+ // ...
+ //
+
+ always @(*)
+ if (r_bvalid)
+ assert(S_AXI_BVALID);
+
+ always @(*)
+ assert(axi_awready == (!S_AXI_WREADY&& !r_bvalid));
+
+ always @(*)
+ if (axi_awready)
+ assert(!S_AXI_WREADY);
+
+
+ //
+ // ...
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Read induction properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+
+ //
+ // ...
+ //
+
+
+ always @(posedge S_AXI_ACLK)
+ if (f_past_valid && axi_rlen == 0)
+ assert(S_AXI_ARREADY);
+
+ always @(posedge S_AXI_ACLK)
+ assert(axi_rlen <= 256);
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Lowpower checking
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ always @(*)
+ if (OPT_LOWPOWER && S_AXI_ARESETN)
+ begin
+ if (!rskd_valid)
+ assert(!rskd_lock);
+ if (faxi_awr_nbursts == 0)
+ begin
+ assert(S_AXI_BRESP == 2'b00);
+ // assert(S_AXI_BID == 0);
+ end
+
+ if (!S_AXI_RVALID)
+ begin
+ assert(S_AXI_RID == 0);
+ assert(S_AXI_RDATA == 0);
+ assert(S_AXI_RRESP == 2'b00);
+ end
+
+ if (!o_we)
+ begin
+ assert(o_waddr == 0);
+ assert(o_wdata == 0);
+ assert(o_wstrb == 0);
+ end
+ end
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Contract checking
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ...
+ //
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Cover properties
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+ reg f_wr_cvr_valid, f_rd_cvr_valid;
+ reg [4:0] f_dbl_rd_count, f_dbl_wr_count;
+
+ initial f_wr_cvr_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_wr_cvr_valid <= 0;
+ else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN > 4)
+ f_wr_cvr_valid <= 1;
+
+ always @(*)
+ cover(!S_AXI_BVALID && axi_awready && !m_awvalid
+ && f_wr_cvr_valid /* && ... */));
+
+ initial f_rd_cvr_valid = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_rd_cvr_valid <= 0;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN > 4)
+ f_rd_cvr_valid <= 1;
+
+ always @(*)
+ cover(S_AXI_ARREADY && f_rd_cvr_valid /* && ... */);
+
+ //
+ // Generate cover statements associated with multiple successive bursts
+ //
+ // These will be useful for demonstrating the throughput of the core.
+ //
+
+ initial f_dbl_wr_count = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_dbl_wr_count = 0;
+ else if (S_AXI_AWVALID && S_AXI_AWREADY && S_AXI_AWLEN == 3)
+ begin
+ if (!(&f_dbl_wr_count))
+ f_dbl_wr_count <= f_dbl_wr_count + 1;
+ end
+
+ always @(*)
+ cover(S_AXI_ARESETN && (f_dbl_wr_count > 1)); //!
+
+ always @(*)
+ cover(S_AXI_ARESETN && (f_dbl_wr_count > 3)); //!
+
+ always @(*)
+ cover(S_AXI_ARESETN && (f_dbl_wr_count > 3) && !m_awvalid
+ &&(!S_AXI_AWVALID && !S_AXI_WVALID && !S_AXI_BVALID)
+ && (faxi_awr_nbursts == 0)
+ && (faxi_wr_pending == 0));
+
+ initial f_dbl_rd_count = 0;
+ always @(posedge S_AXI_ACLK)
+ if (!S_AXI_ARESETN)
+ f_dbl_rd_count = 0;
+ else if (S_AXI_ARVALID && S_AXI_ARREADY && S_AXI_ARLEN == 3)
+ begin
+ if (!(&f_dbl_rd_count))
+ f_dbl_rd_count <= f_dbl_rd_count + 1;
+ end
+
+ always @(*)
+ cover(!S_AXI_ARESETN && (f_dbl_rd_count > 3)
+ /* && ... */
+ && !S_AXI_ARVALID && !S_AXI_RVALID);
+
+ generate if (OPT_LOCK)
+ begin
+ always @(*)
+ cover(S_AXI_ARESETN && S_AXI_BVALID && S_AXI_BREADY
+ && S_AXI_BRESP == 2'b01);
+ end endgenerate
+
+`ifdef VERIFIC
+ cover property (@(posedge S_AXI_ACLK)
+ disable iff (!S_AXI_ARESETN)
+ // Accept a burst request for 4 beats
+ (S_AXI_ARVALID && S_AXI_ARREADY && (S_AXI_ARLEN == 3)
+ ##1 S_AXI_ARVALID [*3]) [*3]
+ ##1 1 [*0:12]
+ // The return to idle
+ ##1 (!S_AXI_ARVALID && !o_rd && !rskd_valid && !S_AXI_RVALID)
+ );
+`endif
+
+ // }}}
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // "Careless" assumptions
+ // {{{
+ ////////////////////////////////////////////////////////////////////////
+ //
+ //
+
+ // }}}
+`endif
+// }}}
+endmodule
+`ifndef YOSYS
+`default_nettype wire
+`endif