File size: 8,129 Bytes
e4cdd5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// ============================================================================
// Async Router
// ============================================================================
//
// Copyright 2026 Henry Arthur Shulayev Barnes / Catalyst Neuromorphic Ltd
// Company No. 17054540 — UK Patent Application No. 2602902.6
//
// 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.
// ============================================================================

`timescale 1ns/1ps

module async_router #(
    parameter PACKET_W      = 34,
    parameter COORD_BITS    = 4,
    parameter FIFO_DEPTH    = 16,
    parameter FIFO_PTR_BITS = 4
)(
    input  wire                    clk,
    input  wire                    rst_n,
    input  wire [COORD_BITS-1:0]   my_x,
    input  wire [COORD_BITS-1:0]   my_y,

    input  wire                    local_in_valid,
    output wire                    local_in_ready,
    input  wire [PACKET_W-1:0]     local_in_data,
    output wire                    local_out_valid,
    input  wire                    local_out_ready,
    output wire [PACKET_W-1:0]     local_out_data,

    input  wire                    north_in_valid,
    output wire                    north_in_ready,
    input  wire [PACKET_W-1:0]     north_in_data,
    output wire                    north_out_valid,
    input  wire                    north_out_ready,
    output wire [PACKET_W-1:0]     north_out_data,

    input  wire                    south_in_valid,
    output wire                    south_in_ready,
    input  wire [PACKET_W-1:0]     south_in_data,
    output wire                    south_out_valid,
    input  wire                    south_out_ready,
    output wire [PACKET_W-1:0]     south_out_data,

    input  wire                    east_in_valid,
    output wire                    east_in_ready,
    input  wire [PACKET_W-1:0]     east_in_data,
    output wire                    east_out_valid,
    input  wire                    east_out_ready,
    output wire [PACKET_W-1:0]     east_out_data,

    input  wire                    west_in_valid,
    output wire                    west_in_ready,
    input  wire [PACKET_W-1:0]     west_in_data,
    output wire                    west_out_valid,
    input  wire                    west_out_ready,
    output wire [PACKET_W-1:0]     west_out_data,

    output wire                    idle
);

    localparam P_LOCAL = 0, P_NORTH = 1, P_SOUTH = 2, P_EAST = 3, P_WEST = 4;

    localparam DX_MSB = PACKET_W - 1;
    localparam DX_LSB = PACKET_W - COORD_BITS;
    localparam DY_MSB = DX_LSB - 1;
    localparam DY_LSB = DX_LSB - COORD_BITS;

    wire [4:0] fifo_empty, fifo_full;
    wire [PACKET_W-1:0] fifo_head [0:4];
    wire [4:0] fifo_push;
    reg  [4:0] fifo_pop;

    assign fifo_push[P_LOCAL] = local_in_valid && !fifo_full[P_LOCAL];
    assign fifo_push[P_NORTH] = north_in_valid && !fifo_full[P_NORTH];
    assign fifo_push[P_SOUTH] = south_in_valid && !fifo_full[P_SOUTH];
    assign fifo_push[P_EAST]  = east_in_valid  && !fifo_full[P_EAST];
    assign fifo_push[P_WEST]  = west_in_valid  && !fifo_full[P_WEST];

    assign local_in_ready = !fifo_full[P_LOCAL];
    assign north_in_ready = !fifo_full[P_NORTH];
    assign south_in_ready = !fifo_full[P_SOUTH];
    assign east_in_ready  = !fifo_full[P_EAST];
    assign west_in_ready  = !fifo_full[P_WEST];

    wire [PACKET_W-1:0] in_data [0:4];
    assign in_data[P_LOCAL] = local_in_data;
    assign in_data[P_NORTH] = north_in_data;
    assign in_data[P_SOUTH] = south_in_data;
    assign in_data[P_EAST]  = east_in_data;
    assign in_data[P_WEST]  = west_in_data;

    genvar gi;
    generate
        for (gi = 0; gi < 5; gi = gi + 1) begin : gen_fifo
            spike_fifo #(
                .ID_WIDTH  (PACKET_W),
                .DEPTH     (FIFO_DEPTH),
                .PTR_BITS  (FIFO_PTR_BITS)
            ) input_fifo (
                .clk       (clk),
                .rst_n     (rst_n),
                .push      (fifo_push[gi]),
                .pop       (fifo_pop[gi]),
                .clear     (1'b0),
                .push_data (in_data[gi]),
                .pop_data  (fifo_head[gi]),
                .empty     (fifo_empty[gi]),
                .full      (fifo_full[gi])
            );
        end
    endgenerate

    function [2:0] xy_route;
        input [COORD_BITS-1:0] dx, dy, cx, cy;
        begin
            if      (dx > cx) xy_route = P_EAST;
            else if (dx < cx) xy_route = P_WEST;
            else if (dy > cy) xy_route = P_NORTH;
            else if (dy < cy) xy_route = P_SOUTH;
            else              xy_route = P_LOCAL;
        end
    endfunction

    wire [2:0] head_route [0:4];
    generate
        for (gi = 0; gi < 5; gi = gi + 1) begin : gen_route
            assign head_route[gi] = xy_route(
                fifo_head[gi][DX_MSB:DX_LSB],
                fifo_head[gi][DY_MSB:DY_LSB],
                my_x, my_y
            );
        end
    endgenerate

    reg  [4:0] out_valid_r;
    reg  [PACKET_W-1:0] out_data_r [0:4];

    wire [4:0] out_ready;
    assign out_ready[P_LOCAL] = local_out_ready;
    assign out_ready[P_NORTH] = north_out_ready;
    assign out_ready[P_SOUTH] = south_out_ready;
    assign out_ready[P_EAST]  = east_out_ready;
    assign out_ready[P_WEST]  = west_out_ready;

    assign local_out_valid = out_valid_r[P_LOCAL];
    assign local_out_data  = out_data_r[P_LOCAL];
    assign north_out_valid = out_valid_r[P_NORTH];
    assign north_out_data  = out_data_r[P_NORTH];
    assign south_out_valid = out_valid_r[P_SOUTH];
    assign south_out_data  = out_data_r[P_SOUTH];
    assign east_out_valid  = out_valid_r[P_EAST];
    assign east_out_data   = out_data_r[P_EAST];
    assign west_out_valid  = out_valid_r[P_WEST];
    assign west_out_data   = out_data_r[P_WEST];

    reg [2:0] arb_ptr;

    reg [4:0] comb_grant;
    reg [4:0] comb_out_claim;

    always @(*) begin : grant_logic
        integer p, idx;
        comb_grant = 5'b0;
        comb_out_claim = 5'b0;
        for (p = 0; p < 5; p = p + 1) begin
            idx = arb_ptr + p;
            if (idx >= 5) idx = idx - 5;
            if (!fifo_empty[idx] && !comb_grant[idx]) begin
                if (!out_valid_r[head_route[idx]] && !comb_out_claim[head_route[idx]]) begin
                    comb_grant[idx] = 1'b1;
                    comb_out_claim[head_route[idx]] = 1'b1;
                end
            end
        end
    end

    always @(posedge clk or negedge rst_n) begin : seq_logic
        integer i;
        if (!rst_n) begin
            out_valid_r <= 5'b0;
            arb_ptr <= 3'd0;
            for (i = 0; i < 5; i = i + 1)
                out_data_r[i] <= {PACKET_W{1'b0}};
        end else begin
            for (i = 0; i < 5; i = i + 1)
                if (out_valid_r[i] && out_ready[i])
                    out_valid_r[i] <= 1'b0;

            for (i = 0; i < 5; i = i + 1) begin
                if (comb_grant[i]) begin
                    out_valid_r[head_route[i]] <= 1'b1;
                    out_data_r[head_route[i]] <= fifo_head[i];
                end
            end

            arb_ptr <= (arb_ptr == 3'd4) ? 3'd0 : arb_ptr + 3'd1;
        end
    end

    always @(*) fifo_pop = comb_grant;

    assign idle = (&fifo_empty) &&
                  !out_valid_r[P_NORTH] && !out_valid_r[P_SOUTH] &&
                  !out_valid_r[P_EAST]  && !out_valid_r[P_WEST];

endmodule