245 lines
6.8 KiB
Verilog
245 lines
6.8 KiB
Verilog
//
|
|
// Copyright 2013 Ettus Research LLC
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
|
|
//
|
|
// This module implements a highly customized TCAM that enbales forwarding
|
|
// decisions to be made on a 16bit field from a VITA SID field.
|
|
// The 16bits are allocated by convention as 8 bits of Network address
|
|
// (Addresses USRP's etc) and 8 bits of Host address (adresses endpoints in
|
|
// a USRP). By definition if the DEST field in the SID addresses a different
|
|
// USRP than this one then we don't care about the Host field, only the Network Field.
|
|
// We only look at the Host Field when the Network field addresses us.
|
|
// Thus Need TCAM of 256+256 entries with Log2(N) bits, where N is the number of
|
|
// slave(output) ports on the crossbar switch.
|
|
//
|
|
//
|
|
//
|
|
// SID format:
|
|
//
|
|
// |--------|---------|--------|---------|
|
|
// | SOURCE | DEST | DEST |
|
|
// | ADDRESS | NETWORK| HOST |
|
|
// |--------|---------|--------|---------|
|
|
// 8 8 8 8
|
|
//
|
|
|
|
|
|
`define LOG2(N) (\
|
|
N < 2 ? 0 : \
|
|
N < 4 ? 1 : \
|
|
N < 8 ? 2 : \
|
|
N < 16 ? 3 : \
|
|
N < 32 ? 4 : \
|
|
N < 64 ? 5 : \
|
|
N < 128 ? 6 : \
|
|
N < 256 ? 7 : \
|
|
N < 512 ? 8 : \
|
|
N < 1024 ? 9 : \
|
|
10)
|
|
|
|
module axi_forwarding_cam
|
|
#(
|
|
parameter BASE = 0, // BASE address for setting registers in this block. (512 addrs used)
|
|
parameter WIDTH=64, // Bit width of FIFO word.
|
|
parameter NUM_OUTPUTS=2 // Number of outputs (destinations) in crossbar.
|
|
)
|
|
(
|
|
input clk,
|
|
input reset,
|
|
input clear,
|
|
// Monitored FIFO signals
|
|
input [WIDTH-1:0] o_tdata,
|
|
input o_tvalid,
|
|
input o_tready,
|
|
input o_tlast,
|
|
input pkt_present,
|
|
// Configuration
|
|
input [7:0] local_addr,
|
|
// Setting Bus
|
|
input set_stb,
|
|
input [15:0] set_addr,
|
|
input [31:0] set_data,
|
|
// Forwarding Flags
|
|
output reg [NUM_OUTPUTS-1:0] forward_valid,
|
|
input [NUM_OUTPUTS-1:0] forward_ack,
|
|
// readback bus
|
|
input rb_rd_stb,
|
|
input [`LOG2(NUM_OUTPUTS)-1:0] rb_addr,
|
|
output [31:0] rb_data
|
|
);
|
|
|
|
|
|
localparam WAIT_SOF = 0;
|
|
localparam WAIT_EOF = 1;
|
|
reg state;
|
|
|
|
localparam IDLE = 0;
|
|
localparam FORWARD = 1;
|
|
localparam WAIT = 2;
|
|
|
|
reg [1:0] demux_state;
|
|
|
|
reg [15:0] dst;
|
|
reg dst_valid, dst_valid_reg;
|
|
wire local_dst;
|
|
wire [8:0] read_addr;
|
|
|
|
//
|
|
// Monitor packets leaving FIFO
|
|
//
|
|
always @(posedge clk)
|
|
if (reset | clear) begin
|
|
state <= WAIT_SOF;
|
|
end else
|
|
case(state)
|
|
//
|
|
// After RESET or the EOF of previous packet, the first cycle with
|
|
// output valid asserted is the SOF and presents the Header word.
|
|
// The cycle following the concurrent presentation of asserted output
|
|
// valid and output ready presents the word following the header.
|
|
//
|
|
WAIT_SOF:
|
|
if (o_tvalid && o_tready) begin
|
|
state <= WAIT_EOF;
|
|
end else begin
|
|
state <= WAIT_SOF;
|
|
end
|
|
//
|
|
// EOF is signalled by o_tlast asserted whilst output valid and ready asserted.
|
|
//
|
|
WAIT_EOF:
|
|
if (o_tlast && o_tvalid && o_tready) begin
|
|
state <= WAIT_SOF;
|
|
end else begin
|
|
state <= WAIT_EOF;
|
|
end
|
|
endcase // case(in_state)
|
|
|
|
//
|
|
// Extract Destination fields(s) from SID
|
|
//
|
|
always @(posedge clk)
|
|
if (reset | clear) begin
|
|
dst <= 0;
|
|
dst_valid <= 0;
|
|
dst_valid_reg <= 0;
|
|
end else if (o_tvalid && (state == WAIT_SOF) && pkt_present) begin
|
|
// SID will remain valid until o_tready is asserted as this will cause a state transition.
|
|
dst <= o_tdata[15:0];
|
|
dst_valid <= 1;
|
|
dst_valid_reg <= dst_valid;
|
|
end else begin
|
|
dst_valid <= 0;
|
|
dst_valid_reg <= dst_valid;
|
|
end
|
|
|
|
//
|
|
// Is Network field in DST our local address?
|
|
//
|
|
assign local_dst = (dst[15:8] == local_addr) && dst_valid;
|
|
|
|
|
|
//
|
|
// Mux address to RAM so that it searches CAM for Network field or Host field.
|
|
// Network addresses are stored in the lower 256 locations, host addresses the upper 256.
|
|
//
|
|
assign read_addr = {local_dst,(local_dst ? dst[7:0] : dst[15:8])};
|
|
|
|
//
|
|
// Imply a block RAM here, 512xCeil(Log2(NUM_OUTPUTS))
|
|
//
|
|
//synthesis attribute ram_style of mem is block
|
|
reg [(`LOG2(NUM_OUTPUTS))-1 : 0] mem [0:511];
|
|
reg [8:0] read_addr_reg;
|
|
wire write;
|
|
wire [`LOG2(NUM_OUTPUTS)-1:0] read_data;
|
|
|
|
assign write = (set_addr[15:9] == (BASE >>9)) && set_stb; // Addr decode.
|
|
|
|
always @(posedge clk)
|
|
begin
|
|
read_addr_reg <= read_addr;
|
|
|
|
if (write) begin
|
|
mem[set_addr[8:0]] <= set_data[`LOG2(NUM_OUTPUTS)-1:0];
|
|
end
|
|
|
|
end
|
|
|
|
assign read_data = mem[read_addr_reg];
|
|
|
|
|
|
//
|
|
// State machine to manage forwarding flags.
|
|
//
|
|
always @(posedge clk)
|
|
if (reset | clear) begin
|
|
demux_state <= IDLE;
|
|
end else
|
|
case(demux_state)
|
|
|
|
// Wait for Valid DST which indicates a new packet lookup in the CAM.
|
|
IDLE: begin
|
|
if (dst_valid_reg == 1) begin
|
|
forward_valid <= 1 << read_data;
|
|
demux_state <= FORWARD;
|
|
end
|
|
end
|
|
// When Slave/Output thats forwarding ACK's the forward flag, clear request and wait for packet to be transfered
|
|
FORWARD: begin
|
|
if ((forward_ack & forward_valid) != 0) begin
|
|
forward_valid <= 0;
|
|
demux_state <= WAIT;
|
|
end
|
|
end
|
|
// When packet transfered go back to idle.
|
|
WAIT: begin
|
|
if (forward_ack == 0)
|
|
demux_state <= IDLE;
|
|
end
|
|
|
|
endcase // case (demux_state)
|
|
|
|
//
|
|
// Compile forwarding statistics
|
|
// (This uses a lot of registers!)
|
|
//
|
|
genvar m;
|
|
reg [31:0] statistics [0:NUM_OUTPUTS-1];
|
|
|
|
generate
|
|
for (m = 0; m < NUM_OUTPUTS; m = m + 1) begin: generate_stats
|
|
always @(posedge clk)
|
|
if (reset | clear)
|
|
statistics[m] <= 0;
|
|
else if ((rb_addr == m) && rb_rd_stb)
|
|
statistics[m] <= 0;
|
|
else if (forward_ack[m] & forward_valid[m])
|
|
statistics[m] <= statistics[m] + 1;
|
|
end
|
|
endgenerate
|
|
|
|
assign rb_data = statistics[rb_addr];
|
|
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
|