aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/zynq_fifo/zf_arbiter.v
blob: 3ee8770ecfb47d76de5bd5d758822c6708684180 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
//////////////////////////////////////////////////////////////////////////////////
// Copyright Ettus Research LLC
// The ZYNQ FIFO configuration arbiter:
//  - holds configuration memory addresses
//  - setting and readback for slave state machines
//  - stream of memory addresses for master state machines
//////////////////////////////////////////////////////////////////////////////////


module zf_arbiter
#(
    parameter STREAMS_WIDTH = 2,
    parameter CMDFIFO_DEPTH = 4,
    parameter PAGE_WIDTH = 16
)
(
    input clk,
    input rst,

    //------------------------------------------------------------------
    //-- settings interface
    //------------------------------------------------------------------
    input [31:0] set_addr,
    input [31:0] set_data,
    input set_stb,

    //------------------------------------------------------------------
    //-- readback interface
    //------------------------------------------------------------------
    input [31:0] rb_addr,
    output [31:0] rb_data,
    input rb_stb,

    //------------------------------------------------------------------
    //-- fifo interactive interface
    //------------------------------------------------------------------
    output [71:0] cmd_tdata,
    output cmd_tvalid,
    input cmd_tready,
    input [7:0] sts_tdata,
    input sts_tvalid,
    output sts_tready,

    //------------------------------------------------------------------
    //-- which stream to process? externally provided
    //------------------------------------------------------------------
    input [STREAMS_WIDTH-1:0] ext_stream,
    input stream_valid,

    output [31:0] debug
);

