1//
2// Copyright 2013 Ettus Research LLC
3// Copyright 2018 Ettus Research, a National Instruments Company
4//
5// SPDX-License-Identifier: LGPL-3.0-or-later
6//
7
8
9module pcie_iop2_msg_arbiter #(
10    parameter E0_ADDR = 20'h0,
11    parameter E0_MASK = 20'h0,
12    parameter E1_ADDR = 20'h0,
13    parameter E1_MASK = 20'h0,
14    parameter E2_ADDR = 20'h0,
15    parameter E2_MASK = 20'h0,
16    parameter E3_ADDR = 20'h0,
17    parameter E3_MASK = 20'h0
18) (
19    //Clocks and resets
20    input           clk,
21    input           reset,
22
23    input [63:0]    regi_tdata,
24    input           regi_tvalid,
25    output          regi_tready,
26    output [63:0]   rego_tdata,
27    output          rego_tvalid,
28    input           rego_tready,
29
30    output [63:0]   e0_regi_tdata,
31    output          e0_regi_tvalid,
32    input           e0_regi_tready,
33    input [63:0]    e0_rego_tdata,
34    input           e0_rego_tvalid,
35    output          e0_rego_tready,
36
37    output [63:0]   e1_regi_tdata,
38    output          e1_regi_tvalid,
39    input           e1_regi_tready,
40    input [63:0]    e1_rego_tdata,
41    input           e1_rego_tvalid,
42    output          e1_rego_tready,
43
44    output [63:0]   e2_regi_tdata,
45    output          e2_regi_tvalid,
46    input           e2_regi_tready,
47    input [63:0]    e2_rego_tdata,
48    input           e2_rego_tvalid,
49    output          e2_rego_tready,
50
51    output [63:0]   e3_regi_tdata,
52    output          e3_regi_tvalid,
53    input           e3_regi_tready,
54    input [63:0]    e3_rego_tdata,
55    input           e3_rego_tvalid,
56    output          e3_rego_tready
57);
58
59    //*******************************************************************************
60    // PCIe output message arbiter
61    //
62    axi_mux4 #(.PRIO(0), .WIDTH(64), .BUFFER(0)) rego_arbiter_mux (
63        .clk(clk), .reset(reset), .clear(1'b0),
64        .i0_tdata(e0_rego_tdata), .i0_tlast(e0_rego_tvalid), .i0_tvalid(e0_rego_tvalid), .i0_tready(e0_rego_tready),
65        .i1_tdata(e1_rego_tdata), .i1_tlast(e1_rego_tvalid), .i1_tvalid(e1_rego_tvalid), .i1_tready(e1_rego_tready),
66        .i2_tdata(e2_rego_tdata), .i2_tlast(e2_rego_tvalid), .i2_tvalid(e2_rego_tvalid), .i2_tready(e2_rego_tready),
67        .i3_tdata(e3_rego_tdata), .i3_tlast(e3_rego_tvalid), .i3_tvalid(e3_rego_tvalid), .i3_tready(e3_rego_tready),
68        .o_tdata(rego_tdata), .o_tlast(), .o_tvalid(rego_tvalid), .o_tready(rego_tready)
69    );
70    //
71    //*******************************************************************************
72
73    //*******************************************************************************
74    // PCIe input message arbiter
75    //
76    wire [63:0]     regi_msg;
77    wire            regi_rc;
78    wire [19:0]     regi_addr;
79    wire            e0_rego_rd, e1_rego_rd, e2_rego_rd, e3_rego_rd;
80
81    ioport2_msg_decode e0_rego_decoder (.message(e0_rego_tdata), .rd_request(e0_rego_rd));
82    ioport2_msg_decode e1_rego_decoder (.message(e1_rego_tdata), .rd_request(e1_rego_rd));
83    ioport2_msg_decode e2_rego_decoder (.message(e2_rego_tdata), .rd_request(e2_rego_rd));
84    ioport2_msg_decode e3_rego_decoder (.message(e3_rego_tdata), .rd_request(e3_rego_rd));
85
86    localparam DEST_E0   = 2'd0;
87    localparam DEST_E1   = 2'd1;
88    localparam DEST_E2   = 2'd2;
89    localparam DEST_E3   = 2'd3;
90
91    reg  [1:0]  regi_resp_dest;
92    wire [1:0]  regi_req_dest, regi_dest;
93
94    assign regi_req_dest =
95        ((regi_addr & E0_MASK) == E0_ADDR) ? DEST_E0 : (
96        ((regi_addr & E1_MASK) == E1_ADDR) ? DEST_E1 : (
97        ((regi_addr & E2_MASK) == E2_ADDR) ? DEST_E2 : (
98        ((regi_addr & E3_MASK) == E3_ADDR) ? DEST_E3 : (
99        DEST_E0))));
100
101    //A response must be routed to the port with the last read request
102    always @(posedge clk) begin
103        if (reset)
104            regi_resp_dest <= DEST_E0;  //Default 0
105        else if (e0_rego_tvalid & e0_rego_tready & e0_rego_rd)
106            regi_resp_dest <= DEST_E0;
107        else if (e1_rego_tvalid & e1_rego_tready & e1_rego_rd)
108            regi_resp_dest <= DEST_E1;
109        else if (e2_rego_tvalid & e2_rego_tready & e2_rego_rd)
110            regi_resp_dest <= DEST_E2;
111        else if (e3_rego_tvalid & e3_rego_tready & e3_rego_rd)
112            regi_resp_dest <= DEST_E3;
113    end
114
115    ioport2_msg_decode regi_decoder (
116        .message(regi_msg), .rd_response(regi_rc), .address(regi_addr));
117
118    //If request, get destination from msg.
119    //If response, get destination from last read location.
120    assign regi_dest = regi_rc ? regi_resp_dest : regi_req_dest;
121
122    axi_demux4 #(.ACTIVE_CHAN(4'b1111), .WIDTH(64), .BUFFER(0)) regi_arbiter_demux (
123        .clk(clk), .reset(reset), .clear(1'b0),
124        .header(regi_msg), .dest(regi_dest),
125        .i_tdata(regi_tdata), .i_tlast(regi_tvalid), .i_tvalid(regi_tvalid), .i_tready(regi_tready),
126        .o0_tdata(e0_regi_tdata), .o0_tlast(), .o0_tvalid(e0_regi_tvalid), .o0_tready(e0_regi_tready),
127        .o1_tdata(e1_regi_tdata), .o1_tlast(), .o1_tvalid(e1_regi_tvalid), .o1_tready(e1_regi_tready),
128        .o2_tdata(e2_regi_tdata), .o2_tlast(), .o2_tvalid(e2_regi_tvalid), .o2_tready(e2_regi_tready),
129        .o3_tdata(e3_regi_tdata), .o3_tlast(), .o3_tvalid(e3_regi_tvalid), .o3_tready(e3_regi_tready)
130    );
131    //
132    //*******************************************************************************
133
134endmodule
135