mirror of
https://github.com/retroSoC/retroSoC.git
synced 2026-11-04 22:32:36 +00:00
1085 lines
48 KiB
Systemverilog
1085 lines
48 KiB
Systemverilog
// Copyright (c) 2026 Yuchi Miao <miaoyuchi@ict.ac.cn>
|
|
// SPDX-License-Identifier: MulanPSL-2.0
|
|
|
|
`include "mmap_define.svh"
|
|
|
|
module axi4_data_crossbar #(
|
|
parameter int unsigned NumMasters = 9,
|
|
parameter int unsigned NumTargets = 6,
|
|
parameter int unsigned StarvationCycles = 256,
|
|
parameter logic [NumMasters-1:0][NumTargets-2:0] ReadTargetMask = '1,
|
|
parameter logic [NumMasters-1:0][NumTargets-2:0] WriteTargetMask = '1,
|
|
parameter logic [NumMasters-1:0] AllowInstruction = '1,
|
|
parameter logic [NumMasters-1:0] RequireNoncacheable = '0
|
|
) (
|
|
// verilog_format: off -- preserve the data-plane contract columns
|
|
input logic clk_i,
|
|
input logic rst_n_i,
|
|
input logic block_new_i,
|
|
input logic [NumMasters-1:0] master_block_i,
|
|
input logic recovery_i,
|
|
input logic flush_i,
|
|
input logic fault_ready_i,
|
|
input logic [1:0] mem_pad_mode_i,
|
|
input logic [31:0] ext_h_read_base_i,
|
|
input logic [31:0] ext_h_read_limit_i,
|
|
input logic [31:0] ext_h_write_base_i,
|
|
input logic [31:0] ext_h_write_limit_i,
|
|
axi4_if.slave masters [NumMasters],
|
|
axi4_if.master targets [NumTargets],
|
|
output logic idle_o,
|
|
output logic [NumMasters-1:0] master_idle_o,
|
|
output logic [7:0] outstanding_read_o,
|
|
output logic [7:0] outstanding_write_o,
|
|
output logic fault_valid_o,
|
|
output logic [3:0] fault_master_o,
|
|
output logic [2:0] fault_target_o,
|
|
output logic [31:0] fault_addr_o,
|
|
output logic fault_write_o,
|
|
output logic [3:0] fault_reason_o,
|
|
output logic [NumMasters-1:0] monitor_master_read_accept_o,
|
|
output logic [NumMasters-1:0] monitor_master_write_accept_o,
|
|
output logic [NumMasters-1:0] monitor_master_read_beat_o,
|
|
output logic [NumMasters-1:0] monitor_master_write_beat_o,
|
|
output logic [NumMasters-1:0] monitor_master_wait_o,
|
|
output logic [NumMasters-1:0] monitor_master_promotion_o,
|
|
output logic [NumMasters-1:0][2:0] monitor_master_read_outstanding_o,
|
|
output logic [NumMasters-1:0][2:0] monitor_master_write_outstanding_o,
|
|
output logic [NumTargets-1:0] monitor_target_read_accept_o,
|
|
output logic [NumTargets-1:0] monitor_target_write_accept_o,
|
|
output logic [NumTargets-1:0] monitor_target_read_beat_o,
|
|
output logic [NumTargets-1:0] monitor_target_write_beat_o,
|
|
output logic [NumTargets-1:0] monitor_target_wait_o,
|
|
output logic [NumTargets-1:0][2:0] monitor_target_read_outstanding_o,
|
|
output logic [NumTargets-1:0][2:0] monitor_target_write_outstanding_o
|
|
// verilog_format: on
|
|
);
|
|
localparam int unsigned MasterWidth = $clog2(NumMasters);
|
|
localparam int unsigned TargetWidth = $clog2(NumTargets);
|
|
localparam int unsigned SourceIds = 8;
|
|
localparam int unsigned RouteDepth = 2;
|
|
localparam int unsigned CountWidth = 3;
|
|
localparam int unsigned AgeWidth = $clog2(StarvationCycles + 1);
|
|
|
|
localparam logic [TargetWidth-1:0] TargetSram = TargetWidth'(0);
|
|
localparam logic [TargetWidth-1:0] TargetSdram = TargetWidth'(1);
|
|
localparam logic [TargetWidth-1:0] TargetQpi = TargetWidth'(2);
|
|
localparam logic [TargetWidth-1:0] TargetOpi = TargetWidth'(3);
|
|
localparam logic [TargetWidth-1:0] TargetXpi = TargetWidth'(4);
|
|
localparam logic [TargetWidth-1:0] TargetError = TargetWidth'(5);
|
|
|
|
localparam logic [3:0] FaultUnmapped = 4'd1;
|
|
localparam logic [3:0] FaultInactivePad = 4'd2;
|
|
localparam logic [3:0] FaultAccess = 4'd3;
|
|
localparam logic [3:0] FaultProtocol = 4'd4;
|
|
|
|
typedef struct packed {
|
|
logic [6:0] id;
|
|
logic [31:0] addr;
|
|
logic [7:0] len;
|
|
logic [2:0] size;
|
|
logic [1:0] burst;
|
|
logic lock;
|
|
logic [3:0] cache;
|
|
logic [2:0] prot;
|
|
logic [3:0] qos;
|
|
logic [3:0] region;
|
|
logic user;
|
|
} addr_channel_t;
|
|
|
|
typedef struct packed {
|
|
logic [63:0] data;
|
|
logic [7:0] strb;
|
|
logic last;
|
|
logic user;
|
|
} write_channel_t;
|
|
|
|
typedef struct packed {
|
|
logic [6:0] id;
|
|
logic [1:0] resp;
|
|
logic user;
|
|
} write_resp_t;
|
|
|
|
typedef struct packed {
|
|
logic [6:0] id;
|
|
logic [63:0] data;
|
|
logic [1:0] resp;
|
|
logic last;
|
|
logic user;
|
|
} read_resp_t;
|
|
|
|
addr_channel_t m_aw [NumMasters];
|
|
addr_channel_t m_ar [NumMasters];
|
|
write_channel_t m_w [NumMasters];
|
|
write_resp_t m_b [NumMasters];
|
|
read_resp_t m_r [NumMasters];
|
|
logic [NumMasters-1:0] m_awvalid;
|
|
logic [NumMasters-1:0] m_awready;
|
|
logic [NumMasters-1:0] m_wvalid;
|
|
logic [NumMasters-1:0] m_wready;
|
|
logic [NumMasters-1:0] m_bvalid;
|
|
logic [NumMasters-1:0] m_bready;
|
|
logic [NumMasters-1:0] m_arvalid;
|
|
logic [NumMasters-1:0] m_arready;
|
|
logic [NumMasters-1:0] m_rvalid;
|
|
logic [NumMasters-1:0] m_rready;
|
|
|
|
addr_channel_t t_aw [NumTargets];
|
|
addr_channel_t t_ar [NumTargets];
|
|
write_channel_t t_w [NumTargets];
|
|
write_resp_t t_b [NumTargets];
|
|
read_resp_t t_r [NumTargets];
|
|
logic [NumTargets-1:0] t_awvalid;
|
|
logic [NumTargets-1:0] t_awready;
|
|
logic [NumTargets-1:0] t_wvalid;
|
|
logic [NumTargets-1:0] t_wready;
|
|
logic [NumTargets-1:0] t_bvalid;
|
|
logic [NumTargets-1:0] t_bready;
|
|
logic [NumTargets-1:0] t_arvalid;
|
|
logic [NumTargets-1:0] t_arready;
|
|
logic [NumTargets-1:0] t_rvalid;
|
|
logic [NumTargets-1:0] t_rready;
|
|
|
|
logic [NumTargets-1:0][ NumMasters-1:0] s_read_req;
|
|
logic [NumTargets-1:0][ NumMasters-1:0] s_write_req;
|
|
logic [NumTargets-1:0][ NumMasters-1:0] s_read_priority_req;
|
|
logic [NumTargets-1:0][ NumMasters-1:0] s_write_priority_req;
|
|
logic [NumTargets-1:0][ NumMasters-1:0] unused_read_grant;
|
|
logic [NumTargets-1:0][ NumMasters-1:0] unused_write_grant;
|
|
logic [NumTargets-1:0][MasterWidth-1:0] s_read_selected;
|
|
logic [NumTargets-1:0][MasterWidth-1:0] s_write_selected;
|
|
logic [NumTargets-1:0] s_read_grant_valid;
|
|
logic [NumTargets-1:0] s_write_grant_valid;
|
|
logic [NumTargets-1:0] s_read_capture;
|
|
logic [NumTargets-1:0] s_write_capture;
|
|
|
|
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_req;
|
|
logic [NumMasters-1:0][ NumTargets-1:0] s_read_resp_arb_req;
|
|
logic [NumMasters-1:0][ NumTargets-1:0] s_write_resp_req;
|
|
logic [NumMasters-1:0][ NumTargets-1:0] unused_read_resp_grant;
|
|
logic [NumMasters-1:0][ NumTargets-1:0] unused_write_resp_grant;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_selected;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_write_resp_selected;
|
|
logic [NumMasters-1:0] s_read_resp_valid;
|
|
logic [NumMasters-1:0] s_write_resp_valid;
|
|
logic [NumMasters-1:0] s_read_terminal;
|
|
logic [NumMasters-1:0] s_write_terminal;
|
|
logic [NumMasters-1:0] s_read_resp_lock_d, s_read_resp_lock_q;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_d;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_resp_lock_target_q;
|
|
logic [NumTargets-1:0] s_invalid_read_response;
|
|
logic [NumTargets-1:0] s_invalid_write_response;
|
|
logic [NumTargets-1:0] s_invalid_read_fault_accept;
|
|
logic [NumTargets-1:0] s_invalid_write_fault_accept;
|
|
logic s_protocol_fault_pending;
|
|
logic s_protocol_fault_event;
|
|
logic s_protocol_recovery_q;
|
|
|
|
logic [NumTargets-1:0] s_target_write_owner_full;
|
|
logic [NumTargets-1:0] s_target_write_owner_empty;
|
|
logic [NumTargets-1:0] s_target_write_owner_push;
|
|
logic [NumTargets-1:0] s_target_write_owner_pop;
|
|
logic [NumTargets-1:0][MasterWidth-1:0] s_target_write_owner_data;
|
|
logic [NumTargets-1:0][ 1:0] unused_target_write_owner_count;
|
|
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_decoded_target;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_write_decoded_target;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_routed_target;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_write_routed_target;
|
|
logic [NumMasters-1:0][ 3:0] s_read_fault_reason;
|
|
logic [NumMasters-1:0][ 3:0] s_write_fault_reason;
|
|
|
|
logic [NumMasters-1:0][CountWidth-1:0] s_master_read_count_d, s_master_read_count_q;
|
|
logic [NumMasters-1:0][CountWidth-1:0] s_master_write_count_d, s_master_write_count_q;
|
|
logic [NumTargets-1:0][CountWidth-1:0] s_target_read_count_d, s_target_read_count_q;
|
|
logic [NumTargets-1:0][CountWidth-1:0] s_target_write_count_d, s_target_write_count_q;
|
|
logic [NumMasters-1:0][SourceIds-1:0] s_read_id_busy_d, s_read_id_busy_q;
|
|
logic [NumMasters-1:0][SourceIds-1:0] s_write_id_busy_d, s_write_id_busy_q;
|
|
logic [NumTargets-1:0][NumMasters-1:0][AgeWidth-1:0] s_read_age_d, s_read_age_q;
|
|
logic [NumTargets-1:0][NumMasters-1:0][AgeWidth-1:0] s_write_age_d, s_write_age_q;
|
|
|
|
logic [NumMasters-1:0][RouteDepth-1:0][TargetWidth-1:0] s_write_route_d;
|
|
logic [NumMasters-1:0][RouteDepth-1:0][TargetWidth-1:0] s_write_route_q;
|
|
logic [NumMasters-1:0] s_route_read_ptr_d, s_route_read_ptr_q;
|
|
logic [NumMasters-1:0] s_route_write_ptr_d, s_route_write_ptr_q;
|
|
logic [NumMasters-1:0][1:0] s_route_count_d, s_route_count_q;
|
|
logic [NumMasters-1:0] s_write_data_terminal;
|
|
|
|
logic [NumMasters-1:0] s_read_accept;
|
|
logic [NumMasters-1:0] s_write_accept;
|
|
logic [NumMasters-1:0] s_read_accept_pre;
|
|
logic [NumMasters-1:0] s_write_accept_pre;
|
|
logic [NumMasters-1:0] s_read_fault_accept;
|
|
logic [NumMasters-1:0] s_write_fault_accept;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_read_accept_target;
|
|
logic [NumMasters-1:0][TargetWidth-1:0] s_write_accept_target;
|
|
logic [NumMasters-1:0][ 2:0] s_read_accept_id;
|
|
logic [NumMasters-1:0][ 2:0] s_write_accept_id;
|
|
logic [NumMasters-1:0][ 2:0] s_read_complete_id;
|
|
logic [NumMasters-1:0][ 2:0] s_write_complete_id;
|
|
logic [NumTargets-1:0][ 4:0] s_read_max_priority;
|
|
logic [NumTargets-1:0][ 4:0] s_write_max_priority;
|
|
logic s_fault_valid_d;
|
|
logic [ 3:0] s_fault_master_d;
|
|
logic [ 2:0] s_fault_target_d;
|
|
logic [ 31:0] s_fault_addr_d;
|
|
logic s_fault_write_d;
|
|
logic [ 3:0] s_fault_reason_d;
|
|
logic s_fault_slot_ready;
|
|
|
|
function automatic logic [TargetWidth-1:0] decode_target(input logic [31:0] addr,
|
|
input logic [1:0] pad_mode);
|
|
if (`SOC_ADDR_IS_SRAM(addr)) return TargetSram;
|
|
if (`SOC_ADDR_IS_SDRAM(addr)) return TargetSdram;
|
|
if (`SOC_ADDR_IS_PSRAM(addr)) return (pad_mode == 2'd1) ? TargetQpi : TargetError;
|
|
if (`SOC_ADDR_IS_OPIPSRAM(addr)) return (pad_mode == 2'd2) ? TargetOpi : TargetError;
|
|
if (`SOC_ADDR_IS_FLASH(addr) || `SOC_ADDR_IS_XPI(addr)) return TargetXpi;
|
|
return TargetError;
|
|
endfunction
|
|
|
|
function automatic logic [3:0] decode_fault_reason(input logic [31:0] addr,
|
|
input logic [1:0] pad_mode);
|
|
if (`SOC_ADDR_IS_PSRAM(addr) && (pad_mode != 2'd1)) return FaultInactivePad;
|
|
if (`SOC_ADDR_IS_OPIPSRAM(addr) && (pad_mode != 2'd2)) return FaultInactivePad;
|
|
if (!(
|
|
`SOC_ADDR_IS_SRAM(addr)
|
|
||
|
|
`SOC_ADDR_IS_SDRAM(addr)
|
|
||
|
|
`SOC_ADDR_IS_PSRAM(addr)
|
|
||
|
|
`SOC_ADDR_IS_OPIPSRAM(addr)
|
|
||
|
|
`SOC_ADDR_IS_FLASH(addr)
|
|
||
|
|
`SOC_ADDR_IS_XPI(addr)
|
|
)) begin
|
|
return FaultUnmapped;
|
|
end
|
|
return 4'd0;
|
|
endfunction
|
|
|
|
function automatic logic access_allowed(
|
|
input int unsigned master, input logic [TargetWidth-1:0] target, input logic [31:0] addr,
|
|
input logic write_access, input logic [2:0] prot, input logic [3:0] cache,
|
|
input logic [31:0] ext_read_base, input logic [31:0] ext_read_limit,
|
|
input logic [31:0] ext_write_base, input logic [31:0] ext_write_limit);
|
|
if (target == TargetError) return 1'b1;
|
|
if (write_access && !WriteTargetMask[master][target]) return 1'b0;
|
|
if (!write_access && !ReadTargetMask[master][target]) return 1'b0;
|
|
if (prot[2] && !AllowInstruction[master]) return 1'b0;
|
|
if (RequireNoncacheable[master] && (cache != 4'd0)) return 1'b0;
|
|
if ((master == 7) && write_access && ((addr < ext_write_base) || (addr > ext_write_limit)))
|
|
return 1'b0;
|
|
if ((master == 7) && !write_access && ((addr < ext_read_base) || (addr > ext_read_limit)))
|
|
return 1'b0;
|
|
return 1'b1;
|
|
endfunction
|
|
|
|
function automatic logic burst_legal(input logic [31:0] addr, input logic [7:0] len,
|
|
input logic [2:0] size, input logic [1:0] burst,
|
|
input logic lock);
|
|
logic [32:0] beat_bytes;
|
|
logic [32:0] burst_bytes;
|
|
logic [32:0] last_addr;
|
|
logic [32:0] window_limit;
|
|
beat_bytes = 33'd1 << size;
|
|
burst_bytes = beat_bytes * ({25'd0, len} + 1'b1);
|
|
last_addr = (burst == 2'b00) ?
|
|
({1'b0, addr} + beat_bytes - 1'b1) :
|
|
({1'b0, addr} + burst_bytes - 1'b1);
|
|
window_limit = {1'b0, addr[31:12], 12'd0} + 33'd4096;
|
|
return !lock && (size <= 3'd3) &&
|
|
((burst == 2'b00) || (burst == 2'b01) ||
|
|
((burst == 2'b10) &&
|
|
((len == 8'd1) || (len == 8'd3) || (len == 8'd7) || (len == 8'd15)))) &&
|
|
(last_addr < window_limit);
|
|
endfunction
|
|
|
|
function automatic logic [CountWidth-1:0] master_read_limit(input int unsigned master);
|
|
if ((master <= 2) || (master == 7)) return CountWidth'(4);
|
|
if ((master == 3) || (master == 4)) return CountWidth'(2);
|
|
if ((master == 5) || (master == 6) || (master == 8)) return CountWidth'(1);
|
|
return '0;
|
|
endfunction
|
|
|
|
function automatic logic [CountWidth-1:0] master_write_limit(input int unsigned master);
|
|
if ((master == 1) || (master == 2) || (master == 7)) return CountWidth'(2);
|
|
if (((master >= 3) && (master <= 6)) || (master == 8)) return CountWidth'(1);
|
|
return '0;
|
|
endfunction
|
|
|
|
function automatic logic [CountWidth-1:0] target_read_limit(input logic [TargetWidth-1:0] target);
|
|
if ((target == TargetSram) || (target == TargetSdram)) return CountWidth'(4);
|
|
return CountWidth'(1);
|
|
endfunction
|
|
|
|
function automatic logic [CountWidth-1:0] target_write_limit(
|
|
input logic [TargetWidth-1:0] target);
|
|
if ((target == TargetSram) || (target == TargetSdram)) return CountWidth'(2);
|
|
return CountWidth'(1);
|
|
endfunction
|
|
|
|
function automatic logic [4:0] master_priority(input int unsigned master,
|
|
input logic [3:0] request_qos, input logic aged,
|
|
input logic recovery);
|
|
logic [3:0] base_priority;
|
|
unique case (master)
|
|
0, 1: base_priority = 4'd12;
|
|
3, 4: base_priority = 4'd10;
|
|
2, 6, 7, 8: base_priority = 4'd8;
|
|
5: base_priority = recovery ? 4'd15 : 4'd2;
|
|
default: base_priority = 4'd0;
|
|
endcase
|
|
if (recovery && (master == 5)) return 5'd31;
|
|
if (aged) return 5'd16;
|
|
if (master == 8) return {1'b0, base_priority};
|
|
return {1'b0, (request_qos > base_priority) ? request_qos : base_priority};
|
|
endfunction
|
|
|
|
for (genvar master = 0; master < NumMasters; master++) begin : gen_master_ports
|
|
assign m_aw[master] = {
|
|
masters[master].awid,
|
|
masters[master].awaddr,
|
|
masters[master].awlen,
|
|
masters[master].awsize,
|
|
masters[master].awburst,
|
|
masters[master].awlock,
|
|
masters[master].awcache,
|
|
masters[master].awprot,
|
|
masters[master].awqos,
|
|
masters[master].awregion,
|
|
masters[master].awuser
|
|
};
|
|
assign m_awvalid[master] = masters[master].awvalid;
|
|
assign masters[master].awready = m_awready[master];
|
|
assign m_w[master] = {
|
|
masters[master].wdata, masters[master].wstrb, masters[master].wlast, masters[master].wuser
|
|
};
|
|
assign m_wvalid[master] = masters[master].wvalid;
|
|
assign masters[master].wready = m_wready[master];
|
|
assign masters[master].bid = m_b[master].id;
|
|
assign masters[master].bresp = m_b[master].resp;
|
|
assign masters[master].buser = m_b[master].user;
|
|
assign masters[master].bvalid = m_bvalid[master];
|
|
assign m_bready[master] = masters[master].bready;
|
|
assign m_ar[master] = {
|
|
masters[master].arid,
|
|
masters[master].araddr,
|
|
masters[master].arlen,
|
|
masters[master].arsize,
|
|
masters[master].arburst,
|
|
masters[master].arlock,
|
|
masters[master].arcache,
|
|
masters[master].arprot,
|
|
masters[master].arqos,
|
|
masters[master].arregion,
|
|
masters[master].aruser
|
|
};
|
|
assign m_arvalid[master] = masters[master].arvalid;
|
|
assign masters[master].arready = m_arready[master];
|
|
assign masters[master].rid = m_r[master].id;
|
|
assign masters[master].rdata = m_r[master].data;
|
|
assign masters[master].rresp = m_r[master].resp;
|
|
assign masters[master].rlast = m_r[master].last;
|
|
assign masters[master].ruser = m_r[master].user;
|
|
assign masters[master].rvalid = m_rvalid[master];
|
|
assign m_rready[master] = masters[master].rready;
|
|
|
|
round_robin_arbiter #(
|
|
.CLIENTS(NumTargets)
|
|
) u_read_response_arbiter (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.advance_i (s_read_terminal[master]),
|
|
.request_i (s_read_resp_arb_req[master]),
|
|
.grant_o (unused_read_resp_grant[master]),
|
|
.selected_o(s_read_resp_selected[master]),
|
|
.valid_o (s_read_resp_valid[master])
|
|
);
|
|
round_robin_arbiter #(
|
|
.CLIENTS(NumTargets)
|
|
) u_write_response_arbiter (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.advance_i (s_write_terminal[master]),
|
|
.request_i (s_write_resp_req[master]),
|
|
.grant_o (unused_write_resp_grant[master]),
|
|
.selected_o(s_write_resp_selected[master]),
|
|
.valid_o (s_write_resp_valid[master])
|
|
);
|
|
end
|
|
|
|
always_comb begin
|
|
// Keep all beats of one read burst on its selected target. AXI read
|
|
// responses may complete out of order by ID, but beats of a burst must
|
|
// not be interleaved with another target's burst on the same master.
|
|
s_read_resp_arb_req = s_read_resp_req;
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (s_read_resp_lock_q[master]) begin
|
|
s_read_resp_arb_req[master] = '0;
|
|
s_read_resp_arb_req[master][s_read_resp_lock_target_q[master]] =
|
|
s_read_resp_req[master][s_read_resp_lock_target_q[master]];
|
|
end
|
|
end
|
|
end
|
|
|
|
for (genvar target = 0; target < NumTargets; target++) begin : gen_target_ports
|
|
assign targets[target].awid = t_aw[target].id;
|
|
assign targets[target].awaddr = t_aw[target].addr;
|
|
assign targets[target].awlen = t_aw[target].len;
|
|
assign targets[target].awsize = t_aw[target].size;
|
|
assign targets[target].awburst = t_aw[target].burst;
|
|
assign targets[target].awlock = t_aw[target].lock;
|
|
assign targets[target].awcache = t_aw[target].cache;
|
|
assign targets[target].awprot = t_aw[target].prot;
|
|
assign targets[target].awqos = t_aw[target].qos;
|
|
assign targets[target].awregion = t_aw[target].region;
|
|
assign targets[target].awuser = t_aw[target].user;
|
|
assign targets[target].awvalid = t_awvalid[target];
|
|
assign t_awready[target] = targets[target].awready;
|
|
assign targets[target].wdata = t_w[target].data;
|
|
assign targets[target].wstrb = t_w[target].strb;
|
|
assign targets[target].wlast = t_w[target].last;
|
|
assign targets[target].wuser = t_w[target].user;
|
|
assign targets[target].wvalid = t_wvalid[target];
|
|
assign t_wready[target] = targets[target].wready;
|
|
assign t_b[target] = {targets[target].bid, targets[target].bresp, targets[target].buser};
|
|
assign t_bvalid[target] = targets[target].bvalid;
|
|
assign targets[target].bready = t_bready[target];
|
|
assign targets[target].arid = t_ar[target].id;
|
|
assign targets[target].araddr = t_ar[target].addr;
|
|
assign targets[target].arlen = t_ar[target].len;
|
|
assign targets[target].arsize = t_ar[target].size;
|
|
assign targets[target].arburst = t_ar[target].burst;
|
|
assign targets[target].arlock = t_ar[target].lock;
|
|
assign targets[target].arcache = t_ar[target].cache;
|
|
assign targets[target].arprot = t_ar[target].prot;
|
|
assign targets[target].arqos = t_ar[target].qos;
|
|
assign targets[target].arregion = t_ar[target].region;
|
|
assign targets[target].aruser = t_ar[target].user;
|
|
assign targets[target].arvalid = t_arvalid[target];
|
|
assign t_arready[target] = targets[target].arready;
|
|
assign t_r[target] = {
|
|
targets[target].rid,
|
|
targets[target].rdata,
|
|
targets[target].rresp,
|
|
targets[target].rlast,
|
|
targets[target].ruser
|
|
};
|
|
assign t_rvalid[target] = targets[target].rvalid;
|
|
assign targets[target].rready = t_rready[target];
|
|
|
|
round_robin_arbiter #(
|
|
.CLIENTS(NumMasters)
|
|
) u_read_address_arbiter (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.advance_i (s_read_capture[target]),
|
|
.request_i (s_read_priority_req[target]),
|
|
.grant_o (unused_read_grant[target]),
|
|
.selected_o(s_read_selected[target]),
|
|
.valid_o (s_read_grant_valid[target])
|
|
);
|
|
round_robin_arbiter #(
|
|
.CLIENTS(NumMasters)
|
|
) u_write_address_arbiter (
|
|
.clk_i (clk_i),
|
|
.rst_n_i (rst_n_i),
|
|
.advance_i (s_write_capture[target]),
|
|
.request_i (s_write_priority_req[target]),
|
|
.grant_o (unused_write_grant[target]),
|
|
.selected_o(s_write_selected[target]),
|
|
.valid_o (s_write_grant_valid[target])
|
|
);
|
|
|
|
fifo #(
|
|
.DATA_WIDTH (MasterWidth),
|
|
.BUFFER_DEPTH(RouteDepth)
|
|
) u_write_owner_fifo (
|
|
.clk_i (clk_i),
|
|
.rst_n_i(rst_n_i),
|
|
.flush_i(flush_i),
|
|
.push_i (s_target_write_owner_push[target]),
|
|
.full_o (s_target_write_owner_full[target]),
|
|
.dat_i (s_write_selected[target]),
|
|
.pop_i (s_target_write_owner_pop[target]),
|
|
.empty_o(s_target_write_owner_empty[target]),
|
|
.dat_o (s_target_write_owner_data[target]),
|
|
.cnt_o (unused_target_write_owner_count[target])
|
|
);
|
|
end
|
|
|
|
|
|
always_comb begin
|
|
s_read_req = '0;
|
|
s_write_req = '0;
|
|
s_read_decoded_target = '0;
|
|
s_write_decoded_target = '0;
|
|
s_read_routed_target = '0;
|
|
s_write_routed_target = '0;
|
|
s_read_fault_reason = '0;
|
|
s_write_fault_reason = '0;
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
s_read_decoded_target[master] = decode_target(m_ar[master].addr, mem_pad_mode_i);
|
|
s_write_decoded_target[master] = decode_target(m_aw[master].addr, mem_pad_mode_i);
|
|
s_read_fault_reason[master] = decode_fault_reason(m_ar[master].addr, mem_pad_mode_i);
|
|
s_write_fault_reason[master] = decode_fault_reason(m_aw[master].addr, mem_pad_mode_i);
|
|
if ((s_read_fault_reason[master] == 4'd0) && !access_allowed(
|
|
master,
|
|
s_read_decoded_target[master],
|
|
m_ar[master].addr,
|
|
1'b0,
|
|
m_ar[master].prot,
|
|
m_ar[master].cache,
|
|
ext_h_read_base_i,
|
|
ext_h_read_limit_i,
|
|
ext_h_write_base_i,
|
|
ext_h_write_limit_i
|
|
)) begin
|
|
s_read_fault_reason[master] = FaultAccess;
|
|
end else if (!burst_legal(
|
|
m_ar[master].addr,
|
|
m_ar[master].len,
|
|
m_ar[master].size,
|
|
m_ar[master].burst,
|
|
m_ar[master].lock
|
|
)) begin
|
|
s_read_fault_reason[master] = FaultProtocol;
|
|
end
|
|
if ((s_write_fault_reason[master] == 4'd0) && !access_allowed(
|
|
master,
|
|
s_write_decoded_target[master],
|
|
m_aw[master].addr,
|
|
1'b1,
|
|
m_aw[master].prot,
|
|
m_aw[master].cache,
|
|
ext_h_read_base_i,
|
|
ext_h_read_limit_i,
|
|
ext_h_write_base_i,
|
|
ext_h_write_limit_i
|
|
)) begin
|
|
s_write_fault_reason[master] = FaultAccess;
|
|
end else if (!burst_legal(
|
|
m_aw[master].addr,
|
|
m_aw[master].len,
|
|
m_aw[master].size,
|
|
m_aw[master].burst,
|
|
m_aw[master].lock
|
|
)) begin
|
|
s_write_fault_reason[master] = FaultProtocol;
|
|
end
|
|
s_read_routed_target[master] = (s_read_fault_reason[master] == 4'd0) ?
|
|
s_read_decoded_target[master] : TargetError;
|
|
s_write_routed_target[master] = (s_write_fault_reason[master] == 4'd0) ?
|
|
s_write_decoded_target[master] : TargetError;
|
|
if (!block_new_i && !s_protocol_recovery_q && !s_protocol_fault_pending &&
|
|
!master_block_i[master] && m_arvalid[master] &&
|
|
(s_target_read_count_q[s_read_routed_target[master]] <
|
|
target_read_limit(
|
|
s_read_routed_target[master]
|
|
)) && (s_master_read_count_q[master] <
|
|
((s_read_fault_reason[master] != 4'd0) ? CountWidth'(1) : master_read_limit(
|
|
master
|
|
))) && !s_read_id_busy_q[master][m_ar[master].id[2:0]]) begin
|
|
s_read_req[s_read_routed_target[master]][master] = 1'b1;
|
|
end
|
|
if (!block_new_i && !s_protocol_recovery_q && !s_protocol_fault_pending &&
|
|
!master_block_i[master] && m_awvalid[master] &&
|
|
!s_target_write_owner_full[s_write_routed_target[master]] &&
|
|
(s_target_write_count_q[s_write_routed_target[master]] <
|
|
target_write_limit(
|
|
s_write_routed_target[master]
|
|
)) && (s_master_write_count_q[master] <
|
|
((s_write_fault_reason[master] != 4'd0) ? CountWidth'(1) : master_write_limit(
|
|
master
|
|
))) && (s_route_count_q[master] < 2'(RouteDepth)) &&
|
|
!s_write_id_busy_q[master][m_aw[master].id[2:0]]) begin
|
|
s_write_req[s_write_routed_target[master]][master] = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_read_priority_req = '0;
|
|
s_write_priority_req = '0;
|
|
s_read_max_priority = '0;
|
|
s_write_max_priority = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (s_read_req[target][master] && (master_priority(
|
|
master,
|
|
m_ar[master].qos,
|
|
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
) > s_read_max_priority[target])) begin
|
|
s_read_max_priority[target] = master_priority(
|
|
master,
|
|
m_ar[master].qos,
|
|
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
);
|
|
end
|
|
if (s_write_req[target][master] && (master_priority(
|
|
master,
|
|
m_aw[master].qos,
|
|
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
) > s_write_max_priority[target])) begin
|
|
s_write_max_priority[target] = master_priority(
|
|
master,
|
|
m_aw[master].qos,
|
|
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
);
|
|
end
|
|
end
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
s_read_priority_req[target][master] = s_read_req[target][master] && (master_priority(
|
|
master,
|
|
m_ar[master].qos,
|
|
s_read_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
) == s_read_max_priority[target]);
|
|
s_write_priority_req[target][master] = s_write_req[target][master] && (master_priority(
|
|
master,
|
|
m_aw[master].qos,
|
|
s_write_age_q[target][master] == AgeWidth'(StarvationCycles),
|
|
recovery_i
|
|
) == s_write_max_priority[target]);
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_read_accept_pre = '0;
|
|
s_write_accept_pre = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (s_read_grant_valid[target]) begin
|
|
automatic logic [MasterWidth-1:0] owner = s_read_selected[target];
|
|
s_read_accept_pre[owner] = m_arvalid[owner] && t_arready[target];
|
|
end
|
|
if (s_write_grant_valid[target]) begin
|
|
automatic logic [MasterWidth-1:0] owner = s_write_selected[target];
|
|
s_write_accept_pre[owner] = m_awvalid[owner] && t_awready[target];
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
m_arready = '0;
|
|
t_ar = '{default: '0};
|
|
t_arvalid = '0;
|
|
s_read_capture = '0;
|
|
s_read_accept = '0;
|
|
s_read_accept_target = '0;
|
|
s_read_accept_id = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (s_read_grant_valid[target]) begin
|
|
automatic logic [MasterWidth-1:0] owner = s_read_selected[target];
|
|
t_ar[target] = m_ar[owner];
|
|
if (owner == MasterWidth'(8)) t_ar[target].qos = 4'd0;
|
|
if ((s_read_fault_reason[owner] == 4'd0) || s_read_fault_accept[owner]) begin
|
|
t_arvalid[target] = m_arvalid[owner];
|
|
m_arready[owner] = t_arready[target];
|
|
s_read_capture[target] = t_arvalid[target] && t_arready[target];
|
|
if (s_read_capture[target]) begin
|
|
s_read_accept[owner] = 1'b1;
|
|
s_read_accept_target[owner] = TargetWidth'(target);
|
|
s_read_accept_id[owner] = m_ar[owner].id[2:0];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
m_awready = '0;
|
|
t_aw = '{default: '0};
|
|
t_awvalid = '0;
|
|
s_write_capture = '0;
|
|
s_target_write_owner_push = '0;
|
|
s_write_accept = '0;
|
|
s_write_accept_target = '0;
|
|
s_write_accept_id = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (s_write_grant_valid[target]) begin
|
|
automatic logic [MasterWidth-1:0] owner = s_write_selected[target];
|
|
t_aw[target] = m_aw[owner];
|
|
if (owner == MasterWidth'(8)) t_aw[target].qos = 4'd0;
|
|
if ((s_write_fault_reason[owner] == 4'd0) || s_write_fault_accept[owner]) begin
|
|
t_awvalid[target] = m_awvalid[owner];
|
|
m_awready[owner] = t_awready[target];
|
|
s_write_capture[target] = t_awvalid[target] && t_awready[target];
|
|
s_target_write_owner_push[target] = s_write_capture[target];
|
|
if (s_write_capture[target]) begin
|
|
s_write_accept[owner] = 1'b1;
|
|
s_write_accept_target[owner] = TargetWidth'(target);
|
|
s_write_accept_id[owner] = m_aw[owner].id[2:0];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
m_wready = '0;
|
|
t_w = '{default: '0};
|
|
t_wvalid = '0;
|
|
s_write_data_terminal = '0;
|
|
s_target_write_owner_pop = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (!s_target_write_owner_empty[target]) begin
|
|
automatic logic [MasterWidth-1:0] master = s_target_write_owner_data[target];
|
|
if ((s_route_count_q[master] != 2'd0) &&
|
|
(s_write_route_q[master][s_route_read_ptr_q[master]] == TargetWidth'(target))) begin
|
|
t_w[target] = m_w[master];
|
|
t_wvalid[target] = m_wvalid[master];
|
|
m_wready[master] = t_wready[target];
|
|
s_write_data_terminal[master] = t_wvalid[target] && t_wready[target] && t_w[target].last;
|
|
s_target_write_owner_pop[target] = s_write_data_terminal[master];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_read_resp_req = '0;
|
|
s_write_resp_req = '0;
|
|
s_invalid_read_response = '0;
|
|
s_invalid_write_response = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (t_rvalid[target] && !flush_i) begin
|
|
if (t_r[target].id[6:3] < 4'(NumMasters)) begin
|
|
s_read_resp_req[t_r[target].id[6:3]][target] = 1'b1;
|
|
end else begin
|
|
s_invalid_read_response[target] = 1'b1;
|
|
end
|
|
end
|
|
if (t_bvalid[target] && !flush_i) begin
|
|
if (t_b[target].id[6:3] < 4'(NumMasters)) begin
|
|
s_write_resp_req[t_b[target].id[6:3]][target] = 1'b1;
|
|
end else begin
|
|
s_invalid_write_response[target] = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
assign s_protocol_fault_pending = (|s_invalid_read_response) || (|s_invalid_write_response);
|
|
assign s_fault_slot_ready = !fault_valid_o || fault_ready_i;
|
|
|
|
always_comb begin
|
|
s_fault_valid_d = 1'b0;
|
|
s_fault_master_d = '0;
|
|
s_fault_target_d = '0;
|
|
s_fault_addr_d = '0;
|
|
s_fault_write_d = 1'b0;
|
|
s_fault_reason_d = '0;
|
|
s_invalid_read_fault_accept = '0;
|
|
s_invalid_write_fault_accept = '0;
|
|
s_read_fault_accept = '0;
|
|
s_write_fault_accept = '0;
|
|
if (s_fault_slot_ready) begin
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (!s_fault_valid_d && !s_protocol_recovery_q && s_invalid_read_response[target]) begin
|
|
s_fault_valid_d = 1'b1;
|
|
s_fault_master_d = t_r[target].id[6:3];
|
|
s_fault_target_d = 3'(target);
|
|
s_fault_addr_d = '0;
|
|
s_fault_write_d = 1'b0;
|
|
s_fault_reason_d = FaultProtocol;
|
|
s_invalid_read_fault_accept[target] = 1'b1;
|
|
end
|
|
if (!s_fault_valid_d && !s_protocol_recovery_q && s_invalid_write_response[target]) begin
|
|
s_fault_valid_d = 1'b1;
|
|
s_fault_master_d = t_b[target].id[6:3];
|
|
s_fault_target_d = 3'(target);
|
|
s_fault_addr_d = '0;
|
|
s_fault_write_d = 1'b1;
|
|
s_fault_reason_d = FaultProtocol;
|
|
s_invalid_write_fault_accept[target] = 1'b1;
|
|
end
|
|
end
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (!s_fault_valid_d && s_read_accept_pre[master] &&
|
|
(s_read_fault_reason[master] != 4'd0)) begin
|
|
s_fault_valid_d = 1'b1;
|
|
s_fault_master_d = 4'(master);
|
|
s_fault_target_d = 3'(s_read_decoded_target[master]);
|
|
s_fault_addr_d = m_ar[master].addr;
|
|
s_fault_write_d = 1'b0;
|
|
s_fault_reason_d = s_read_fault_reason[master];
|
|
s_read_fault_accept[master] = 1'b1;
|
|
end
|
|
if (!s_fault_valid_d && s_write_accept_pre[master] &&
|
|
(s_write_fault_reason[master] != 4'd0)) begin
|
|
s_fault_valid_d = 1'b1;
|
|
s_fault_master_d = 4'(master);
|
|
s_fault_target_d = 3'(s_write_decoded_target[master]);
|
|
s_fault_addr_d = m_aw[master].addr;
|
|
s_fault_write_d = 1'b1;
|
|
s_fault_reason_d = s_write_fault_reason[master];
|
|
s_write_fault_accept[master] = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
assign s_protocol_fault_event = (|s_invalid_read_fault_accept) || (|s_invalid_write_fault_accept);
|
|
|
|
always_comb begin
|
|
m_r = '{default: '0};
|
|
m_rvalid = '0;
|
|
t_rready = flush_i ? '1 : '0;
|
|
s_read_terminal = '0;
|
|
s_read_complete_id = '0;
|
|
m_b = '{default: '0};
|
|
m_bvalid = '0;
|
|
t_bready = flush_i ? '1 : '0;
|
|
s_write_terminal = '0;
|
|
s_write_complete_id = '0;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
if (s_invalid_read_fault_accept[target]) t_rready[target] = 1'b1;
|
|
if (s_invalid_write_fault_accept[target]) t_bready[target] = 1'b1;
|
|
end
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (s_read_resp_valid[master]) begin
|
|
automatic logic [TargetWidth-1:0] target = s_read_resp_selected[master];
|
|
m_r[master] = t_r[target];
|
|
m_rvalid[master] = t_rvalid[target];
|
|
t_rready[target] = m_rready[master];
|
|
s_read_terminal[master] = m_rvalid[master] && m_rready[master] && m_r[master].last;
|
|
s_read_complete_id[master] = m_r[master].id[2:0];
|
|
end
|
|
if (s_write_resp_valid[master]) begin
|
|
automatic logic [TargetWidth-1:0] target = s_write_resp_selected[master];
|
|
m_b[master] = t_b[target];
|
|
m_bvalid[master] = t_bvalid[target];
|
|
t_bready[target] = m_bready[master];
|
|
s_write_terminal[master] = m_bvalid[master] && m_bready[master];
|
|
s_write_complete_id[master] = m_b[master].id[2:0];
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_master_read_count_d = s_master_read_count_q;
|
|
s_master_write_count_d = s_master_write_count_q;
|
|
s_target_read_count_d = s_target_read_count_q;
|
|
s_target_write_count_d = s_target_write_count_q;
|
|
s_read_id_busy_d = s_read_id_busy_q;
|
|
s_write_id_busy_d = s_write_id_busy_q;
|
|
s_read_resp_lock_d = s_read_resp_lock_q;
|
|
s_read_resp_lock_target_d = s_read_resp_lock_target_q;
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (s_read_terminal[master]) begin
|
|
s_master_read_count_d[master] = s_master_read_count_d[master] - 1'b1;
|
|
s_target_read_count_d[s_read_resp_selected[master]] =
|
|
s_target_read_count_d[s_read_resp_selected[master]] - 1'b1;
|
|
s_read_id_busy_d[master][s_read_complete_id[master]] = 1'b0;
|
|
s_read_resp_lock_d[master] = 1'b0;
|
|
end else if (!s_read_resp_lock_q[master] && s_read_resp_valid[master]) begin
|
|
s_read_resp_lock_d[master] = 1'b1;
|
|
s_read_resp_lock_target_d[master] = s_read_resp_selected[master];
|
|
end
|
|
if (s_write_terminal[master]) begin
|
|
s_master_write_count_d[master] = s_master_write_count_d[master] - 1'b1;
|
|
s_target_write_count_d[s_write_resp_selected[master]] =
|
|
s_target_write_count_d[s_write_resp_selected[master]] - 1'b1;
|
|
s_write_id_busy_d[master][s_write_complete_id[master]] = 1'b0;
|
|
end
|
|
if (s_read_accept[master]) begin
|
|
s_master_read_count_d[master] = s_master_read_count_d[master] + 1'b1;
|
|
s_target_read_count_d[s_read_accept_target[master]] =
|
|
s_target_read_count_d[s_read_accept_target[master]] + 1'b1;
|
|
s_read_id_busy_d[master][s_read_accept_id[master]] = 1'b1;
|
|
end
|
|
if (s_write_accept[master]) begin
|
|
s_master_write_count_d[master] = s_master_write_count_d[master] + 1'b1;
|
|
s_target_write_count_d[s_write_accept_target[master]] =
|
|
s_target_write_count_d[s_write_accept_target[master]] + 1'b1;
|
|
s_write_id_busy_d[master][s_write_accept_id[master]] = 1'b1;
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_write_route_d = s_write_route_q;
|
|
s_route_read_ptr_d = s_route_read_ptr_q;
|
|
s_route_write_ptr_d = s_route_write_ptr_q;
|
|
s_route_count_d = s_route_count_q;
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
unique case ({
|
|
s_write_accept[master], s_write_data_terminal[master]
|
|
})
|
|
2'b10: s_route_count_d[master] = s_route_count_q[master] + 1'b1;
|
|
2'b01: s_route_count_d[master] = s_route_count_q[master] - 1'b1;
|
|
default: s_route_count_d[master] = s_route_count_q[master];
|
|
endcase
|
|
if (s_write_accept[master]) begin
|
|
s_write_route_d[master][s_route_write_ptr_q[master]] = s_write_accept_target[master];
|
|
s_route_write_ptr_d[master] = ~s_route_write_ptr_q[master];
|
|
end
|
|
if (s_write_data_terminal[master]) begin
|
|
s_route_read_ptr_d[master] = ~s_route_read_ptr_q[master];
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
s_read_age_d = s_read_age_q;
|
|
s_write_age_d = s_write_age_q;
|
|
for (int target = 0; target < NumTargets; target++) begin
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
if (!s_read_req[target][master] ||
|
|
(s_read_capture[target] && (s_read_selected[target] == MasterWidth'(master)))) begin
|
|
s_read_age_d[target][master] = '0;
|
|
end else if (s_read_age_q[target][master] < AgeWidth'(StarvationCycles)) begin
|
|
s_read_age_d[target][master] = s_read_age_q[target][master] + 1'b1;
|
|
end
|
|
if (!s_write_req[target][master] ||
|
|
(s_write_capture[target] && (s_write_selected[target] == MasterWidth'(master)))) begin
|
|
s_write_age_d[target][master] = '0;
|
|
end else if (s_write_age_q[target][master] < AgeWidth'(StarvationCycles)) begin
|
|
s_write_age_d[target][master] = s_write_age_q[target][master] + 1'b1;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin
|
|
outstanding_read_o = '0;
|
|
outstanding_write_o = '0;
|
|
for (int master = 0; master < NumMasters; master++) begin
|
|
outstanding_read_o = outstanding_read_o + 8'(s_master_read_count_q[master]);
|
|
outstanding_write_o = outstanding_write_o + 8'(s_master_write_count_q[master]);
|
|
end
|
|
end
|
|
|
|
assign idle_o = !s_protocol_recovery_q && (outstanding_read_o == 8'd0) &&
|
|
(outstanding_write_o == 8'd0) && !(|s_route_count_q);
|
|
for (genvar master = 0; master < NumMasters; master++) begin : gen_master_idle
|
|
assign master_idle_o[master] = (s_master_read_count_q[master] == '0) &&
|
|
(s_master_write_count_q[master] == '0) && (s_route_count_q[master] == '0) &&
|
|
!m_arvalid[master] && !m_awvalid[master] && !m_wvalid[master];
|
|
assign monitor_master_read_accept_o[master] = s_read_accept[master];
|
|
assign monitor_master_write_accept_o[master] = s_write_accept[master];
|
|
assign monitor_master_read_beat_o[master] = m_rvalid[master] && m_rready[master];
|
|
assign monitor_master_write_beat_o[master] = m_wvalid[master] && m_wready[master];
|
|
assign monitor_master_wait_o[master] =
|
|
(m_arvalid[master] && !m_arready[master]) ||
|
|
(m_awvalid[master] && !m_awready[master]) ||
|
|
(m_wvalid[master] && !m_wready[master]);
|
|
assign monitor_master_promotion_o[master] =
|
|
(s_read_accept[master] &&
|
|
(s_read_age_q[s_read_accept_target[master]][master] == AgeWidth'(StarvationCycles))) ||
|
|
(s_write_accept[master] &&
|
|
(s_write_age_q[s_write_accept_target[master]][master] == AgeWidth'(StarvationCycles)));
|
|
assign monitor_master_read_outstanding_o[master] = s_master_read_count_q[master];
|
|
assign monitor_master_write_outstanding_o[master] = s_master_write_count_q[master];
|
|
end
|
|
for (genvar target = 0; target < NumTargets; target++) begin : gen_target_monitor
|
|
assign monitor_target_read_accept_o[target] = s_read_capture[target];
|
|
assign monitor_target_write_accept_o[target] = s_write_capture[target];
|
|
assign monitor_target_read_beat_o[target] = t_rvalid[target] && t_rready[target];
|
|
assign monitor_target_write_beat_o[target] = t_wvalid[target] && t_wready[target];
|
|
assign monitor_target_wait_o[target] =
|
|
(t_arvalid[target] && !t_arready[target]) ||
|
|
(t_awvalid[target] && !t_awready[target]) ||
|
|
(t_wvalid[target] && !t_wready[target]) ||
|
|
(t_rvalid[target] && !t_rready[target]) ||
|
|
(t_bvalid[target] && !t_bready[target]);
|
|
assign monitor_target_read_outstanding_o[target] = s_target_read_count_q[target];
|
|
assign monitor_target_write_outstanding_o[target] = s_target_write_count_q[target];
|
|
end
|
|
|
|
always_ff @(posedge clk_i or negedge rst_n_i) begin
|
|
if (!rst_n_i) begin
|
|
s_master_read_count_q <= '0;
|
|
s_master_write_count_q <= '0;
|
|
s_target_read_count_q <= '0;
|
|
s_target_write_count_q <= '0;
|
|
s_read_id_busy_q <= '0;
|
|
s_write_id_busy_q <= '0;
|
|
s_read_resp_lock_q <= '0;
|
|
s_read_resp_lock_target_q <= '0;
|
|
s_write_route_q <= '0;
|
|
s_route_read_ptr_q <= '0;
|
|
s_route_write_ptr_q <= '0;
|
|
s_route_count_q <= '0;
|
|
s_read_age_q <= '0;
|
|
s_write_age_q <= '0;
|
|
s_protocol_recovery_q <= 1'b0;
|
|
fault_valid_o <= 1'b0;
|
|
fault_master_o <= '0;
|
|
fault_target_o <= '0;
|
|
fault_addr_o <= '0;
|
|
fault_write_o <= 1'b0;
|
|
fault_reason_o <= '0;
|
|
end else begin
|
|
if (flush_i) begin
|
|
s_master_read_count_q <= '0;
|
|
s_master_write_count_q <= '0;
|
|
s_target_read_count_q <= '0;
|
|
s_target_write_count_q <= '0;
|
|
s_read_id_busy_q <= '0;
|
|
s_write_id_busy_q <= '0;
|
|
s_read_resp_lock_q <= '0;
|
|
s_read_resp_lock_target_q <= '0;
|
|
s_write_route_q <= '0;
|
|
s_route_read_ptr_q <= '0;
|
|
s_route_write_ptr_q <= '0;
|
|
s_route_count_q <= '0;
|
|
s_read_age_q <= '0;
|
|
s_write_age_q <= '0;
|
|
s_protocol_recovery_q <= 1'b0;
|
|
end else begin
|
|
s_master_read_count_q <= s_master_read_count_d;
|
|
s_master_write_count_q <= s_master_write_count_d;
|
|
s_target_read_count_q <= s_target_read_count_d;
|
|
s_target_write_count_q <= s_target_write_count_d;
|
|
s_read_id_busy_q <= s_read_id_busy_d;
|
|
s_write_id_busy_q <= s_write_id_busy_d;
|
|
s_read_resp_lock_q <= s_read_resp_lock_d;
|
|
s_read_resp_lock_target_q <= s_read_resp_lock_target_d;
|
|
s_write_route_q <= s_write_route_d;
|
|
s_route_read_ptr_q <= s_route_read_ptr_d;
|
|
s_route_write_ptr_q <= s_route_write_ptr_d;
|
|
s_route_count_q <= s_route_count_d;
|
|
s_read_age_q <= s_read_age_d;
|
|
s_write_age_q <= s_write_age_d;
|
|
if (s_protocol_fault_event) s_protocol_recovery_q <= 1'b1;
|
|
end
|
|
if (!fault_valid_o || fault_ready_i) begin
|
|
fault_valid_o <= s_fault_valid_d;
|
|
fault_master_o <= s_fault_master_d;
|
|
fault_target_o <= s_fault_target_d;
|
|
fault_addr_o <= s_fault_addr_d;
|
|
fault_write_o <= s_fault_write_d;
|
|
fault_reason_o <= s_fault_reason_d;
|
|
end
|
|
end
|
|
end
|
|
|
|
`ifndef SYNTHESIS
|
|
always_ff @(posedge clk_i) begin
|
|
if (rst_n_i && $test$plusargs("trace_mgmt")) begin
|
|
if (m_arvalid[5] && m_arready[5]) begin
|
|
$display("DATA_M5_AR addr=%08x target=%0d", m_ar[5].addr, s_read_routed_target[5]);
|
|
end
|
|
if (m_rvalid[5] && m_rready[5] && m_r[5].last) begin
|
|
$display("DATA_M5_R resp=%0d data=%016x", m_r[5].resp, m_r[5].data);
|
|
end
|
|
end
|
|
end
|
|
|
|
initial begin
|
|
if ((NumMasters != 9) || (NumTargets != 6) || (StarvationCycles < 2) ||
|
|
((StarvationCycles & (StarvationCycles - 1)) != 0)) begin
|
|
$fatal(1, "axi4_data_crossbar: invalid product topology or aging interval");
|
|
end
|
|
end
|
|
`endif
|
|
endmodule
|