////////////////////////////////////////////////////////////////////////
///////////////////////////// Begin R T L //////////////////////////////
////////////////////////////////////////////////////////////////////////

    localparam NUM_STREAMS = (1 << STREAMS_WIDTH);

    reg [STREAMS_WIDTH-1:0] which_stream;

    //readback mux assignment
    reg [31:0] rb_data_i [NUM_STREAMS-1:0];
    assign rb_data = rb_data_i[rb_addr[STREAMS_WIDTH+4:5]];

    //cmd + sts fifo mux signals
    wire [72:0] cmd_data_i [NUM_STREAMS-1:0];
    assign cmd_tdata = cmd_data_i[which_stream];
    wire cmd_tvalid_i [NUM_STREAMS-1:0];
    wire sts_tready_i [NUM_STREAMS-1:0];

    ////////////////////////////////////////////////////////////////////
    // state machine for driving fifo arbitration
    ////////////////////////////////////////////////////////////////////
    localparam STATE_SET_WHICH_STREAM = 0;
    localparam STATE_ASSERT_DO_CMD = 1;
    localparam STATE_ASSERT_DO_STS = 2;
    localparam STATE_SOME_IDLE = 3;

    reg [1:0] state;

    always @(posedge clk) begin
        if (rst) begin
            state <= STATE_SET_WHICH_STREAM;
            which_stream <= 0;
        end
        else case (state)

        STATE_SET_WHICH_STREAM: begin
            if (cmd_tvalid_i[ext_stream]) state <= STATE_ASSERT_DO_CMD;
            which_stream <= ext_stream;
        end

        STATE_ASSERT_DO_CMD: begin
            if (cmd_tvalid && cmd_tready) state <= STATE_ASSERT_DO_STS;
        end

        STATE_ASSERT_DO_STS: begin
            if (sts_tvalid && sts_tready) state <= STATE_SOME_IDLE;
        end

        STATE_SOME_IDLE: begin
            state <= STATE_SET_WHICH_STREAM;
        end

        default: state <= STATE_SET_WHICH_STREAM;

        endcase //state
    end

    ////////////////////////////////////////////////////////////////////
    // memory map + fifos for the host control/status
    ////////////////////////////////////////////////////////////////////

    wire do_cmd = (state == STATE_ASSERT_DO_CMD);
    wire do_sts = (state == STATE_ASSERT_DO_STS);

    assign cmd_tvalid = do_cmd && cmd_tvalid_i[which_stream];
    assign sts_tready = do_sts && sts_tready_i[which_stream];

    genvar i;
    generate
    for (i=0; i < NUM_STREAMS; i=i+1) begin : stream_circuit

        wire [PAGE_WIDTH-3:0] set_addr32 = set_addr[PAGE_WIDTH-1:2];
        wire write_clear = set_stb && (set_addr32 == (0 + i*8));
        wire write_addr  = set_stb && (set_addr32 == (1 + i*8));
        wire write_size  = set_stb && (set_addr32 == (2 + i*8));
        wire write_sts_rdy  = set_stb && (set_addr32 == (3 + i*8));
        wire write_sts      = set_stb && (set_addr32 == (4 + i*8));

        wire [PAGE_WIDTH-3:0] rb_addr32 = rb_addr[PAGE_WIDTH-1:2];
        wire read_sig            = (rb_addr32 == (0 + i*8));
        wire read_status         = (rb_addr32 == (4 + i*8));
        wire read_sts_occupied   = (rb_addr32 == (5 + i*8));
        wire read_cmd_addr_space = (rb_addr32 == (6 + i*8));
        wire read_cmd_size_space = (rb_addr32 == (7 + i*8));

        wire [15:0] sts_occupied, cmd_addr_space, cmd_size_space;
        wire [7:0] sts_readback;

        wire [15:0] this_stream = i;
        always @* begin
            if (read_sig) rb_data_i[i] <= {16'hACE0, this_stream};
            else if (read_status) rb_data_i[i] <= {24'b0, sts_readback};
            else if (read_sts_occupied) rb_data_i[i] <= {16'b0, sts_occupied};
            else if (read_cmd_addr_space) rb_data_i[i] <= {16'b0, cmd_addr_space};
            else if (read_cmd_size_space) rb_data_i[i] <= {16'b0, cmd_size_space};
            else rb_data_i[i] <= 32'h12345678;
        end

        wire [31:0] cmd_addr, cmd_size;
        wire cmd_addr_tvalid, cmd_size_tvalid;
        assign cmd_data_i[i][32+39:32+36] = 4'b0; //reserved - 0?
        assign cmd_data_i[i][32+35:64] = i[3:0]; //tag
        assign cmd_data_i[i][63:32] = cmd_addr;
        assign cmd_data_i[i][31] = 1'b0; //DRE ReAlignment Request
        assign cmd_data_i[i][30] = 1'b1; //always EOF for tlast stream
        assign cmd_data_i[i][29:24] = 6'b0; //DRE Stream Alignment
        assign cmd_data_i[i][23] = 1'b0; //reserved - 0?
        assign cmd_data_i[i][22:0] = cmd_size[22:0];

        axi_fifo #(.WIDTH(32), .SIZE(CMDFIFO_DEPTH)) crl_addr_fifo
        (
            .clk(clk), .reset(rst), .clear(write_clear),
            .i_tdata(set_data), .i_tvalid(write_addr), .i_tready(), .space(cmd_addr_space),
            .o_tdata(cmd_addr), .o_tvalid(cmd_addr_tvalid), .o_tready(cmd_tready && do_cmd && (which_stream == i)), .occupied()
        );

        axi_fifo #(.WIDTH(32), .SIZE(CMDFIFO_DEPTH)) crl_size_fifo
        (
            .clk(clk), .reset(rst), .clear(write_clear),
            .i_tdata(set_data), .i_tvalid(write_size), .i_tready(), .space(cmd_size_space),
            .o_tdata(cmd_size), .o_tvalid(cmd_size_tvalid), .o_tready(cmd_tready && do_cmd && (which_stream == i)), .occupied()
        );

        assign cmd_tvalid_i[i] = cmd_addr_tvalid && cmd_size_tvalid && stream_valid;

        wire dm_sts_tvalid = sts_tvalid && do_sts && (which_stream == i);

        axi_fifo #(.WIDTH(8), .SIZE(CMDFIFO_DEPTH)) sts_fifo
        (
            .clk(clk), .reset(rst), .clear(),
            .i_tdata((write_sts)?set_data[7:0]:sts_tdata), .i_tvalid(dm_sts_tvalid || write_sts), .i_tready(sts_tready_i[i]), .space(),
            .o_tdata(sts_readback), .o_tvalid(), .o_tready(write_sts_rdy), .occupied(sts_occupied)
        );

    end
    endgenerate

    assign debug[1:0] = state;
    assign debug[4] = cmd_tvalid;
    assign debug[5] = cmd_tready;
    assign debug[6] = sts_tvalid;
    assign debug[7] = sts_tready;
    assign debug[8] = ext_stream;
    assign debug[9] = which_stream;
    assign debug[15] = rb_addr[STREAMS_WIDTH+4:5];

endmodule //zf_arbiter