336 lines
7.5 KiB
Verilog
336 lines
7.5 KiB
Verilog
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Filename: dropshort.v
|
|
// {{{
|
|
// Project: 10Gb Ethernet switch
|
|
//
|
|
// Purpose: Drops short packets by raising the ABORT flag if LAST arrives
|
|
// too early.
|
|
//
|
|
// 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 dropshort #(
|
|
// {{{
|
|
parameter DW=32, // Bits per beat
|
|
parameter [0:0] OPT_LOWPOWER = 0,
|
|
parameter MINBYTES = 64
|
|
// }}}
|
|
) (
|
|
// {{{
|
|
input wire S_CLK, S_ARESETN,
|
|
//
|
|
// Incoming packet data
|
|
// {{{
|
|
input wire S_VALID,
|
|
output wire S_READY,
|
|
input wire [DW-1:0] S_DATA,
|
|
input wire [$clog2(DW/8)-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 [$clog2(DW/8)-1:0] M_BYTES,
|
|
output reg M_ABORT,
|
|
output reg M_LAST
|
|
// }}}
|
|
// }}}
|
|
);
|
|
|
|
localparam LENBITS = $clog2(MINBYTES+1)+1,
|
|
MSB = LENBITS-1,
|
|
BW = $clog2(DW/8);
|
|
reg [MSB:0] pktlen;
|
|
reg midpacket;
|
|
reg [$clog2(DW/8):0] i_bytes;
|
|
|
|
// pktlen
|
|
// {{{
|
|
always @(posedge S_CLK)
|
|
if (!S_ARESETN)
|
|
pktlen <= 0;
|
|
else if (S_ABORT && (!S_VALID || S_READY))
|
|
pktlen <= 0;
|
|
else if (S_VALID && S_READY)
|
|
begin
|
|
if (S_LAST)
|
|
pktlen <= 0;
|
|
else if (!pktlen[MSB])
|
|
pktlen <= pktlen + 1;
|
|
end
|
|
// }}}
|
|
|
|
// midpacket
|
|
// {{{
|
|
always @(posedge S_CLK)
|
|
if (!S_ARESETN)
|
|
midpacket <= 0;
|
|
else if (S_ABORT && (!S_VALID || S_READY))
|
|
midpacket <= 0;
|
|
else if (S_VALID && S_READY)
|
|
begin
|
|
if (S_LAST)
|
|
midpacket <= 0;
|
|
else
|
|
midpacket <= 1;
|
|
end
|
|
// }}}
|
|
|
|
// i_bytes
|
|
// {{{
|
|
always @(*)
|
|
if (S_BYTES[$clog2(DW/8)-1] == 0)
|
|
i_bytes = { 1'b1, {($clog2(DW/8)){1'b0}} };
|
|
else
|
|
i_bytes = { 1'b0, S_BYTES };
|
|
// }}}
|
|
|
|
// M_VALID
|
|
// {{{
|
|
initial M_VALID = 1'b0;
|
|
always @(posedge S_CLK)
|
|
if (!S_ARESETN)
|
|
M_VALID <= 0;
|
|
else if (!M_VALID || M_READY)
|
|
M_VALID <= S_VALID && !S_ABORT;
|
|
// }}}
|
|
|
|
// M_DATA, M_BYTES, M_LAST
|
|
// {{{
|
|
always @(posedge S_CLK)
|
|
if (OPT_LOWPOWER && !S_ARESETN)
|
|
{ M_DATA, M_BYTES, M_LAST } <= 0;
|
|
else if (!M_VALID || M_READY)
|
|
begin
|
|
M_DATA <= S_DATA;
|
|
M_BYTES <= S_BYTES;
|
|
M_LAST <= S_LAST;
|
|
if (OPT_LOWPOWER && (!S_VALID || S_ABORT))
|
|
{ M_DATA, M_BYTES, M_LAST } <= 0;
|
|
end
|
|
// }}}
|
|
|
|
// M_ABORT
|
|
// {{{
|
|
initial M_ABORT = 1'b0;
|
|
always @(posedge S_CLK)
|
|
if (!S_ARESETN)
|
|
M_ABORT <= 0;
|
|
else if (S_ABORT && midpacket && (!M_VALID || !M_LAST))
|
|
M_ABORT <= 1;
|
|
else if (!M_VALID || M_READY)
|
|
begin
|
|
M_ABORT <= 0;
|
|
// Verilator lint_off WIDTH
|
|
if (S_VALID && S_READY && S_LAST && !pktlen[MSB])
|
|
M_ABORT <= ({ pktlen,{(BW){1'b0}} } + i_bytes
|
|
< MINBYTES);
|
|
// Verilator lint_on WIDTH
|
|
end
|
|
// }}}
|
|
|
|
assign S_READY = (!M_VALID || M_READY);
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Formal properties
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
`ifdef FORMAL
|
|
wire [12-1:0] fslv_packets, fmst_packets;
|
|
wire [11-1:0] fslv_word, fmst_word;
|
|
(* anyconst *) reg [DW:0] fnvr_data;
|
|
(* anyconst *) reg f_nvr_abort;
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Interface checks
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
faxin_slave #(
|
|
.DATA_WIDTH(DW),
|
|
.MIN_LENGTH(0)
|
|
) fslv (
|
|
// {{{
|
|
.S_AXI_ACLK(S_CLK), .S_AXI_ARESETN(S_ARESETN),
|
|
.S_AXIN_VALID(S_VALID),
|
|
.S_AXIN_READY(S_READY),
|
|
.S_AXIN_DATA(S_DATA),
|
|
.S_AXIN_BYTES(S_BYTES),
|
|
.S_AXIN_LAST(S_LAST),
|
|
.S_AXIN_ABORT(S_ABORT),
|
|
.f_stream_word(fslv_word),
|
|
.f_packets_rcvd(fslv_packets)
|
|
// }}}
|
|
);
|
|
|
|
faxin_master #(
|
|
.DATA_WIDTH(DW),
|
|
.MIN_LENGTH(0)
|
|
) fmst (
|
|
// {{{
|
|
.S_AXI_ACLK(S_CLK), .S_AXI_ARESETN(S_ARESETN),
|
|
.S_AXIN_VALID(M_VALID),
|
|
.S_AXIN_READY(M_READY),
|
|
.S_AXIN_DATA(M_DATA),
|
|
.S_AXIN_BYTES(M_BYTES),
|
|
.S_AXIN_LAST(M_LAST),
|
|
.S_AXIN_ABORT(M_ABORT),
|
|
.f_stream_word(fmst_word),
|
|
.f_packets_rcvd(fmst_packets)
|
|
// }}}
|
|
);
|
|
|
|
always @(*)
|
|
if (S_ARESETN && !M_ABORT && (!M_VALID || !M_LAST))
|
|
begin
|
|
assert(fslv_word == fmst_word + (M_VALID ? 1:0));
|
|
end
|
|
|
|
always @(*)
|
|
if (S_ARESETN)
|
|
begin
|
|
if (M_ABORT || (M_VALID && M_LAST))
|
|
begin
|
|
assert(fslv_word == 0);
|
|
if (!S_VALID || !S_ABORT)
|
|
assert(!midpacket);
|
|
end else if (M_VALID)
|
|
begin
|
|
assert(fslv_word > 0);
|
|
assert(midpacket);
|
|
end
|
|
|
|
if (!pktlen[MSB])
|
|
begin
|
|
assert(M_ABORT || pktlen == fslv_word);
|
|
end else begin
|
|
assert(M_ABORT || pktlen <= fslv_word);
|
|
end
|
|
|
|
assert(midpacket == (pktlen != 0));
|
|
end
|
|
|
|
always @(*)
|
|
if (S_VALID && !S_ABORT)
|
|
assume({ S_LAST, S_DATA } != fnvr_data);
|
|
|
|
always @(*)
|
|
if (S_ARESETN && M_VALID && !M_ABORT)
|
|
assert({ M_LAST, M_DATA } != fnvr_data);
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Never abort checking
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
always @(*)
|
|
if (f_nvr_abort)
|
|
assume(!midpacket || !S_ABORT);
|
|
|
|
always @(*)
|
|
if (S_ARESETN && f_nvr_abort)
|
|
assume(!S_VALID || !S_LAST || (S_BYTES + pktlen >= MINBYTES));
|
|
|
|
always @(*)
|
|
if (S_ARESETN && f_nvr_abort)
|
|
assert(!M_ABORT);
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Lowpower checking
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(*)
|
|
if (S_ARESETN && OPT_LOWPOWER && !M_VALID)
|
|
begin
|
|
assert(M_DATA == 0);
|
|
assert(M_BYTES == 0);
|
|
assert(M_LAST == 0);
|
|
end
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Cover checking
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
always @(*)
|
|
if (S_ARESETN)
|
|
begin
|
|
cover(M_ABORT);
|
|
cover(M_ABORT && M_VALID);
|
|
cover(M_ABORT && !M_VALID);
|
|
cover(M_VALID && M_LAST && M_READY);
|
|
end
|
|
|
|
always @(posedge S_CLK)
|
|
if (S_ARESETN)
|
|
begin
|
|
cover($rose(M_ABORT) && !$past(S_ABORT));
|
|
cover($rose(M_ABORT) && $past(S_ABORT && !S_LAST));
|
|
end
|
|
|
|
// }}}
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// "Careless" (?) assumptions
|
|
// {{{
|
|
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
//
|
|
|
|
always @(*)
|
|
begin
|
|
assume(fmst_packets < 12'h3fe);
|
|
assume(!fslv_word[10]);
|
|
end
|
|
|
|
// }}}
|
|
`endif // FORMAL
|
|
// }}}
|
|
endmodule
|