From 3038edc09a2eb15762f2e58533f429489107520b Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Wed, 6 Mar 2024 02:38:24 -0600 Subject: rtl/wb2axip: add to version control --- rtl/wb2axip/demofull.v | 1285 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1285 insertions(+) create mode 100644 rtl/wb2axip/demofull.v (limited to 'rtl/wb2axip/demofull.v') 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= 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<= 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 -- cgit v1.2.3