283 lines
6.7 KiB
Verilog
283 lines
6.7 KiB
Verilog
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename: rxgetsrcmac.v
|
|
// {{{
|
|
// Project: 10Gb Ethernet switch
|
|
//
|
|
// Purpose: Given an incoming packet, copy the source MAC address and
|
|
// forward it to the routing table.
|
|
//
|
|
// Creator: Dan Gisselquist, Ph.D.
|
|
// Gisselquist Technology, LLC
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// }}}
|
|
// Copyright (C) 2023, Gisselquist Technology, LLC
|
|
// {{{
|
|
// This file is part of the ETH10G project.
|
|
//
|
|
// The ETH10G project contains free software and gateware, licensed under the
|
|
// Apache License, Version 2.0 (the "License"). You may not use this project,
|
|
// or 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, files
|
|
// 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.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
`default_nettype none
|
|
// }}}
|
|
module rxgetsrcmac #(
|
|
// {{{
|
|
parameter [0:0] OPT_SKIDBUFFER = 1'b0,
|
|
parameter [0:0] OPT_LOWPOWER = 1'b0,
|
|
parameter [0:0] OPT_LITTLE_ENDIAN= 1'b0,
|
|
parameter DW=64, // Bits per incoming beat
|
|
parameter WBITS = $clog2(DW/8), // Bits to desc # bytes
|
|
parameter MACW = 48 // Bits in a MAC address
|
|
// }}}
|
|
) (
|
|
// {{{
|
|
input wire i_clk, i_reset,
|
|
// Incoming packet data from one interface
|
|
// {{{
|
|
input wire S_VALID,
|
|
output wire S_READY,
|
|
input wire [DW-1:0] S_DATA,
|
|
input wire [WBITS-1:0] S_BYTES,
|
|
input wire S_ABORT,
|
|
input wire S_LAST,
|
|
// }}}
|
|
// Outgoing packet data
|
|
// {{{
|
|
output reg M_VALID,
|
|
input wire M_READY,
|
|
output reg [DW-1:0] M_DATA,
|
|
output reg [WBITS-1:0] M_BYTES,
|
|
output reg M_ABORT,
|
|
output reg M_LAST,
|
|
// }}}
|
|
// Outgoing packet data, needing destination lookup
|
|
// {{{
|
|
output reg TBL_VALID,
|
|
input wire TBL_READY,
|
|
output reg [MACW-1:0] TBL_SRCMAC
|
|
// }}}
|
|
// }}}
|
|
);
|
|
|
|
// Local declarations
|
|
// {{{
|
|
localparam MAXPOSN = (MACW+(DW-1))/DW;
|
|
localparam LGPOSN = $clog2(MAXPOSN);
|
|
|
|
wire skd_valid, skd_ready,
|
|
skd_abort, skd_last;
|
|
wire [DW-1:0] skd_data;
|
|
wire [WBITS-1:0] skd_bytes;
|
|
|
|
reg [LGPOSN:0] pkt_posn;
|
|
reg m_active;
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// (Optional) Skidbuffer
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
generate if (OPT_SKIDBUFFER)
|
|
begin : GEN_SKIDBUFFER
|
|
|
|
netskid #(
|
|
.DW(DW + WBITS)
|
|
) u_skidbuffer (
|
|
// {{{
|
|
.i_clk(i_clk), .i_reset(i_reset),
|
|
.S_AXIN_VALID( S_VALID),
|
|
.S_AXIN_READY( S_READY),
|
|
.S_AXIN_DATA({ S_BYTES, S_DATA }),
|
|
.S_AXIN_LAST( S_LAST),
|
|
.S_AXIN_ABORT( S_ABORT),
|
|
//
|
|
.M_AXIN_VALID( skd_valid),
|
|
.M_AXIN_READY( skd_ready),
|
|
.M_AXIN_DATA({ skd_bytes, skd_data }),
|
|
.M_AXIN_LAST( skd_last),
|
|
.M_AXIN_ABORT( skd_abort)
|
|
// }}}
|
|
);
|
|
|
|
end else begin : NO_SKIDBUFFER
|
|
|
|
assign skd_valid = S_VALID;
|
|
assign S_READY = skd_ready;
|
|
assign skd_data = S_DATA;
|
|
assign skd_bytes = S_BYTES;
|
|
assign skd_abort = S_ABORT;
|
|
assign skd_last = S_LAST;
|
|
|
|
end endgenerate
|
|
|
|
assign skd_ready= ((!TBL_VALID || TBL_READY) && (!M_VALID || M_READY));
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Extract MACs
|
|
// {{{
|
|
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
pkt_posn <= 0;
|
|
else if (skd_abort && (!skd_valid || skd_ready))
|
|
pkt_posn <= 0;
|
|
else if (skd_valid && skd_ready)
|
|
begin
|
|
if (!pkt_posn[LGPOSN])
|
|
pkt_posn <= pkt_posn + 1;
|
|
if (skd_last)
|
|
pkt_posn <= 0;
|
|
end
|
|
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
TBL_VALID <= 0;
|
|
else if (skd_valid && skd_ready && skd_last) // pkt_posn == MAXPOSN-1)
|
|
// Require a full, non-aborted, packet before forwarding the
|
|
// MAC address to the table. This will guarantee that the
|
|
// packet CRC is good, and therefore that the MAC address is
|
|
// a valid one.
|
|
TBL_VALID <= !skd_abort;
|
|
else if (TBL_READY)
|
|
TBL_VALID <= 0;
|
|
|
|
generate if (MACW <= DW)
|
|
begin : GEN_SMALL_MAC
|
|
// {{{
|
|
always @(posedge i_clk)
|
|
if (OPT_LOWPOWER && i_reset)
|
|
TBL_SRCMAC <= 0;
|
|
else if (!TBL_VALID || TBL_READY)
|
|
begin
|
|
if (skd_valid && skd_ready && pkt_posn == 0)
|
|
begin
|
|
if (OPT_LITTLE_ENDIAN)
|
|
TBL_SRCMAC <= skd_data[MACW-1:0];
|
|
else
|
|
TBL_SRCMAC <= skd_data[DW-1:DW-MACW];
|
|
end
|
|
end
|
|
// }}}
|
|
end else begin : GEN_WIDE_MAC
|
|
// {{{
|
|
reg [DW*MAXPOSN-1:0] last_data;
|
|
|
|
always @(posedge i_clk)
|
|
if (OPT_LOWPOWER && (i_reset || skd_abort))
|
|
last_data <= 0;
|
|
else if (skd_valid && skd_ready)
|
|
begin
|
|
if (MAXPOSN <= 1)
|
|
last_data <= skd_data;
|
|
else if (OPT_LITTLE_ENDIAN)
|
|
last_data <= { skd_data, last_data[DW*MAXPOSN-1:DW] };
|
|
else
|
|
last_data <= { last_data[DW*(MAXPOSN-1)-1:0], skd_data };
|
|
end
|
|
|
|
always @(posedge i_clk)
|
|
if (OPT_LOWPOWER && i_reset)
|
|
TBL_SRCMAC <= 0;
|
|
else if (!TBL_VALID || TBL_READY)
|
|
begin
|
|
if (skd_valid && skd_ready && pkt_posn == MAXPOSN-1)
|
|
begin
|
|
if (OPT_LITTLE_ENDIAN)
|
|
TBL_SRCMAC <= { skd_data[MACW-DW-1:0], last_data };
|
|
else
|
|
TBL_SRCMAC <= { last_data, skd_data[DW-1:DW-MACW] };
|
|
end
|
|
end
|
|
// }}}
|
|
end endgenerate
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Copy packets forward
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
initial M_VALID = 0;
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
M_VALID <= 0;
|
|
else if (!M_VALID || M_READY)
|
|
M_VALID <= skd_valid && !skd_abort;
|
|
|
|
initial { M_BYTES, M_DATA } = 0;
|
|
always @(posedge i_clk)
|
|
if (OPT_LOWPOWER && i_reset)
|
|
begin
|
|
M_DATA <= 0;
|
|
M_BYTES <= 0;
|
|
end else if (!M_VALID || M_READY)
|
|
begin
|
|
M_DATA <= skd_data;
|
|
M_BYTES <= skd_bytes;
|
|
|
|
if (OPT_LOWPOWER && (!skd_valid || !skd_ready || skd_abort))
|
|
{ M_DATA, M_BYTES } <= 0;
|
|
end
|
|
|
|
initial m_active = 0;
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
m_active <= 0;
|
|
else if (skd_abort && (!skd_valid || skd_ready))
|
|
m_active <= 0;
|
|
else if (skd_valid && skd_ready)
|
|
m_active <= !skd_last;
|
|
|
|
initial M_LAST = 0;
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
M_LAST <= 0;
|
|
else if (!M_VALID || M_READY)
|
|
begin
|
|
M_LAST <= skd_last;
|
|
if (OPT_LOWPOWER && (!skd_valid || !skd_ready))
|
|
M_LAST <= 1'b0;
|
|
end
|
|
|
|
initial M_ABORT = 0;
|
|
always @(posedge i_clk)
|
|
if (i_reset)
|
|
M_ABORT <= 0;
|
|
else if (skd_abort && m_active)
|
|
M_ABORT <= 1'b1;
|
|
else if (!M_VALID || M_READY)
|
|
M_ABORT <= 1'b0;
|
|
|
|
// }}}
|
|
|
|
// Keep Verilator happy
|
|
// {{{
|
|
// Verilator lint_off UNUSED
|
|
wire unused;
|
|
assign unused = &{ 1'b0 };
|
|
// Verilator lint_on UNUSED
|
|
// }}}
|
|
endmodule
|