From 02d939898a31035b526e4b9545a242989211b9b1 Mon Sep 17 00:00:00 2001 From: Caleb Whitehead Date: Tue, 28 May 2024 13:21:27 -0700 Subject: [PATCH] Add AXI sub wrapper and simplex arbiter --- src/axi/rtl/axi_sub.sv | 196 +++++++++++++++++++++++++++++++++++++ src/axi/rtl/axi_sub_arb.sv | 135 +++++++++++++++++++++++++ 2 files changed, 331 insertions(+) create mode 100644 src/axi/rtl/axi_sub.sv create mode 100644 src/axi/rtl/axi_sub_arb.sv diff --git a/src/axi/rtl/axi_sub.sv b/src/axi/rtl/axi_sub.sv new file mode 100644 index 000000000..319140172 --- /dev/null +++ b/src/axi/rtl/axi_sub.sv @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use 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. +// + +// ------------------------------------------------------------- +// AXI Subordinate +// ------------------------------------------------------------- +// Description: +// Subordinate to convert AXI protocol transactions into internal component accesses +// Includes an arbiter to squash duplex AXI transactions into simplex component operations +// May optionally include an Exclusive Access monitor (AxLOCK signal) +// +// Limitations: +// - When multiple ID tracking is enabled, write responses are returned in the +// same order they are received, regardless of ID. +// +// ------------------------------------------------------------- + +module axi_sub import axi_pkg::*; #( + parameter AW = 32, // Address Width + parameter DW = 32, // Data Width + BC = DW/8, // Byte Count + BW = $clog2(BC), // Byte count Width + parameter UW = 32, // User Width + parameter IW = 1, // ID Width + ID_NUM = 1 << IW, // Don't override + + parameter EX_EN = 0, // Enable exclusive access tracking w/ AxLOCK + parameter C_LAT = 0 // Component latency in clock cycles from (dv&&!hld) -> rdata + // Must be const per component + // For registers, typically 0 + // For SRAM, 1 or more +) ( + input clk, + input rst_n, + + // AXI INF + axi_if.w_sub s_axi_w_if, + axi_if.r_sub s_axi_r_if, + + //COMPONENT INF + output logic dv, + output logic [AW-1:0] addr, // Byte address + output logic [UW-1:0] user, + output logic [DW-1:0] wdata, // Requires: Component dwidth == AXI dwidth + output logic [BC-1:0] wstrb, // Requires: Component dwidth == AXI dwidth + input logic [DW-1:0] rdata, // Requires: Component dwidth == AXI dwidth + output logic last, // Asserted with final 'dv' of a burst + input logic hld, + input logic err + +); + + // Exclusive Access Signals + logic [ID_NUM-1:0] ex_clr; + logic [ID_NUM-1:0] ex_active; + axi_ex_ctx_t [ID_NUM-1:0] ex_ctx; + + //Read Subordinate INF + logic r_dv; + logic [AW-1:0] r_addr; // Byte address + logic [UW-1:0] r_user; + logic r_last; // Asserted with final 'dv' of a burst + logic r_hld; + logic r_err; + + logic [DW-1:0] r_rdata; // Requires: Component dwidth == AXI dwidth + + //Write Subordinate INF + logic w_dv; + logic [AW-1:0] w_addr; // Byte address + logic [UW-1:0] w_user; + logic [DW-1:0] w_wdata; // Requires: Component dwidth == AXI dwidth + logic [BC-1:0] w_wstrb; // Requires: Component dwidth == AXI dwidth + logic w_last; // Asserted with final 'dv' of a burst + logic w_hld; + logic w_err; + + + axi_sub_wr #( + .AW (AW ), + .DW (DW ), + .UW (UW ), + .IW (IW ), + + .EX_EN(EX_EN) + ) i_axi_sub_wr ( + .clk (clk ), + .rst_n(rst_n), + + // AXI INF + .s_axi_if(s_axi_w_if), + + // Exclusive Access Signals + .ex_clr (ex_clr ), + .ex_active(ex_active), + .ex_ctx (ex_ctx ), + + //COMPONENT INF + .dv (w_dv ), + .addr (w_addr ), + .user (w_user ), + .wdata(w_wdata), + .wstrb(w_wstrb), + .last (w_last ), + .hld (w_hld ), + .err (w_err ) + + ); + + axi_sub_rd #( + .AW(AW), + .DW(DW), + .UW(UW), + .IW(IW), + + .EX_EN(EX_EN), + .C_LAT(C_LAT) + ) i_axi_sub_rd ( + .clk (clk ), + .rst_n(rst_n), + + // AXI INF + .s_axi_if(s_axi_r_if), + + // Exclusive Access Signals + .ex_clr (ex_clr ), + .ex_active(ex_active), + .ex_ctx (ex_ctx ), + + //COMPONENT INF + .dv (r_dv ), + .addr (r_addr ), + .user (r_user ), + .last (r_last ), + .hld (r_hld ), + .err (r_err ), + + .rdata(r_rdata) + ); + + axi_sub_arb #( + .AW(AW), + .DW(DW), + .UW(UW), + .IW(IW), + + .EX_EN(EX_EN), + .C_LAT(C_LAT) + ) i_axi_sub_arb ( + .clk (clk ), + .rst_n (rst_n ), + + //Read Subordinate INF + .r_dv (r_dv ), + .r_addr (r_addr ), + .r_user (r_user ), + .r_last (r_last ), + .r_hld (r_hld ), + .r_err (r_err ), + .r_rdata(r_rdata), + + //Write Subordinate INF + .w_dv (w_dv ), + .w_addr (w_addr ), + .w_user (w_user ), + .w_wdata(w_wdata), + .w_wstrb(w_wstrb), + .w_last (w_last ), + .w_hld (w_hld ), + .w_err (w_err ), + + //COMPONENT INF + .dv (dv ), + .addr (addr ), + .user (user ), + .wdata (wdata ), + .wstrb (wstrb ), + .last (last ), + .hld (hld ), + .err (err ), + .rdata (rdata ) + ); + +endmodule diff --git a/src/axi/rtl/axi_sub_arb.sv b/src/axi/rtl/axi_sub_arb.sv new file mode 100644 index 000000000..235405d80 --- /dev/null +++ b/src/axi/rtl/axi_sub_arb.sv @@ -0,0 +1,135 @@ +// SPDX-License-Identifier: Apache-2.0 +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use 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. +// + +// ------------------------------------------------------------- +// AXI Subordinate Arbiter +// ------------------------------------------------------------- +// Description: +// Arbitrate between Reads and Writes coming from AXI subordinate modules. +// Always give precedence to Writes. +// +// ------------------------------------------------------------- + +module axi_sub_arb import axi_pkg::*; #( + parameter AW = 32, // Address Width + parameter DW = 32, // Data Width + BC = DW/8, // Byte Count + BW = $clog2(BC), // Byte count Width + parameter UW = 32, // User Width + parameter IW = 1, // ID Width + ID_NUM = 1 << IW, // Don't override + + parameter EX_EN = 0, // Enable exclusive access tracking w/ AxLOCK + parameter C_LAT = 0 // Component latency in clock cycles from (dv&&!hld) -> rdata + // Must be const per component + // For registers, typically 0 + // For SRAM, 1 or more +) ( + input clk, + input rst_n, + + //Read Subordinate INF + input logic r_dv, + input logic [AW-1:0] r_addr, // Byte address + input logic [UW-1:0] r_user, + input logic r_last, // Asserted with final 'dv' of a burst + output logic r_hld, + output logic r_err, + + output logic [DW-1:0] r_rdata, // Requires: Component dwidth == AXI dwidth + + //Write Subordinate INF + input logic w_dv, + input logic [AW-1:0] w_addr, // Byte address + input logic [UW-1:0] w_user, + input logic [DW-1:0] w_wdata, // Requires: Component dwidth == AXI dwidth + input logic [BC-1:0] w_wstrb, // Requires: Component dwidth == AXI dwidth + input logic w_last, // Asserted with final 'dv' of a burst + output logic w_hld, + output logic w_err, + + //COMPONENT INF + output logic dv, + output logic [AW-1:0] addr, // Byte address + output logic [UW-1:0] user, + output logic [DW-1:0] wdata, // Requires: Component dwidth == AXI dwidth + output logic [BC-1:0] wstrb, // Requires: Component dwidth == AXI dwidth + output logic last, // Asserted with final 'dv' of a burst + input logic hld, + input logic err, // FIXME Does this assert with dv or with rdata for reads (when C_LAT > 0)? + + input logic [DW-1:0] rdata // Requires: Component dwidth == AXI dwidth +); + + logic r_pri; // Priority to reads + logic r_win; + + // Switch priority to current arb winner so that priority persists + // in case + // a) it was granted during a hold + // b) it was granted at start of multi-beat burst + // Otherwise, always give priority to other channel at end of a burst + // to arbitrate fairly + always_ff@(posedge clk or negedge rst_n) begin + if (!rst_n) + r_pri <= 1'b0; + // Toggle priority at end of burst + else if (w_dv && !w_hld && w_last) + r_pri <= 1'b1; + else if (r_dv && !r_hld && r_last) + r_pri <= 1'b0; + // Keep priority when burst starts + else if (w_dv && !r_win && !w_last) + r_pri <= 1'b0; + else if (r_dv && r_win && !r_last) + r_pri <= 1'b1; + end + + always_comb begin +// case ({r_pri,r_dv,w_dv}) inside +// 3'b000: r_win = 0; +// 3'b001: r_win = 0; +// 3'b010: r_win = 1; +// 3'b011: r_win = 0; +// 3'b100: r_win = 1; +// 3'b101: r_win = 0; +// 3'b110: r_win = 1; +// 3'b111: r_win = 1; +// endcase + if (r_pri) r_win = r_dv || !w_dv; + else r_win = w_dv || !r_dv; + end + + always_comb begin + dv = r_dv || w_dv; + addr = r_win ? r_addr : w_addr; + user = r_win ? r_user : w_user; + last = r_win ? r_last : w_last; + r_hld = hld || !r_win; + w_hld = hld || r_win; + r_err = err; + w_err = err; + wdata = w_wdata; + wstrb = w_wstrb; + r_rdata = rdata; + end + + `CALIPTRA_ASSERT_NEVER(AXI_SUB_ARB_CONFLICT, r_dv && !r_hld && w_dv && !w_hld, clk, !rst_n) + // This arbiter can't deal with an err signal that asserts at + // a delay from the dv signal (as in the case of the read channel). + `CALIPTRA_ASSERT(AXI_SUB_ARB_LAT_ERR, C_LAT == 0, clk, !rst_n) + + +endmodule