-
Notifications
You must be signed in to change notification settings - Fork 44
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add AXI sub wrapper and simplex arbiter
- Loading branch information
1 parent
1645788
commit 02d9398
Showing
2 changed files
with
331 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |