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/wbxbar.v | 1790 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1790 insertions(+) create mode 100644 rtl/wb2axip/wbxbar.v (limited to 'rtl/wb2axip/wbxbar.v') diff --git a/rtl/wb2axip/wbxbar.v b/rtl/wb2axip/wbxbar.v new file mode 100644 index 0000000..15d6587 --- /dev/null +++ b/rtl/wb2axip/wbxbar.v @@ -0,0 +1,1790 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: wbxbar.v +// {{{ +// Project: WB2AXIPSP: bus bridges and other odds and ends +// +// Purpose: A Configurable wishbone cross-bar interconnect, conforming +// to the WB-B4 pipeline specification, as described on the +// ZipCPU blog. +// +// Performance: +// Throughput: One transaction per clock +// Latency: One clock to get access to an unused channel, another to +// place the results on the slave bus, and another to return, or a minimum +// of three clocks. +// +// Usage: To use, you'll need to set NM and NS to the number of masters +// (input ports) and the number of slaves respectively. You'll then +// want to set the addresses for the slaves in the SLAVE_ADDR array, +// together with the SLAVE_MASK array indicating which SLAVE_ADDRs +// are valid. Address and data widths should be adjusted at the same +// time. +// +// Voila, you are now set up! +// +// Now let's fine tune this: +// +// LGMAXBURST can be set to control the maximum number of outstanding +// transactions. An LGMAXBURST of 6 will allow 63 outstanding +// transactions. +// +// OPT_TIMEOUT, if set to a non-zero value, is a number of clock periods +// to wait for a slave to respond. Should the timeout expire and the +// slave not respond, a bus error will be returned and the slave will +// be issued a bus abort signal (CYC will be dropped). +// +// OPT_STARVATION_TIMEOUT, if set, applies the OPT_TIMEOUT counter to +// how long a particular master waits for arbitration. If the master is +// "starved", a bus error will be returned. +// +// OPT_DBLBUFFER is used to increase clock speed by registering all +// outputs. +// +// OPT_LOWPOWER is an experimental feature that, if set, will cause any +// unused FFs to be set to zero rather than flopping in the electronic +// wind, in an effort to minimize transitions over bus wires. This will +// cost some extra logic, for ... an uncertain power savings. +// +// +// 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 wbxbar #( + // {{{ + parameter NM = 4, NS=8, + parameter AW = 32, DW=32, + parameter [NS*AW-1:0] SLAVE_ADDR = { + { 3'b111, {(AW-3){1'b0}} }, + { 3'b110, {(AW-3){1'b0}} }, + { 3'b101, {(AW-3){1'b0}} }, + { 3'b100, {(AW-3){1'b0}} }, + { 3'b011, {(AW-3){1'b0}} }, + { 3'b010, {(AW-3){1'b0}} }, + { 4'b0010, {(AW-4){1'b0}} }, + { 4'b0000, {(AW-4){1'b0}} } }, + parameter [NS*AW-1:0] SLAVE_MASK = (NS <= 1) ? 0 + : { {(NS-2){ 3'b111, {(AW-3){1'b0}} }}, + {(2){ 4'b1111, {(AW-4){1'b0}} }} }, + // + // LGMAXBURST is the log_2 of the length of the longest burst + // that might be seen. It's used to set the size of the + // internal counters that are used to make certain that the + // cross bar doesn't switch while still waiting on a response. + parameter LGMAXBURST=6, + // + // OPT_TIMEOUT is used to help recover from a misbehaving slave. + // If set, this value will determine the number of clock cycles + // to wait for a misbehaving slave before returning a bus error. + // Alternatively, if set to zero, this functionality will be + // removed. + parameter OPT_TIMEOUT = 0, // 1023; + // + // If OPT_TIMEOUT is set, then OPT_STARVATION_TIMEOUT may also + // be set. The starvation timeout adds to the bus error timeout + // generation the possibility that a master will wait + // OPT_TIMEOUT counts without receiving the bus. This may be + // the case, for example, if one bus master is consuming a + // peripheral to such an extent that there's no time/room for + // another bus master to use it. In that case, when the timeout + // runs out, the waiting bus master will be given a bus error. + parameter [0:0] OPT_STARVATION_TIMEOUT = 1'b0 + && (OPT_TIMEOUT > 0), + // + // OPT_DBLBUFFER is used to register all of the outputs, and + // thus avoid adding additional combinational latency through + // the core that might require a slower clock speed. + parameter [0:0] OPT_DBLBUFFER = 1'b0, + // + // OPT_LOWPOWER adds logic to try to force unused values to + // zero, rather than to allow a variety of logic optimizations + // that could be used to reduce the logic count of the device. + // Hence, OPT_LOWPOWER will use more logic, but it won't drive + // bus wires unless there's a value to drive onto them. + parameter [0:0] OPT_LOWPOWER = 1'b1 + // }}} + ) ( + // {{{ + input wire i_clk, i_reset, + // + // Here are the bus inputs from each of the WB bus masters + input wire [NM-1:0] i_mcyc, i_mstb, i_mwe, + input wire [NM*AW-1:0] i_maddr, + input wire [NM*DW-1:0] i_mdata, + input wire [NM*DW/8-1:0] i_msel, + // + // .... and their return data + output wire [NM-1:0] o_mstall, + output wire [NM-1:0] o_mack, + output reg [NM*DW-1:0] o_mdata, + output wire [NM-1:0] o_merr, + // + // + // Here are the output ports, used to control each of the + // various slave ports that we are connected to + output reg [NS-1:0] o_scyc, o_sstb, o_swe, + output reg [NS*AW-1:0] o_saddr, + output reg [NS*DW-1:0] o_sdata, + output reg [NS*DW/8-1:0] o_ssel, + // + // ... and their return data back to us. + input wire [NS-1:0] i_sstall, i_sack, + input wire [NS*DW-1:0] i_sdata, + input wire [NS-1:0] i_serr + // }}} + ); + // + // + //////////////////////////////////////////////////////////////////////// + // + // Register declarations + // {{{ + // + // TIMEOUT_WIDTH is the number of bits in counter used to check + // on a timeout. + localparam TIMEOUT_WIDTH = $clog2(OPT_TIMEOUT); + // + // LGNM is the log (base two) of the number of bus masters + // connecting to this crossbar + localparam LGNM = (NM>1) ? $clog2(NM) : 1; + // + // LGNS is the log (base two) of the number of slaves plus one + // come out of the system. The extra "plus one" is used for a + // pseudo slave representing the case where the given address + // doesn't connect to any of the slaves. This address will + // generate a bus error. + localparam LGNS = $clog2(NS+1); + // At one time I used o_macc and o_sacc to put into the outgoing + // trace file, just enough logic to tell me if a transaction was + // taking place on the given clock. + // + // assign o_macc = (i_mstb & ~o_mstall); + // assign o_sacc = (o_sstb & ~i_sstall); + // + // These definitions work with Veri1ator, just not with Yosys + // reg [NM-1:0][NS:0] request; + // reg [NM-1:0][NS-1:0] requested; + // reg [NM-1:0][NS:0] grant; + // + // These definitions work with both + wire [NS:0] request [0:NM-1]; + reg [NS-1:0] requested [0:NM-1]; + reg [NS:0] grant [0:NM-1]; + reg [NM-1:0] mgrant; + reg [NS-1:0] sgrant; + + // Verilator lint_off UNUSED + wire [LGMAXBURST-1:0] w_mpending [0:NM-1]; + // Verilator lint_on UNUSED + reg [NM-1:0] mfull, mnearfull, mempty; + wire [NM-1:0] timed_out; + + localparam NMFULL = (NM > 1) ? (1< 0) + begin : CHECK_TIMEOUT + // {{{ + for(N=0; N 0) + begin + deadlock_timer <= deadlock_timer - 1; + r_timed_out <= (deadlock_timer <= 1); + end + + assign timed_out[N] = r_timed_out; + end + // }}} + end else begin : NO_TIMEOUT + // {{{ + assign timed_out = 0; + // }}} + end endgenerate + // }}} + //////////////////////////////////////////////////////////////////////// + // + // Parameter consistency check + // {{{ + //////////////////////////////////////////////////////////////////////// + // + // + initial begin : PARAMETER_CONSISTENCY_CHECK + // {{{ + if (NM == 0) + begin + $display("ERROR: At least one master must be defined"); + $stop; + end + + if (NS == 0) + begin + $display("ERROR: At least one slave must be defined"); + $stop; + end + + if (OPT_STARVATION_TIMEOUT != 0 && OPT_TIMEOUT == 0) + begin + $display("ERROR: The starvation timeout is implemented as part of the regular timeout"); + $display(" Without a timeout, the starvation timeout will not work"); + $stop; + end + // }}} + end + // }}} +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +// +// Formal properties used to verify the core +// {{{ +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////// +`ifdef FORMAL + // Register declarations + // {{{ + localparam F_MAX_DELAY = 4; + localparam F_LGDEPTH = LGMAXBURST; + // + reg f_past_valid; + // + // Our bus checker keeps track of the number of requests, + // acknowledgments, and the number of outstanding transactions on + // every channel, both the masters driving us + wire [F_LGDEPTH-1:0] f_mreqs [0:NM-1]; + wire [F_LGDEPTH-1:0] f_macks [0:NM-1]; + wire [F_LGDEPTH-1:0] f_moutstanding [0:NM-1]; + // + // as well as the slaves that we drive ourselves + wire [F_LGDEPTH-1:0] f_sreqs [0:NS-1]; + wire [F_LGDEPTH-1:0] f_sacks [0:NS-1]; + wire [F_LGDEPTH-1:0] f_soutstanding [0:NS-1]; + // }}} + + initial assert(!OPT_STARVATION_TIMEOUT || OPT_TIMEOUT > 0); + + initial f_past_valid = 0; + always @(posedge i_clk) + f_past_valid = 1'b1; + + always @(*) + if (!f_past_valid) + assume(i_reset); + + generate for(N=0; N= + ((OPT_BUFFER_DECODER && dcd_stb[N]) ? 1:0) + + (o_mack[N] && OPT_DBLBUFFER) ? 1:0); + + always @(*) + n_outstanding = f_moutstanding[N] + - ((OPT_BUFFER_DECODER && dcd_stb[N]) ? 1:0) + - ((o_mack[N] && OPT_DBLBUFFER) ? 1:0); + + always @(posedge i_clk) + if (i_mcyc[N] && !mgrant[N] && !o_merr[N]) + assert(f_moutstanding[N] + == ((OPT_BUFFER_DECODER & dcd_stb[N]) ? 1:0)); + + else if (i_mcyc[N] && mgrant[N] && !i_reset) + for(iM=0; iM 0) + assert(i_mwe[N] == o_swe[iM]); + if (o_sstb[iM]) + assert(i_mwe[N] == o_swe[iM]); + if (o_mack[N]) + assert(i_mwe[N] == o_swe[iM]); + if (o_scyc[iM] && i_sack[iM]) + assert(i_mwe[N] == o_swe[iM]); + if (o_merr[N] && !timed_out[N]) + assert(i_mwe[N] == o_swe[iM]); + if (o_scyc[iM] && i_serr[iM]) + assert(i_mwe[N] == o_swe[iM]); + end + end + + always @(*) + if (!i_reset && OPT_BUFFER_DECODER && i_mcyc[N]) + begin + if (dcd_stb[N]) + assert(i_mwe[N] == m_we[N]); + end + // }}} + end endgenerate + + generate for(M=0; M 1) + begin : DOUBLE_ADDRESS_CHECK + // {{{ + // + // Check that no slave address has been assigned twice. + // This check only needs to be done once at the beginning + // of the run, during the BMC section. + reg address_found; + + always @(*) + if (!f_past_valid) + begin + address_found = 0; + for(iM=0; iM 1) + begin + + always @(posedge i_clk) + cover(!f_cvr_aborted && (&f_m_ackd[1:0])); + + end endgenerate + + initial f_s_ackd = 0; + generate for (M=0; M 1) + begin + + always @(posedge i_clk) + cover(!f_cvr_aborted && (&f_s_ackd[NS-1:0])); + + end endgenerate + // }}} +`endif +// }}} +endmodule +`ifndef YOSYS +`default_nettype wire +`endif -- cgit v1.2.3