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/axildouble.v | 734 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 734 insertions(+) create mode 100644 rtl/wb2axip/axildouble.v (limited to 'rtl/wb2axip/axildouble.v') diff --git a/rtl/wb2axip/axildouble.v b/rtl/wb2axip/axildouble.v new file mode 100644 index 0000000..ddaedb6 --- /dev/null +++ b/rtl/wb2axip/axildouble.v @@ -0,0 +1,734 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: axildouble.v +// {{{ +// Project: WB2AXIPSP: bus bridges and other odds and ends +// +// Purpose: Create a special slave which can be used to reduce crossbar +// logic for multiple simplified slaves. This is a companion +// core to the similar axilsingle core, but allowing the slave to +// decode the clock between multiple possible addresses. +// +// To use this, the slave must follow specific (simplified AXI) rules: +// +// Write interface +// 1. The slave must guarantee that AWREADY == WREADY = 1 +// (This core doesn't have AWREADY or WREADY inputs) +// 2. The slave must also guarantee that BVALID == $past(AWVALID) +// (This core internally generates BVALID) +// 3. The controller will guarantee that AWVALID == WVALID +// (You can connect AWVALID to WVALID when connecting to your core) +// 4. The controller will also guarantee that BREADY = 1 +// (This core doesn't have a BVALID input) +// +// Read interface +// 1. The slave must guarantee that ARREADY == 1 +// (This core doesn't have an ARREADY input) +// 2. The slave must also guarantee that RVALID == $past(ARVALID) +// (This core doesn't have an RVALID input, trusting the slave +// instead) +// 3. The controller will guarantee that RREADY = 1 +// (This core doesn't have an RREADY output) +// +// +// Why? This simplifies slave logic. Slaves may interact with the bus +// using only the logic below: +// +// always @(posedge S_AXI_ACLK) +// if (AWVALID) case(AWADDR) +// R1: slvreg_1 <= WDATA; +// R2: slvreg_2 <= WDATA; +// R3: slvreg_3 <= WDATA; +// R4: slvreg_4 <= WDATA; +// endcase +// +// always @(*) +// BRESP = 2'b00; +// +// always @(posedge S_AXI_ACLK) +// if (ARVALID) +// case(ARADDR) +// R1: RDATA <= slvreg_1; +// R2: RDATA <= slvreg_2; +// R3: RDATA <= slvreg_3; +// R4: RDATA <= slvreg_4; +// endcase +// +// always @(*) +// RRESP = 2'b00; +// +// This core will then keep track of the more complex bus logic, +// simplifying both slaves and connection logic. Slaves with the more +// complicated (and proper/accurate) logic, that follow the rules above, +// should have no problems with this additional logic. +// +// Performance: +// +// This core can sustain one read/write per clock as long as the upstream +// AXI master keeps S_AXI_[BR]READY high. If S_AXI_[BR]READY ever drops, +// there's some flexibility provided by the return FIFO, so the master +// might not notice a drop in throughput until the FIFO fills. +// +// The more practical performance measure is the latency of this core. +// That I've measured at four clocks. +// +// 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 +// `ifdef VERILATOR +// `define FORMAL +// `endif +// }}} +module axildouble #( + // {{{ + parameter integer C_AXI_DATA_WIDTH = 32, + parameter integer C_AXI_ADDR_WIDTH = 32, + // + // NS is the number of slave interfaces + parameter NS = 8, + // + // + parameter [NS*C_AXI_ADDR_WIDTH-1:0] SLAVE_ADDR = { + { 3'b111, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b110, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b101, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b100, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b011, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 3'b010, {(C_AXI_ADDR_WIDTH-3){1'b0}} }, + { 4'b0001,{(C_AXI_ADDR_WIDTH-4){1'b0}} }, + { 4'b0000,{(C_AXI_ADDR_WIDTH-4){1'b0}} } }, + // + // + parameter [NS*C_AXI_ADDR_WIDTH-1:0] SLAVE_MASK = + (NS <= 1) ? 0 + : { {(NS-2){ 3'b111,{(C_AXI_ADDR_WIDTH-3){1'b0}} }}, + {(2){ 4'b1111,{(C_AXI_ADDR_WIDTH-4){1'b0}} }} + }, + // + // + // LGFLEN specifies the log (based two) of the number of + // transactions that may need to be held outstanding internally. + // If you really want high throughput, and if you expect any + // back pressure at all, then increase LGFLEN. Otherwise the + // default value of 3 (FIFO size = 8) should be sufficient + // to maintain full loading + parameter LGFLEN=3, + // + // If set, OPT_LOWPOWER will set all unused registers, both + // internal and external, to zero anytime their corresponding + // *VALID bit is clear + parameter [0:0] OPT_LOWPOWER = 0 + // }}} + ) ( + // {{{ + input wire S_AXI_ACLK, + input wire S_AXI_ARESETN, + // + input wire S_AXI_AWVALID, + output wire S_AXI_AWREADY, + input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_AWADDR, + input wire [3-1:0] S_AXI_AWPROT, + // + input wire S_AXI_WVALID, + output wire S_AXI_WREADY, + input wire [C_AXI_DATA_WIDTH-1:0] S_AXI_WDATA, + input wire [C_AXI_DATA_WIDTH/8-1:0] S_AXI_WSTRB, + // + output wire [2-1:0] S_AXI_BRESP, + output wire S_AXI_BVALID, + input wire S_AXI_BREADY, + // + input wire [C_AXI_ADDR_WIDTH-1:0] S_AXI_ARADDR, + input wire [3-1:0] S_AXI_ARPROT, + input wire S_AXI_ARVALID, + output wire S_AXI_ARREADY, + // + output wire [C_AXI_DATA_WIDTH-1:0] S_AXI_RDATA, + output wire [2-1:0] S_AXI_RRESP, + output wire S_AXI_RVALID, + input wire S_AXI_RREADY, + // + // + // + output wire [NS-1:0] M_AXI_AWVALID, + output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_AWADDR, + output wire [3-1:0] M_AXI_AWPROT, + // + output wire [C_AXI_DATA_WIDTH-1:0] M_AXI_WDATA, + output wire [C_AXI_DATA_WIDTH/8-1:0] M_AXI_WSTRB, + // + input wire [NS*2-1:0] M_AXI_BRESP, + // + output wire [NS-1:0] M_AXI_ARVALID, + output wire [C_AXI_ADDR_WIDTH-1:0] M_AXI_ARADDR, + output wire [3-1:0] M_AXI_ARPROT, + // + input wire [NS*C_AXI_DATA_WIDTH-1:0] M_AXI_RDATA, + input wire [NS*2-1:0] M_AXI_RRESP + // }}} + ); + + // + // AW, and DW, are short-hand abbreviations used locally. + localparam AW = C_AXI_ADDR_WIDTH; + localparam DW = C_AXI_DATA_WIDTH; + localparam LGNS = $clog2(NS); + // + localparam INTERCONNECT_ERROR = 2'b11; + + //////////////////////////////////////////////////////////////////////// + // + // Write logic: + // + //////////////////////////////////////////////////////////////////////// + // + // + wire awskid_valid, bffull, bempty, write_awskidready, + dcd_awvalid; + reg write_bvalid, write_response; + reg bfull, write_wready, write_no_index; + wire [NS:0] wdecode; + wire [AW-1:0] awskid_addr; + wire [AW-1:0] m_awaddr; + reg [LGNS-1:0] write_windex, write_bindex; + wire [3-1:0] awskid_prot, m_axi_awprot; + wire [LGFLEN:0] bfill; + reg [LGFLEN:0] write_count; + reg [1:0] write_resp; + integer k; + + skidbuffer #(.OPT_LOWPOWER(OPT_LOWPOWER), .OPT_OUTREG(0), + .DW(AW+3)) + awskid( .i_clk(S_AXI_ACLK), + .i_reset(!S_AXI_ARESETN), + .i_valid(S_AXI_AWVALID), + .o_ready(S_AXI_AWREADY), + .i_data({ S_AXI_AWPROT, S_AXI_AWADDR }), + .o_valid(awskid_valid), .i_ready(write_awskidready), + .o_data({ awskid_prot, awskid_addr })); + + wire awskd_stall; + + addrdecode #(.AW(AW), .DW(3), .NS(NS), + .SLAVE_ADDR(SLAVE_ADDR), + .SLAVE_MASK(SLAVE_MASK), + .OPT_REGISTERED(1'b1)) + wraddr(.i_clk(S_AXI_ACLK), .i_reset(!S_AXI_ARESETN), + .i_valid(awskid_valid && write_awskidready), .o_stall(awskd_stall), + .i_addr(awskid_addr), + .i_data(awskid_prot), + .o_valid(dcd_awvalid), .i_stall(!S_AXI_WVALID), + .o_decode(wdecode), .o_addr(m_awaddr), + .o_data(m_axi_awprot)); + + always @(*) + write_wready = dcd_awvalid; + assign S_AXI_WREADY = write_wready; + assign M_AXI_AWVALID = (S_AXI_WVALID) ? wdecode[NS-1:0] : 0; + assign M_AXI_AWADDR = m_awaddr; + assign M_AXI_AWPROT = m_axi_awprot; + assign M_AXI_WDATA = S_AXI_WDATA; + assign M_AXI_WSTRB = S_AXI_WSTRB; + assign write_awskidready = (S_AXI_WVALID || !S_AXI_WREADY) && !bfull; + + always @(*) + begin + write_windex = 0; + for(k=0; k 4); + + always @(*) + cover(cvr_arvalids > 4); + + always @(*) + cover(cvr_reads > 4); + + always @(*) + cover(cvr_writes > 4); + + always @(*) + cover((cvr_writes > 4) && (cvr_reads > 4)); +`endif +endmodule +// `ifndef YOSYS +// `default_nettype wire +// `endif -- cgit v1.2.3