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/axixbar.v | 2585 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2585 insertions(+) create mode 100644 rtl/wb2axip/axixbar.v (limited to 'rtl/wb2axip/axixbar.v') diff --git a/rtl/wb2axip/axixbar.v b/rtl/wb2axip/axixbar.v new file mode 100644 index 0000000..f2e1ac6 --- /dev/null +++ b/rtl/wb2axip/axixbar.v @@ -0,0 +1,2585 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// Filename: axixbar.v +// {{{ +// Project: WB2AXIPSP: bus bridges and other odds and ends +// +// Purpose: Create a full crossbar between NM AXI sources (masters), and NS +// AXI slaves. Every master can talk to any slave, provided it +// isn't already busy. +// {{{ +// Performance: This core has been designed with the goal of being able to push +// one transaction through the interconnect, from any master to +// any slave, per clock cycle. This may perhaps be its most unique +// feature. While throughput is good, latency is something else. +// +// The arbiter requires a clock to switch, then another clock to send data +// downstream. This creates a minimum two clock latency up front. The +// return path suffers another clock of latency as well, placing the +// minimum latency at four clocks. The minimum write latency is at +// least one clock longer, since the write data must wait for the write +// address before proceeeding. +// +// Note that this arbiter only forwards AxID fields. It does not use +// them in arbitration. As a result, only one master may ever make +// requests of any given slave at a time. All responses from a slave +// will be returned to that known master. This is a known limitation in +// this implementation which will be fixed (in time) with funding and +// interest. Until that time, in order for a second master to access +// a given slave, the first master must receive all of its acknowledgments. +// +// Usage: To use, you must first set NM and NS to the number of masters +// and the number of slaves you wish to connect to. You then need to +// adjust the addresses of the slaves, found SLAVE_ADDR array. Those +// bits that are relevant in SLAVE_ADDR to then also be set in SLAVE_MASK. +// Adjusting the data and address widths go without saying. +// +// Lower numbered masters are given priority in any "fight". +// +// Channel grants are given on the condition that 1) they are requested, +// 2) no other channel has a grant, 3) all of the responses have been +// received from the current channel, and 4) the internal counters are +// not overflowing. +// +// The core limits the number of outstanding transactions on any channel to +// 1<1) ? $clog2(OPT_LINGER+1) : 1; + // + localparam LGNM = (NM>1) ? $clog2(NM) : 1; + localparam LGNS = (NS>1) ? $clog2(NS+1) : 1; + // + // In order to use indexes, and hence fully balanced mux trees, it helps + // to make certain that we have a power of two based lookup. NMFULL + // is the number of masters in this lookup, with potentially some + // unused extra ones. NSFULL is defined similarly. + localparam NMFULL = (NM>1) ? (1<1) ? (1< we have to accept more + // write data before we can issue BVALID + slave_awaccepts[N] = 1'b0; + end + end + // }}} + + // slave_waccepts + // {{{ + always @(*) + begin + slave_waccepts[N] = 1'b1; + if (!mwgrant[N]) + slave_waccepts[N] = 1'b0; + if (!wdata_expected[N] && (!OPT_AWW || !slave_awaccepts[N])) + slave_waccepts[N] = 1'b0; + if (!wgrant[N][NS]) + begin + if (!slave_wready[mwindex[N]]) + slave_waccepts[N] = 1'b0; + end else if (berr_valid[N] && !bskd_ready[N]) + slave_waccepts[N] = 1'b0; + end + // }}} + + reg r_awvalid; + + always @(*) + begin + r_awvalid = dcd_awvalid[N] && !mwfull[N]; + wrequest[N]= 0; + if (!mwfull[N]) + wrequest[N][NS:0] = wdecode; + end + + assign m_awvalid[N] = r_awvalid; + + // QOS handling via write_qos_lockout + // {{{ + if (!OPT_QOS || NM == 1) + begin : WRITE_NO_QOS + + // If we aren't using QOS, then never lock any packets + // out from arbitration + assign write_qos_lockout[N] = 0; + + end else begin : WRITE_QOS + + // Lock out a master based upon a second master having + // a higher QOS request level + // {{{ + reg r_write_qos_lockout; + + initial r_write_qos_lockout = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + r_write_qos_lockout <= 0; + else begin + r_write_qos_lockout <= 0; + + for(iN=0; iN 0) + begin + // Otherwise, we decrement it until it reaches + // zero + r_linger <= (linger_counter > 1); + linger_counter <= linger_counter - 1; + end else + r_linger <= 0; + + assign linger = r_linger; + end + // }}} + + // leave_channel + // {{{ + // True of another master is requesting access to this slave, + // or if we are requesting access to another slave. If QOS + // lockout is enabled, then we also leave the channel if a + // request with a higher QOS has arrived + always @(*) + begin + leave_channel = 0; + if (!m_awvalid[N] + && (!linger || wrequested[NM][mwindex[N]])) + // Leave the channel after OPT_LINGER counts + // of the channel being idle, or when someone + // else asks for the channel + leave_channel = 1; + if (m_awvalid[N] && !wrequest[N][mwindex[N]]) + // Need to leave this channel to connect + // to any other channel + leave_channel = 1; + if (write_qos_lockout[N]) + // Need to leave this channel for another higher + // priority request + leave_channel = 1; + end + // }}} + + // WRITE GRANT ALLOCATION + // {{{ + // Now that we've done our homework, we can switch grants + // if necessary + initial wgrant[N] = 0; + initial mwgrant[N] = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + begin + wgrant[N] <= 0; + mwgrant[N] <= 0; + end else if (!stay_on_channel) + begin + if (requested_channel_is_available) + begin + // Switch to a new channel + mwgrant[N] <= 1'b1; + wgrant[N] <= wrequest[N][NS:0]; + end else if (leave_channel) + begin + // Revoke the given grant + mwgrant[N] <= 1'b0; + wgrant[N] <= 0; + end + end + // }}} + + // mwindex (registered) + // {{{ + always @(wrequest[N]) + begin + requested_index = 0; + for(iM=0; iM<=NS; iM=iM+1) + if (wrequest[N][iM]) + requested_index= requested_index | iM[LGNS-1:0]; + end + + // Now for mwindex + initial r_mwindex = 0; + always @(posedge S_AXI_ACLK) + if (!stay_on_channel && requested_channel_is_available) + r_mwindex <= requested_index; + + assign mwindex[N] = r_mwindex; + // }}} + + end for (N=NM; N 0) + begin + r_linger <= (linger_counter > 1); + linger_counter <= linger_counter - 1; + end else + r_linger <= 0; + + assign linger = r_linger; + end + // }}} + + // leave_channel + // {{{ + // True of another master is requesting access to this slave, + // or if we are requesting access to another slave. If QOS + // lockout is enabled, then we also leave the channel if a + // request with a higher QOS has arrived + always @(*) + begin + leave_channel = 0; + if (!m_arvalid[N] + && (!linger || rrequested[NM][mrindex[N]])) + // Leave the channel after OPT_LINGER counts + // of the channel being idle, or when someone + // else asks for the channel + leave_channel = 1; + if (m_arvalid[N] && !rrequest[N][mrindex[N]]) + // Need to leave this channel to connect + // to any other channel + leave_channel = 1; + if (read_qos_lockout[N]) + leave_channel = 1; + end + // }}} + + + // READ GRANT ALLOCATION + // {{{ + initial rgrant[N] = 0; + initial mrgrant[N] = 0; + always @(posedge S_AXI_ACLK) + if (!S_AXI_ARESETN) + begin + rgrant[N] <= 0; + mrgrant[N] <= 0; + end else if (!stay_on_channel) + begin + if (requested_channel_is_available) + begin + // Switching channels + mrgrant[N] <= 1'b1; + rgrant[N] <= rrequest[N][NS:0]; + end else if (leave_channel) + begin + mrgrant[N] <= 1'b0; + rgrant[N] <= 0; + end + end + // }}} + + // mrindex (registered) + // {{{ + always @(rrequest[N]) + begin + requested_index = 0; + for(iM=0; iM<=NS; iM=iM+1) + if (rrequest[N][iM]) + requested_index = requested_index|iM[LGNS-1:0]; + end + + initial r_mrindex = 0; + always @(posedge S_AXI_ACLK) + if (!stay_on_channel && requested_channel_is_available) + r_mrindex <= requested_index; + + assign mrindex[N] = r_mrindex; + // }}} + + end for (N=NM; N 1); + wpending <= wpending - 1; + end + 2'b10: begin + wpending <= wpending + 1; + r_wdata_expected <= 1; + end + default: begin end + endcase + + assign wdata_expected[N] = r_wdata_expected; + + assign wlasts_pending[N] = wpending; + // }}} + // }}} + end endgenerate + + generate for (N=0; N= 1); + initial assert(NM >= 1); + // }}} + + //////////////////////////////////////////////////////////////////////// + // + // Check the arbiter signals for consistency + // {{{ + generate for(N=0; N