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
|