mirror of
https://github.com/openhwgroup/cvw.git
synced 2025-04-19 03:24:50 -04:00
Cleanup in prep to merge the rvvi branch into main.
This commit is contained in:
parent
ce2cc48642
commit
0d40b8c933
21 changed files with 10 additions and 6312 deletions
|
@ -2,6 +2,7 @@ rtl/eth_mac_mii_fifo.sv
|
|||
rtl/eth_mac_mii.sv
|
||||
rtl/mii_phy_if.sv
|
||||
rtl/ssio_ddr_in.sv
|
||||
rtl/ssio_sdr_in.sv
|
||||
rtl/eth_mac_1g.sv
|
||||
rtl/axis_gmii_rx.sv
|
||||
rtl/lfsr.sv
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 13c33ff1a82348691a40d78cf2bab10cbf4f76b2
|
||||
Subproject commit 43990ab4fd0c8d34dbc1be5cd8d4f3ed3e33f853
|
|
@ -32,30 +32,25 @@ set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe2]
|
|||
connect_debug_port u_ila_0/probe2 [get_nets [list wallypipelinedsoc/core/InstrValidM ]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 4 [get_debug_ports u_ila_0/probe3]
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe3]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe3]
|
||||
connect_debug_port u_ila_0/probe3 [get_nets [list {ethernet/eth_mac_1g_mii_inst/mii_phy_if_inst/mac_mii_txd[0]} {ethernet/eth_mac_1g_mii_inst/mii_phy_if_inst/mac_mii_txd[1]} {ethernet/eth_mac_1g_mii_inst/mii_phy_if_inst/mac_mii_txd[2]} {ethernet/eth_mac_1g_mii_inst/mii_phy_if_inst/mac_mii_txd[3]} ]]
|
||||
connect_debug_port u_ila_0/probe3 [get_nets [list {RvviAxiRlast}]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 4 [get_debug_ports u_ila_0/probe4]
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe4]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe4]
|
||||
connect_debug_port u_ila_0/probe4 [get_nets [list {packetizer/CurrState[0]} {packetizer/CurrState[1]} {packetizer/CurrState[2]} {packetizer/CurrState[3]}]]
|
||||
connect_debug_port u_ila_0/probe4 [get_nets [list {RvviAxiRvalid}]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe5]
|
||||
set_property port_width 4 [get_debug_ports u_ila_0/probe5]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe5]
|
||||
connect_debug_port u_ila_0/probe5 [get_nets [list {ethernet/eth_mac_1g_mii_inst/mii_phy_if_inst/mac_mii_tx_en} ]]
|
||||
connect_debug_port u_ila_0/probe5 [get_nets [list {packetizer/CurrState[0]} {packetizer/CurrState[1]} {packetizer/CurrState[2]} {packetizer/CurrState[3]}]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 64 [get_debug_ports u_ila_0/probe6]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe6]
|
||||
connect_debug_port u_ila_0/probe6 [get_nets [list {wallypipelinedsoc/core/PCM[0]} {wallypipelinedsoc/core/PCM[1]} {wallypipelinedsoc/core/PCM[2]} {wallypipelinedsoc/core/PCM[3]} {wallypipelinedsoc/core/PCM[4]} {wallypipelinedsoc/core/PCM[5]} {wallypipelinedsoc/core/PCM[6]} {wallypipelinedsoc/core/PCM[7]} {wallypipelinedsoc/core/PCM[8]} {wallypipelinedsoc/core/PCM[9]} {wallypipelinedsoc/core/PCM[10]} {wallypipelinedsoc/core/PCM[11]} {wallypipelinedsoc/core/PCM[12]} {wallypipelinedsoc/core/PCM[13]} {wallypipelinedsoc/core/PCM[14]} {wallypipelinedsoc/core/PCM[15]} {wallypipelinedsoc/core/PCM[16]} {wallypipelinedsoc/core/PCM[17]} {wallypipelinedsoc/core/PCM[18]} {wallypipelinedsoc/core/PCM[19]} {wallypipelinedsoc/core/PCM[20]} {wallypipelinedsoc/core/PCM[21]} {wallypipelinedsoc/core/PCM[22]} {wallypipelinedsoc/core/PCM[23]} {wallypipelinedsoc/core/PCM[24]} {wallypipelinedsoc/core/PCM[25]} {wallypipelinedsoc/core/PCM[26]} {wallypipelinedsoc/core/PCM[27]} {wallypipelinedsoc/core/PCM[28]} {wallypipelinedsoc/core/PCM[29]} {wallypipelinedsoc/core/PCM[30]} {wallypipelinedsoc/core/PCM[31]} {wallypipelinedsoc/core/PCM[32]} {wallypipelinedsoc/core/PCM[33]} {wallypipelinedsoc/core/PCM[34]} {wallypipelinedsoc/core/PCM[35]} {wallypipelinedsoc/core/PCM[36]} {wallypipelinedsoc/core/PCM[37]} {wallypipelinedsoc/core/PCM[38]} {wallypipelinedsoc/core/PCM[39]} {wallypipelinedsoc/core/PCM[40]} {wallypipelinedsoc/core/PCM[41]} {wallypipelinedsoc/core/PCM[42]} {wallypipelinedsoc/core/PCM[43]} {wallypipelinedsoc/core/PCM[44]} {wallypipelinedsoc/core/PCM[45]} {wallypipelinedsoc/core/PCM[46]} {wallypipelinedsoc/core/PCM[47]} {wallypipelinedsoc/core/PCM[48]} {wallypipelinedsoc/core/PCM[49]} {wallypipelinedsoc/core/PCM[50]} {wallypipelinedsoc/core/PCM[51]} {wallypipelinedsoc/core/PCM[52]} {wallypipelinedsoc/core/PCM[53]} {wallypipelinedsoc/core/PCM[54]} {wallypipelinedsoc/core/PCM[55]} {wallypipelinedsoc/core/PCM[56]} {wallypipelinedsoc/core/PCM[57]} {wallypipelinedsoc/core/PCM[58]} {wallypipelinedsoc/core/PCM[59]} {wallypipelinedsoc/core/PCM[60]} {wallypipelinedsoc/core/PCM[61]} {wallypipelinedsoc/core/PCM[62]} {wallypipelinedsoc/core/PCM[63]} ]]
|
||||
|
||||
#create_debug_port u_ila_0 probe
|
||||
#set_property port_width 1 [get_debug_ports u_ila_0/probe7]
|
||||
#set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe7]
|
||||
#connect_debug_port u_ila_0/probe7 [get_nets [list {IlaTrigger} ]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe7]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe7]
|
||||
|
@ -81,16 +76,6 @@ set_property port_width 3 [get_debug_ports u_ila_0/probe11]
|
|||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe11]
|
||||
connect_debug_port u_ila_0/probe11 [get_nets [list {triggergen/CurrState[0]} {triggergen/CurrState[1]} {triggergen/CurrState[2]}]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe12]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe12]
|
||||
connect_debug_port u_ila_0/probe12 [get_nets [list {RvviAxiRlast}]]
|
||||
|
||||
create_debug_port u_ila_0 probe
|
||||
set_property port_width 1 [get_debug_ports u_ila_0/probe13]
|
||||
set_property PROBE_TYPE DATA_AND_TRIGGER [get_debug_ports u_ila_0/probe13]
|
||||
connect_debug_port u_ila_0/probe13 [get_nets [list {RvviAxiRvalid}]]
|
||||
|
||||
|
||||
# the debug hub has issues with the clocks from the mmcm so lets give up an connect to the 100Mhz input clock.
|
||||
#connect_debug_port dbg_hub/clk [get_nets default_100mhz_clk]
|
||||
|
|
|
@ -51,6 +51,8 @@ PreProcessFiles:
|
|||
$(MAKE) -C ../../sim deriv
|
||||
rm -rf ../src/CopiedFiles_do_not_add_to_repo/
|
||||
cp -r ../../src/ ../src/CopiedFiles_do_not_add_to_repo/
|
||||
cp -r ../../addins/verilog-ethernet/*/*.sv ../src/CopiedFiles_do_not_add_to_repo/rvvi
|
||||
cp -r ../../addins/verilog-ethernet/*/*/*/*.sv ../src/CopiedFiles_do_not_add_to_repo/rvvi
|
||||
mkdir ../src/CopiedFiles_do_not_add_to_repo/config/
|
||||
cp ../../config/deriv/fpga/config.vh ../src/CopiedFiles_do_not_add_to_repo/config/
|
||||
./insert_debug_comment.sh
|
||||
|
|
|
@ -1,324 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2014-2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream bus width adapter
|
||||
*/
|
||||
module axis_adapter #
|
||||
(
|
||||
// Width of input AXI stream interface in bits
|
||||
parameter S_DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal on input interface
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle) on input interface
|
||||
parameter S_KEEP_WIDTH = ((S_DATA_WIDTH+7)/8),
|
||||
// Width of output AXI stream interface in bits
|
||||
parameter M_DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal on output interface
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle) on output interface
|
||||
parameter M_KEEP_WIDTH = ((M_DATA_WIDTH+7)/8),
|
||||
// Propagate tid signal
|
||||
parameter ID_ENABLE = 0,
|
||||
// tid signal width
|
||||
parameter ID_WIDTH = 8,
|
||||
// Propagate tdest signal
|
||||
parameter DEST_ENABLE = 0,
|
||||
// tdest signal width
|
||||
parameter DEST_WIDTH = 8,
|
||||
// Propagate tuser signal
|
||||
parameter USER_ENABLE = 1,
|
||||
// tuser signal width
|
||||
parameter USER_WIDTH = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [S_DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [S_KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [ID_WIDTH-1:0] s_axis_tid,
|
||||
input wire [DEST_WIDTH-1:0] s_axis_tdest,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [M_DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [M_KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire [ID_WIDTH-1:0] m_axis_tid,
|
||||
output wire [DEST_WIDTH-1:0] m_axis_tdest,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser
|
||||
);
|
||||
|
||||
// force keep width to 1 when disabled
|
||||
localparam S_BYTE_LANES = S_KEEP_ENABLE ? S_KEEP_WIDTH : 1;
|
||||
localparam M_BYTE_LANES = M_KEEP_ENABLE ? M_KEEP_WIDTH : 1;
|
||||
|
||||
// bus byte sizes (must be identical)
|
||||
localparam S_BYTE_SIZE = S_DATA_WIDTH / S_BYTE_LANES;
|
||||
localparam M_BYTE_SIZE = M_DATA_WIDTH / M_BYTE_LANES;
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (S_BYTE_SIZE * S_BYTE_LANES != S_DATA_WIDTH) begin
|
||||
$error("Error: input data width not evenly divisible (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (M_BYTE_SIZE * M_BYTE_LANES != M_DATA_WIDTH) begin
|
||||
$error("Error: output data width not evenly divisible (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (S_BYTE_SIZE != M_BYTE_SIZE) begin
|
||||
$error("Error: byte size mismatch (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
generate
|
||||
|
||||
if (M_BYTE_LANES == S_BYTE_LANES) begin : bypass
|
||||
// same width; bypass
|
||||
|
||||
assign s_axis_tready = m_axis_tready;
|
||||
|
||||
assign m_axis_tdata = s_axis_tdata;
|
||||
assign m_axis_tkeep = M_KEEP_ENABLE ? s_axis_tkeep : {M_KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = s_axis_tvalid;
|
||||
assign m_axis_tlast = s_axis_tlast;
|
||||
assign m_axis_tid = ID_ENABLE ? s_axis_tid : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest = DEST_ENABLE ? s_axis_tdest : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser = USER_ENABLE ? s_axis_tuser : {USER_WIDTH{1'b0}};
|
||||
|
||||
end else if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize
|
||||
// output is wider; upsize
|
||||
|
||||
// required number of segments in wider bus
|
||||
localparam SEG_COUNT = M_BYTE_LANES / S_BYTE_LANES;
|
||||
// data width and keep width per segment
|
||||
localparam SEG_DATA_WIDTH = M_DATA_WIDTH / SEG_COUNT;
|
||||
localparam SEG_KEEP_WIDTH = M_BYTE_LANES / SEG_COUNT;
|
||||
|
||||
reg [$clog2(SEG_COUNT)-1:0] seg_reg = 0;
|
||||
|
||||
reg [S_DATA_WIDTH-1:0] s_axis_tdata_reg = {S_DATA_WIDTH{1'b0}};
|
||||
reg [S_KEEP_WIDTH-1:0] s_axis_tkeep_reg = {S_KEEP_WIDTH{1'b0}};
|
||||
reg s_axis_tvalid_reg = 1'b0;
|
||||
reg s_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] s_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] s_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] s_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
reg [M_DATA_WIDTH-1:0] m_axis_tdata_reg = {M_DATA_WIDTH{1'b0}};
|
||||
reg [M_KEEP_WIDTH-1:0] m_axis_tkeep_reg = {M_KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
assign s_axis_tready = !s_axis_tvalid_reg;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = M_KEEP_ENABLE ? m_axis_tkeep_reg : {M_KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||
|
||||
always @(posedge clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_reg && !m_axis_tready;
|
||||
|
||||
if (!m_axis_tvalid_reg || m_axis_tready) begin
|
||||
// output register empty
|
||||
|
||||
if (seg_reg == 0) begin
|
||||
m_axis_tdata_reg[seg_reg*SEG_DATA_WIDTH +: SEG_DATA_WIDTH] <= s_axis_tvalid_reg ? s_axis_tdata_reg : s_axis_tdata;
|
||||
m_axis_tkeep_reg <= s_axis_tvalid_reg ? s_axis_tkeep_reg : s_axis_tkeep;
|
||||
end else begin
|
||||
m_axis_tdata_reg[seg_reg*SEG_DATA_WIDTH +: SEG_DATA_WIDTH] <= s_axis_tdata;
|
||||
m_axis_tkeep_reg[seg_reg*SEG_KEEP_WIDTH +: SEG_KEEP_WIDTH] <= s_axis_tkeep;
|
||||
end
|
||||
m_axis_tlast_reg <= s_axis_tvalid_reg ? s_axis_tlast_reg : s_axis_tlast;
|
||||
m_axis_tid_reg <= s_axis_tvalid_reg ? s_axis_tid_reg : s_axis_tid;
|
||||
m_axis_tdest_reg <= s_axis_tvalid_reg ? s_axis_tdest_reg : s_axis_tdest;
|
||||
m_axis_tuser_reg <= s_axis_tvalid_reg ? s_axis_tuser_reg : s_axis_tuser;
|
||||
|
||||
if (s_axis_tvalid_reg) begin
|
||||
// consume data from buffer
|
||||
s_axis_tvalid_reg <= 1'b0;
|
||||
|
||||
if (s_axis_tlast_reg || seg_reg == SEG_COUNT-1) begin
|
||||
seg_reg <= 0;
|
||||
m_axis_tvalid_reg <= 1'b1;
|
||||
end else begin
|
||||
seg_reg <= seg_reg + 1;
|
||||
end
|
||||
end else if (s_axis_tvalid) begin
|
||||
// data direct from input
|
||||
if (s_axis_tlast || seg_reg == SEG_COUNT-1) begin
|
||||
seg_reg <= 0;
|
||||
m_axis_tvalid_reg <= 1'b1;
|
||||
end else begin
|
||||
seg_reg <= seg_reg + 1;
|
||||
end
|
||||
end
|
||||
end else if (s_axis_tvalid && s_axis_tready) begin
|
||||
// store input data in skid buffer
|
||||
s_axis_tdata_reg <= s_axis_tdata;
|
||||
s_axis_tkeep_reg <= s_axis_tkeep;
|
||||
s_axis_tvalid_reg <= 1'b1;
|
||||
s_axis_tlast_reg <= s_axis_tlast;
|
||||
s_axis_tid_reg <= s_axis_tid;
|
||||
s_axis_tdest_reg <= s_axis_tdest;
|
||||
s_axis_tuser_reg <= s_axis_tuser;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
seg_reg <= 0;
|
||||
s_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin : downsize
|
||||
// output is narrower; downsize
|
||||
|
||||
// required number of segments in wider bus
|
||||
localparam SEG_COUNT = S_BYTE_LANES / M_BYTE_LANES;
|
||||
// data width and keep width per segment
|
||||
localparam SEG_DATA_WIDTH = S_DATA_WIDTH / SEG_COUNT;
|
||||
localparam SEG_KEEP_WIDTH = S_BYTE_LANES / SEG_COUNT;
|
||||
|
||||
reg [S_DATA_WIDTH-1:0] s_axis_tdata_reg = {S_DATA_WIDTH{1'b0}};
|
||||
reg [S_KEEP_WIDTH-1:0] s_axis_tkeep_reg = {S_KEEP_WIDTH{1'b0}};
|
||||
reg s_axis_tvalid_reg = 1'b0;
|
||||
reg s_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] s_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] s_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] s_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
reg [M_DATA_WIDTH-1:0] m_axis_tdata_reg = {M_DATA_WIDTH{1'b0}};
|
||||
reg [M_KEEP_WIDTH-1:0] m_axis_tkeep_reg = {M_KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
assign s_axis_tready = !s_axis_tvalid_reg;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = M_KEEP_ENABLE ? m_axis_tkeep_reg : {M_KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||
|
||||
always @(posedge clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_reg && !m_axis_tready;
|
||||
|
||||
if (!m_axis_tvalid_reg || m_axis_tready) begin
|
||||
// output register empty
|
||||
|
||||
m_axis_tdata_reg <= s_axis_tvalid_reg ? s_axis_tdata_reg : s_axis_tdata;
|
||||
m_axis_tkeep_reg <= s_axis_tvalid_reg ? s_axis_tkeep_reg : s_axis_tkeep;
|
||||
m_axis_tlast_reg <= 1'b0;
|
||||
m_axis_tid_reg <= s_axis_tvalid_reg ? s_axis_tid_reg : s_axis_tid;
|
||||
m_axis_tdest_reg <= s_axis_tvalid_reg ? s_axis_tdest_reg : s_axis_tdest;
|
||||
m_axis_tuser_reg <= s_axis_tvalid_reg ? s_axis_tuser_reg : s_axis_tuser;
|
||||
|
||||
if (s_axis_tvalid_reg) begin
|
||||
// buffer has data; shift out from buffer
|
||||
s_axis_tdata_reg <= s_axis_tdata_reg >> SEG_DATA_WIDTH;
|
||||
s_axis_tkeep_reg <= s_axis_tkeep_reg >> SEG_KEEP_WIDTH;
|
||||
|
||||
m_axis_tvalid_reg <= 1'b1;
|
||||
|
||||
if ((s_axis_tkeep_reg >> SEG_KEEP_WIDTH) == 0) begin
|
||||
s_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tlast_reg <= s_axis_tlast_reg;
|
||||
end
|
||||
end else if (s_axis_tvalid && s_axis_tready) begin
|
||||
// buffer is empty; store from input
|
||||
s_axis_tdata_reg <= s_axis_tdata >> SEG_DATA_WIDTH;
|
||||
s_axis_tkeep_reg <= s_axis_tkeep >> SEG_KEEP_WIDTH;
|
||||
s_axis_tlast_reg <= s_axis_tlast;
|
||||
s_axis_tid_reg <= s_axis_tid;
|
||||
s_axis_tdest_reg <= s_axis_tdest;
|
||||
s_axis_tuser_reg <= s_axis_tuser;
|
||||
|
||||
m_axis_tvalid_reg <= 1'b1;
|
||||
|
||||
if ((s_axis_tkeep >> SEG_KEEP_WIDTH) == 0) begin
|
||||
s_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tlast_reg <= s_axis_tlast;
|
||||
end else begin
|
||||
s_axis_tvalid_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else if (s_axis_tvalid && s_axis_tready) begin
|
||||
// store input data
|
||||
s_axis_tdata_reg <= s_axis_tdata;
|
||||
s_axis_tkeep_reg <= s_axis_tkeep;
|
||||
s_axis_tvalid_reg <= 1'b1;
|
||||
s_axis_tlast_reg <= s_axis_tlast;
|
||||
s_axis_tid_reg <= s_axis_tid;
|
||||
s_axis_tdest_reg <= s_axis_tdest;
|
||||
s_axis_tuser_reg <= s_axis_tuser;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
s_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,909 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2014-2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream asynchronous FIFO
|
||||
*/
|
||||
module axis_async_fifo #
|
||||
(
|
||||
// FIFO depth in words
|
||||
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
|
||||
// Rounded up to nearest power of 2 cycles
|
||||
parameter DEPTH = 4096,
|
||||
// Width of AXI stream interfaces in bits
|
||||
parameter DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter KEEP_ENABLE = (DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle)
|
||||
parameter KEEP_WIDTH = ((DATA_WIDTH+7)/8),
|
||||
// Propagate tlast signal
|
||||
parameter LAST_ENABLE = 1,
|
||||
// Propagate tid signal
|
||||
parameter ID_ENABLE = 0,
|
||||
// tid signal width
|
||||
parameter ID_WIDTH = 8,
|
||||
// Propagate tdest signal
|
||||
parameter DEST_ENABLE = 0,
|
||||
// tdest signal width
|
||||
parameter DEST_WIDTH = 8,
|
||||
// Propagate tuser signal
|
||||
parameter USER_ENABLE = 1,
|
||||
// tuser signal width
|
||||
parameter USER_WIDTH = 1,
|
||||
// number of RAM pipeline registers
|
||||
parameter RAM_PIPELINE = 1,
|
||||
// use output FIFO
|
||||
// When set, the RAM read enable and pipeline clock enables are removed
|
||||
parameter OUTPUT_FIFO_ENABLE = 0,
|
||||
// Frame FIFO mode - operate on frames instead of cycles
|
||||
// When set, m_axis_tvalid will not be deasserted within a frame
|
||||
// Requires LAST_ENABLE set
|
||||
parameter FRAME_FIFO = 0,
|
||||
// tuser value for bad frame marker
|
||||
parameter USER_BAD_FRAME_VALUE = 1'b1,
|
||||
// tuser mask for bad frame marker
|
||||
parameter USER_BAD_FRAME_MASK = 1'b1,
|
||||
// Drop frames larger than FIFO
|
||||
// Requires FRAME_FIFO set
|
||||
parameter DROP_OVERSIZE_FRAME = FRAME_FIFO,
|
||||
// Drop frames marked bad
|
||||
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
||||
parameter DROP_BAD_FRAME = 0,
|
||||
// Drop incoming frames when full
|
||||
// When set, s_axis_tready is always asserted
|
||||
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
||||
parameter DROP_WHEN_FULL = 0,
|
||||
// Mark incoming frames as bad frames when full
|
||||
// When set, s_axis_tready is always asserted
|
||||
// Requires FRAME_FIFO to be clear
|
||||
parameter MARK_WHEN_FULL = 0,
|
||||
// Enable pause request input
|
||||
parameter PAUSE_ENABLE = 0,
|
||||
// Pause between frames
|
||||
parameter FRAME_PAUSE = FRAME_FIFO
|
||||
)
|
||||
(
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire s_clk,
|
||||
input wire s_rst,
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [ID_WIDTH-1:0] s_axis_tid,
|
||||
input wire [DEST_WIDTH-1:0] s_axis_tdest,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
input wire m_clk,
|
||||
input wire m_rst,
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire [ID_WIDTH-1:0] m_axis_tid,
|
||||
output wire [DEST_WIDTH-1:0] m_axis_tdest,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser,
|
||||
|
||||
/*
|
||||
* Pause
|
||||
*/
|
||||
input wire s_pause_req,
|
||||
output wire s_pause_ack,
|
||||
input wire m_pause_req,
|
||||
output wire m_pause_ack,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire [$clog2(DEPTH):0] s_status_depth,
|
||||
output wire [$clog2(DEPTH):0] s_status_depth_commit,
|
||||
output wire s_status_overflow,
|
||||
output wire s_status_bad_frame,
|
||||
output wire s_status_good_frame,
|
||||
output wire [$clog2(DEPTH):0] m_status_depth,
|
||||
output wire [$clog2(DEPTH):0] m_status_depth_commit,
|
||||
output wire m_status_overflow,
|
||||
output wire m_status_bad_frame,
|
||||
output wire m_status_good_frame
|
||||
);
|
||||
|
||||
parameter ADDR_WIDTH = (KEEP_ENABLE && KEEP_WIDTH > 1) ? $clog2(DEPTH/KEEP_WIDTH) : $clog2(DEPTH);
|
||||
|
||||
parameter OUTPUT_FIFO_ADDR_WIDTH = RAM_PIPELINE < 2 ? 3 : $clog2(RAM_PIPELINE*2+7);
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (FRAME_FIFO && !LAST_ENABLE) begin
|
||||
$error("Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (DROP_OVERSIZE_FRAME && !FRAME_FIFO) begin
|
||||
$error("Error: DROP_OVERSIZE_FRAME set requires FRAME_FIFO set (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (DROP_BAD_FRAME && !(FRAME_FIFO && DROP_OVERSIZE_FRAME)) begin
|
||||
$error("Error: DROP_BAD_FRAME set requires FRAME_FIFO and DROP_OVERSIZE_FRAME set (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (DROP_WHEN_FULL && !(FRAME_FIFO && DROP_OVERSIZE_FRAME)) begin
|
||||
$error("Error: DROP_WHEN_FULL set requires FRAME_FIFO and DROP_OVERSIZE_FRAME set (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if ((DROP_BAD_FRAME || MARK_WHEN_FULL) && (USER_BAD_FRAME_MASK & {USER_WIDTH{1'b1}}) == 0) begin
|
||||
$error("Error: Invalid USER_BAD_FRAME_MASK value (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (MARK_WHEN_FULL && FRAME_FIFO) begin
|
||||
$error("Error: MARK_WHEN_FULL is not compatible with FRAME_FIFO (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (MARK_WHEN_FULL && !LAST_ENABLE) begin
|
||||
$error("Error: MARK_WHEN_FULL set requires LAST_ENABLE set (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
localparam KEEP_OFFSET = DATA_WIDTH;
|
||||
localparam LAST_OFFSET = KEEP_OFFSET + (KEEP_ENABLE ? KEEP_WIDTH : 0);
|
||||
localparam ID_OFFSET = LAST_OFFSET + (LAST_ENABLE ? 1 : 0);
|
||||
localparam DEST_OFFSET = ID_OFFSET + (ID_ENABLE ? ID_WIDTH : 0);
|
||||
localparam USER_OFFSET = DEST_OFFSET + (DEST_ENABLE ? DEST_WIDTH : 0);
|
||||
localparam WIDTH = USER_OFFSET + (USER_ENABLE ? USER_WIDTH : 0);
|
||||
|
||||
function [ADDR_WIDTH:0] bin2gray(input [ADDR_WIDTH:0] b);
|
||||
bin2gray = b ^ (b >> 1);
|
||||
endfunction
|
||||
|
||||
function [ADDR_WIDTH:0] gray2bin(input [ADDR_WIDTH:0] g);
|
||||
integer i;
|
||||
for (i = 0; i <= ADDR_WIDTH; i = i + 1) begin
|
||||
gray2bin[i] = ^(g >> i);
|
||||
end
|
||||
endfunction
|
||||
|
||||
reg [ADDR_WIDTH:0] wr_ptr_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] wr_ptr_commit_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] wr_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] wr_ptr_sync_commit_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] rd_ptr_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] rd_ptr_gray_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] wr_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
reg [ADDR_WIDTH:0] rd_ptr_conv_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
|
||||
reg [ADDR_WIDTH:0] wr_ptr_temp;
|
||||
reg [ADDR_WIDTH:0] rd_ptr_temp;
|
||||
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg [ADDR_WIDTH:0] wr_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg [ADDR_WIDTH:0] wr_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg [ADDR_WIDTH:0] wr_ptr_commit_sync_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg [ADDR_WIDTH:0] rd_ptr_gray_sync1_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg [ADDR_WIDTH:0] rd_ptr_gray_sync2_reg = {ADDR_WIDTH+1{1'b0}};
|
||||
|
||||
reg wr_ptr_update_valid_reg = 1'b0;
|
||||
reg wr_ptr_update_reg = 1'b0;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg wr_ptr_update_sync1_reg = 1'b0;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg wr_ptr_update_sync2_reg = 1'b0;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg wr_ptr_update_sync3_reg = 1'b0;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg wr_ptr_update_ack_sync1_reg = 1'b0;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg wr_ptr_update_ack_sync2_reg = 1'b0;
|
||||
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg s_rst_sync1_reg = 1'b1;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg s_rst_sync2_reg = 1'b1;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg s_rst_sync3_reg = 1'b1;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg m_rst_sync1_reg = 1'b1;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg m_rst_sync2_reg = 1'b1;
|
||||
(* SHREG_EXTRACT = "NO" *)
|
||||
reg m_rst_sync3_reg = 1'b1;
|
||||
|
||||
(* ramstyle = "no_rw_check" *)
|
||||
reg [WIDTH-1:0] mem[(2**ADDR_WIDTH)-1:0];
|
||||
reg mem_read_data_valid_reg = 1'b0;
|
||||
|
||||
(* shreg_extract = "no" *)
|
||||
reg [WIDTH-1:0] m_axis_pipe_reg[RAM_PIPELINE+1-1:0];
|
||||
reg [RAM_PIPELINE+1-1:0] m_axis_tvalid_pipe_reg = 0;
|
||||
|
||||
// full when first TWO MSBs do NOT match, but rest matches
|
||||
// (gray code equivalent of first MSB different but rest same)
|
||||
wire full = wr_ptr_gray_reg == (rd_ptr_gray_sync2_reg ^ {2'b11, {ADDR_WIDTH-1{1'b0}}});
|
||||
// empty when pointers match exactly
|
||||
wire empty = FRAME_FIFO ? (rd_ptr_reg == wr_ptr_commit_sync_reg) : (rd_ptr_gray_reg == wr_ptr_gray_sync2_reg);
|
||||
// overflow within packet
|
||||
wire full_wr = wr_ptr_reg == (wr_ptr_commit_reg ^ {1'b1, {ADDR_WIDTH{1'b0}}});
|
||||
|
||||
// control signals
|
||||
reg write;
|
||||
reg read;
|
||||
reg store_output;
|
||||
|
||||
reg s_frame_reg = 1'b0;
|
||||
reg m_frame_reg = 1'b0;
|
||||
|
||||
reg drop_frame_reg = 1'b0;
|
||||
reg mark_frame_reg = 1'b0;
|
||||
reg send_frame_reg = 1'b0;
|
||||
reg overflow_reg = 1'b0;
|
||||
reg bad_frame_reg = 1'b0;
|
||||
reg good_frame_reg = 1'b0;
|
||||
|
||||
reg m_drop_frame_reg = 1'b0;
|
||||
reg m_terminate_frame_reg = 1'b0;
|
||||
|
||||
reg [ADDR_WIDTH:0] s_depth_reg = 0;
|
||||
reg [ADDR_WIDTH:0] s_depth_commit_reg = 0;
|
||||
reg [ADDR_WIDTH:0] m_depth_reg = 0;
|
||||
reg [ADDR_WIDTH:0] m_depth_commit_reg = 0;
|
||||
|
||||
reg overflow_sync1_reg = 1'b0;
|
||||
reg overflow_sync2_reg = 1'b0;
|
||||
reg overflow_sync3_reg = 1'b0;
|
||||
reg overflow_sync4_reg = 1'b0;
|
||||
reg bad_frame_sync1_reg = 1'b0;
|
||||
reg bad_frame_sync2_reg = 1'b0;
|
||||
reg bad_frame_sync3_reg = 1'b0;
|
||||
reg bad_frame_sync4_reg = 1'b0;
|
||||
reg good_frame_sync1_reg = 1'b0;
|
||||
reg good_frame_sync2_reg = 1'b0;
|
||||
reg good_frame_sync3_reg = 1'b0;
|
||||
reg good_frame_sync4_reg = 1'b0;
|
||||
|
||||
assign s_axis_tready = (FRAME_FIFO ? (!full || (full_wr && DROP_OVERSIZE_FRAME) || DROP_WHEN_FULL) : (!full || MARK_WHEN_FULL)) && !s_rst_sync3_reg;
|
||||
|
||||
wire [WIDTH-1:0] s_axis;
|
||||
|
||||
generate
|
||||
assign s_axis[DATA_WIDTH-1:0] = s_axis_tdata;
|
||||
if (KEEP_ENABLE) assign s_axis[KEEP_OFFSET +: KEEP_WIDTH] = s_axis_tkeep;
|
||||
if (LAST_ENABLE) assign s_axis[LAST_OFFSET] = s_axis_tlast | mark_frame_reg;
|
||||
if (ID_ENABLE) assign s_axis[ID_OFFSET +: ID_WIDTH] = s_axis_tid;
|
||||
if (DEST_ENABLE) assign s_axis[DEST_OFFSET +: DEST_WIDTH] = s_axis_tdest;
|
||||
if (USER_ENABLE) assign s_axis[USER_OFFSET +: USER_WIDTH] = mark_frame_reg ? USER_BAD_FRAME_VALUE : s_axis_tuser;
|
||||
endgenerate
|
||||
|
||||
wire [WIDTH-1:0] m_axis = m_axis_pipe_reg[RAM_PIPELINE+1-1];
|
||||
|
||||
wire m_axis_tready_pipe;
|
||||
wire m_axis_tvalid_pipe = m_axis_tvalid_pipe_reg[RAM_PIPELINE+1-1];
|
||||
|
||||
wire [DATA_WIDTH-1:0] m_axis_tdata_pipe = m_axis[DATA_WIDTH-1:0];
|
||||
wire [KEEP_WIDTH-1:0] m_axis_tkeep_pipe = KEEP_ENABLE ? m_axis[KEEP_OFFSET +: KEEP_WIDTH] : {KEEP_WIDTH{1'b1}};
|
||||
wire m_axis_tlast_pipe = LAST_ENABLE ? m_axis[LAST_OFFSET] | m_terminate_frame_reg : 1'b1;
|
||||
wire [ID_WIDTH-1:0] m_axis_tid_pipe = ID_ENABLE ? m_axis[ID_OFFSET +: ID_WIDTH] : {ID_WIDTH{1'b0}};
|
||||
wire [DEST_WIDTH-1:0] m_axis_tdest_pipe = DEST_ENABLE ? m_axis[DEST_OFFSET +: DEST_WIDTH] : {DEST_WIDTH{1'b0}};
|
||||
wire [USER_WIDTH-1:0] m_axis_tuser_pipe = USER_ENABLE ? (m_terminate_frame_reg ? USER_BAD_FRAME_VALUE : m_axis[USER_OFFSET +: USER_WIDTH]) : {USER_WIDTH{1'b0}};
|
||||
|
||||
wire m_axis_tready_out;
|
||||
wire m_axis_tvalid_out;
|
||||
|
||||
wire [DATA_WIDTH-1:0] m_axis_tdata_out;
|
||||
wire [KEEP_WIDTH-1:0] m_axis_tkeep_out;
|
||||
wire m_axis_tlast_out;
|
||||
wire [ID_WIDTH-1:0] m_axis_tid_out;
|
||||
wire [DEST_WIDTH-1:0] m_axis_tdest_out;
|
||||
wire [USER_WIDTH-1:0] m_axis_tuser_out;
|
||||
|
||||
wire pipe_ready;
|
||||
|
||||
assign s_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_reg;
|
||||
assign s_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {s_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : s_depth_commit_reg;
|
||||
assign s_status_overflow = overflow_reg;
|
||||
assign s_status_bad_frame = bad_frame_reg;
|
||||
assign s_status_good_frame = good_frame_reg;
|
||||
|
||||
assign m_status_depth = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_reg;
|
||||
assign m_status_depth_commit = (KEEP_ENABLE && KEEP_WIDTH > 1) ? {m_depth_commit_reg, {$clog2(KEEP_WIDTH){1'b0}}} : m_depth_commit_reg;
|
||||
assign m_status_overflow = overflow_sync3_reg ^ overflow_sync4_reg;
|
||||
assign m_status_bad_frame = bad_frame_sync3_reg ^ bad_frame_sync4_reg;
|
||||
assign m_status_good_frame = good_frame_sync3_reg ^ good_frame_sync4_reg;
|
||||
|
||||
// reset synchronization
|
||||
always @(posedge m_clk or posedge m_rst) begin
|
||||
if (m_rst) begin
|
||||
s_rst_sync1_reg <= 1'b1;
|
||||
end else begin
|
||||
s_rst_sync1_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge s_clk) begin
|
||||
s_rst_sync2_reg <= s_rst_sync1_reg;
|
||||
s_rst_sync3_reg <= s_rst_sync2_reg;
|
||||
end
|
||||
|
||||
always @(posedge s_clk or posedge s_rst) begin
|
||||
if (s_rst) begin
|
||||
m_rst_sync1_reg <= 1'b1;
|
||||
end else begin
|
||||
m_rst_sync1_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
m_rst_sync2_reg <= m_rst_sync1_reg;
|
||||
m_rst_sync3_reg <= m_rst_sync2_reg;
|
||||
end
|
||||
|
||||
// Write logic
|
||||
always @(posedge s_clk) begin
|
||||
overflow_reg <= 1'b0;
|
||||
bad_frame_reg <= 1'b0;
|
||||
good_frame_reg <= 1'b0;
|
||||
|
||||
if (FRAME_FIFO && wr_ptr_update_valid_reg) begin
|
||||
// have updated pointer to sync
|
||||
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
|
||||
// no sync in progress; sync update
|
||||
wr_ptr_update_valid_reg <= 1'b0;
|
||||
wr_ptr_sync_commit_reg <= wr_ptr_commit_reg;
|
||||
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
|
||||
end
|
||||
end
|
||||
|
||||
if (s_axis_tready && s_axis_tvalid && LAST_ENABLE) begin
|
||||
// track input frame status
|
||||
s_frame_reg <= !s_axis_tlast;
|
||||
end
|
||||
|
||||
if (s_rst_sync3_reg && LAST_ENABLE) begin
|
||||
// if sink side is reset during transfer, drop partial frame
|
||||
if (s_frame_reg && !(s_axis_tready && s_axis_tvalid && s_axis_tlast)) begin
|
||||
drop_frame_reg <= 1'b1;
|
||||
end
|
||||
if (s_axis_tready && s_axis_tvalid && !s_axis_tlast) begin
|
||||
drop_frame_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (FRAME_FIFO) begin
|
||||
// frame FIFO mode
|
||||
if (s_axis_tready && s_axis_tvalid) begin
|
||||
// transfer in
|
||||
if ((full && DROP_WHEN_FULL) || (full_wr && DROP_OVERSIZE_FRAME) || drop_frame_reg) begin
|
||||
// full, packet overflow, or currently dropping frame
|
||||
// drop frame
|
||||
drop_frame_reg <= 1'b1;
|
||||
if (s_axis_tlast) begin
|
||||
// end of frame, reset write pointer
|
||||
wr_ptr_temp = wr_ptr_commit_reg;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
drop_frame_reg <= 1'b0;
|
||||
overflow_reg <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
|
||||
wr_ptr_temp = wr_ptr_reg + 1;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
if (s_axis_tlast || (!DROP_OVERSIZE_FRAME && (full_wr || send_frame_reg))) begin
|
||||
// end of frame or send frame
|
||||
send_frame_reg <= !s_axis_tlast;
|
||||
if (s_axis_tlast && DROP_BAD_FRAME && USER_BAD_FRAME_MASK & ~(s_axis_tuser ^ USER_BAD_FRAME_VALUE)) begin
|
||||
// bad packet, reset write pointer
|
||||
wr_ptr_temp = wr_ptr_commit_reg;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
bad_frame_reg <= 1'b1;
|
||||
end else begin
|
||||
// good packet or packet overflow, update write pointer
|
||||
wr_ptr_temp = wr_ptr_reg + 1;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
|
||||
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
|
||||
// no sync in progress; sync update
|
||||
wr_ptr_update_valid_reg <= 1'b0;
|
||||
wr_ptr_sync_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
|
||||
end else begin
|
||||
// sync in progress; flag it for later
|
||||
wr_ptr_update_valid_reg <= 1'b1;
|
||||
end
|
||||
|
||||
good_frame_reg <= s_axis_tlast;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else if (s_axis_tvalid && full_wr && FRAME_FIFO && !DROP_OVERSIZE_FRAME) begin
|
||||
// data valid with packet overflow
|
||||
// update write pointer
|
||||
send_frame_reg <= 1'b1;
|
||||
wr_ptr_temp = wr_ptr_reg;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
|
||||
if (wr_ptr_update_reg == wr_ptr_update_ack_sync2_reg) begin
|
||||
// no sync in progress; sync update
|
||||
wr_ptr_update_valid_reg <= 1'b0;
|
||||
wr_ptr_sync_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_update_reg <= !wr_ptr_update_ack_sync2_reg;
|
||||
end else begin
|
||||
// sync in progress; flag it for later
|
||||
wr_ptr_update_valid_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
// normal FIFO mode
|
||||
if (s_axis_tready && s_axis_tvalid) begin
|
||||
if (drop_frame_reg && LAST_ENABLE) begin
|
||||
// currently dropping frame
|
||||
if (s_axis_tlast) begin
|
||||
// end of frame
|
||||
if (!full && mark_frame_reg && MARK_WHEN_FULL) begin
|
||||
// terminate marked frame
|
||||
mark_frame_reg <= 1'b0;
|
||||
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
|
||||
wr_ptr_temp = wr_ptr_reg + 1;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
end
|
||||
// end of frame, clear drop flag
|
||||
drop_frame_reg <= 1'b0;
|
||||
overflow_reg <= 1'b1;
|
||||
end
|
||||
end else if ((full || mark_frame_reg) && MARK_WHEN_FULL) begin
|
||||
// full or marking frame
|
||||
// drop frame; mark if this isn't the first cycle
|
||||
drop_frame_reg <= 1'b1;
|
||||
mark_frame_reg <= mark_frame_reg || s_frame_reg;
|
||||
if (s_axis_tlast) begin
|
||||
drop_frame_reg <= 1'b0;
|
||||
overflow_reg <= 1'b1;
|
||||
end
|
||||
end else begin
|
||||
// transfer in
|
||||
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
|
||||
wr_ptr_temp = wr_ptr_reg + 1;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
end
|
||||
end else if ((!full && !drop_frame_reg && mark_frame_reg) && MARK_WHEN_FULL) begin
|
||||
// terminate marked frame
|
||||
mark_frame_reg <= 1'b0;
|
||||
mem[wr_ptr_reg[ADDR_WIDTH-1:0]] <= s_axis;
|
||||
wr_ptr_temp = wr_ptr_reg + 1;
|
||||
wr_ptr_reg <= wr_ptr_temp;
|
||||
wr_ptr_commit_reg <= wr_ptr_temp;
|
||||
wr_ptr_gray_reg <= bin2gray(wr_ptr_temp);
|
||||
end
|
||||
end
|
||||
|
||||
if (s_rst_sync3_reg) begin
|
||||
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
|
||||
wr_ptr_update_valid_reg <= 1'b0;
|
||||
wr_ptr_update_reg <= 1'b0;
|
||||
end
|
||||
|
||||
if (s_rst) begin
|
||||
wr_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_commit_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_sync_commit_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
|
||||
wr_ptr_update_valid_reg <= 1'b0;
|
||||
wr_ptr_update_reg <= 1'b0;
|
||||
|
||||
s_frame_reg <= 1'b0;
|
||||
|
||||
drop_frame_reg <= 1'b0;
|
||||
mark_frame_reg <= 1'b0;
|
||||
send_frame_reg <= 1'b0;
|
||||
overflow_reg <= 1'b0;
|
||||
bad_frame_reg <= 1'b0;
|
||||
good_frame_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// Write-side status
|
||||
always @(posedge s_clk) begin
|
||||
rd_ptr_conv_reg <= gray2bin(rd_ptr_gray_sync2_reg);
|
||||
s_depth_reg <= wr_ptr_reg - rd_ptr_conv_reg;
|
||||
s_depth_commit_reg <= wr_ptr_commit_reg - rd_ptr_conv_reg;
|
||||
end
|
||||
|
||||
// pointer synchronization
|
||||
always @(posedge s_clk) begin
|
||||
rd_ptr_gray_sync1_reg <= rd_ptr_gray_reg;
|
||||
rd_ptr_gray_sync2_reg <= rd_ptr_gray_sync1_reg;
|
||||
wr_ptr_update_ack_sync1_reg <= wr_ptr_update_sync3_reg;
|
||||
wr_ptr_update_ack_sync2_reg <= wr_ptr_update_ack_sync1_reg;
|
||||
|
||||
if (s_rst) begin
|
||||
rd_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
rd_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_update_ack_sync1_reg <= 1'b0;
|
||||
wr_ptr_update_ack_sync2_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
wr_ptr_gray_sync1_reg <= wr_ptr_gray_reg;
|
||||
wr_ptr_gray_sync2_reg <= wr_ptr_gray_sync1_reg;
|
||||
if (FRAME_FIFO && wr_ptr_update_sync2_reg ^ wr_ptr_update_sync3_reg) begin
|
||||
wr_ptr_commit_sync_reg <= wr_ptr_sync_commit_reg;
|
||||
end
|
||||
wr_ptr_update_sync1_reg <= wr_ptr_update_reg;
|
||||
wr_ptr_update_sync2_reg <= wr_ptr_update_sync1_reg;
|
||||
wr_ptr_update_sync3_reg <= wr_ptr_update_sync2_reg;
|
||||
|
||||
if (FRAME_FIFO && m_rst_sync3_reg) begin
|
||||
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
end
|
||||
|
||||
if (m_rst) begin
|
||||
wr_ptr_gray_sync1_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_gray_sync2_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_commit_sync_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
wr_ptr_update_sync1_reg <= 1'b0;
|
||||
wr_ptr_update_sync2_reg <= 1'b0;
|
||||
wr_ptr_update_sync3_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// status synchronization
|
||||
always @(posedge s_clk) begin
|
||||
overflow_sync1_reg <= overflow_sync1_reg ^ overflow_reg;
|
||||
bad_frame_sync1_reg <= bad_frame_sync1_reg ^ bad_frame_reg;
|
||||
good_frame_sync1_reg <= good_frame_sync1_reg ^ good_frame_reg;
|
||||
|
||||
if (s_rst) begin
|
||||
overflow_sync1_reg <= 1'b0;
|
||||
bad_frame_sync1_reg <= 1'b0;
|
||||
good_frame_sync1_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
overflow_sync2_reg <= overflow_sync1_reg;
|
||||
overflow_sync3_reg <= overflow_sync2_reg;
|
||||
overflow_sync4_reg <= overflow_sync3_reg;
|
||||
bad_frame_sync2_reg <= bad_frame_sync1_reg;
|
||||
bad_frame_sync3_reg <= bad_frame_sync2_reg;
|
||||
bad_frame_sync4_reg <= bad_frame_sync3_reg;
|
||||
good_frame_sync2_reg <= good_frame_sync1_reg;
|
||||
good_frame_sync3_reg <= good_frame_sync2_reg;
|
||||
good_frame_sync4_reg <= good_frame_sync3_reg;
|
||||
|
||||
if (m_rst) begin
|
||||
overflow_sync2_reg <= 1'b0;
|
||||
overflow_sync3_reg <= 1'b0;
|
||||
overflow_sync4_reg <= 1'b0;
|
||||
bad_frame_sync2_reg <= 1'b0;
|
||||
bad_frame_sync3_reg <= 1'b0;
|
||||
bad_frame_sync4_reg <= 1'b0;
|
||||
good_frame_sync2_reg <= 1'b0;
|
||||
good_frame_sync3_reg <= 1'b0;
|
||||
good_frame_sync4_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// Read logic
|
||||
integer j;
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
if (m_axis_tready_pipe) begin
|
||||
// output ready; invalidate stage
|
||||
m_axis_tvalid_pipe_reg[RAM_PIPELINE+1-1] <= 1'b0;
|
||||
m_terminate_frame_reg <= 1'b0;
|
||||
end
|
||||
|
||||
for (j = RAM_PIPELINE+1-1; j > 0; j = j - 1) begin
|
||||
if (m_axis_tready_pipe || ((~m_axis_tvalid_pipe_reg) >> j)) begin
|
||||
// output ready or bubble in pipeline; transfer down pipeline
|
||||
m_axis_tvalid_pipe_reg[j] <= m_axis_tvalid_pipe_reg[j-1];
|
||||
m_axis_pipe_reg[j] <= m_axis_pipe_reg[j-1];
|
||||
m_axis_tvalid_pipe_reg[j-1] <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
if (m_axis_tready_pipe || ~m_axis_tvalid_pipe_reg) begin
|
||||
// output ready or bubble in pipeline; read new data from FIFO
|
||||
m_axis_tvalid_pipe_reg[0] <= 1'b0;
|
||||
m_axis_pipe_reg[0] <= mem[rd_ptr_reg[ADDR_WIDTH-1:0]];
|
||||
if (!empty && !m_rst_sync3_reg && !m_drop_frame_reg && pipe_ready) begin
|
||||
// not empty, increment pointer
|
||||
m_axis_tvalid_pipe_reg[0] <= 1'b1;
|
||||
rd_ptr_temp = rd_ptr_reg + 1;
|
||||
rd_ptr_reg <= rd_ptr_temp;
|
||||
rd_ptr_gray_reg <= rd_ptr_temp ^ (rd_ptr_temp >> 1);
|
||||
end
|
||||
end
|
||||
|
||||
if (m_axis_tvalid_pipe && LAST_ENABLE) begin
|
||||
// track output frame status
|
||||
if (m_axis_tlast_pipe && m_axis_tready_pipe) begin
|
||||
m_frame_reg <= 1'b0;
|
||||
end else begin
|
||||
m_frame_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (m_drop_frame_reg && (OUTPUT_FIFO_ENABLE ? pipe_ready : m_axis_tready_pipe || !m_axis_tvalid_pipe) && LAST_ENABLE) begin
|
||||
// terminate frame
|
||||
// (only for frame transfers interrupted by source reset)
|
||||
m_axis_tvalid_pipe_reg[RAM_PIPELINE+1-1] <= 1'b1;
|
||||
m_terminate_frame_reg <= 1'b1;
|
||||
m_drop_frame_reg <= 1'b0;
|
||||
end
|
||||
|
||||
if (m_rst_sync3_reg && LAST_ENABLE) begin
|
||||
// if source side is reset during transfer, drop partial frame
|
||||
|
||||
// empty output pipeline, except for last stage
|
||||
if (RAM_PIPELINE > 0) begin
|
||||
m_axis_tvalid_pipe_reg[RAM_PIPELINE+1-2:0] <= 0;
|
||||
end
|
||||
|
||||
if (m_frame_reg && (!m_axis_tvalid_pipe || (m_axis_tvalid_pipe && !m_axis_tlast_pipe)) &&
|
||||
!(m_drop_frame_reg || m_terminate_frame_reg)) begin
|
||||
// terminate frame
|
||||
m_drop_frame_reg <= 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (m_rst_sync3_reg) begin
|
||||
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
end
|
||||
|
||||
if (m_rst) begin
|
||||
rd_ptr_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
rd_ptr_gray_reg <= {ADDR_WIDTH+1{1'b0}};
|
||||
m_axis_tvalid_pipe_reg <= 0;
|
||||
m_frame_reg <= 1'b0;
|
||||
m_drop_frame_reg <= 1'b0;
|
||||
m_terminate_frame_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// Read-side status
|
||||
always @(posedge m_clk) begin
|
||||
wr_ptr_conv_reg <= gray2bin(wr_ptr_gray_sync2_reg);
|
||||
m_depth_reg <= wr_ptr_conv_reg - rd_ptr_reg;
|
||||
m_depth_commit_reg <= FRAME_FIFO ? wr_ptr_commit_sync_reg - rd_ptr_reg : wr_ptr_conv_reg - rd_ptr_reg;
|
||||
end
|
||||
|
||||
generate
|
||||
|
||||
if (!OUTPUT_FIFO_ENABLE) begin
|
||||
|
||||
assign pipe_ready = 1'b1;
|
||||
|
||||
assign m_axis_tready_pipe = m_axis_tready_out;
|
||||
assign m_axis_tvalid_out = m_axis_tvalid_pipe;
|
||||
|
||||
assign m_axis_tdata_out = m_axis_tdata_pipe;
|
||||
assign m_axis_tkeep_out = m_axis_tkeep_pipe;
|
||||
assign m_axis_tlast_out = m_axis_tlast_pipe;
|
||||
assign m_axis_tid_out = m_axis_tid_pipe;
|
||||
assign m_axis_tdest_out = m_axis_tdest_pipe;
|
||||
assign m_axis_tuser_out = m_axis_tuser_pipe;
|
||||
|
||||
end else begin : output_fifo
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_wr_ptr_reg = 0;
|
||||
reg [OUTPUT_FIFO_ADDR_WIDTH+1-1:0] out_fifo_rd_ptr_reg = 0;
|
||||
reg out_fifo_half_full_reg = 1'b0;
|
||||
|
||||
wire out_fifo_full = out_fifo_wr_ptr_reg == (out_fifo_rd_ptr_reg ^ {1'b1, {OUTPUT_FIFO_ADDR_WIDTH{1'b0}}});
|
||||
wire out_fifo_empty = out_fifo_wr_ptr_reg == out_fifo_rd_ptr_reg;
|
||||
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg [DATA_WIDTH-1:0] out_fifo_tdata[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg [KEEP_WIDTH-1:0] out_fifo_tkeep[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg out_fifo_tlast[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg [ID_WIDTH-1:0] out_fifo_tid[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg [DEST_WIDTH-1:0] out_fifo_tdest[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
(* ram_style = "distributed", ramstyle = "no_rw_check, mlab" *)
|
||||
reg [USER_WIDTH-1:0] out_fifo_tuser[2**OUTPUT_FIFO_ADDR_WIDTH-1:0];
|
||||
|
||||
assign pipe_ready = !out_fifo_half_full_reg;
|
||||
|
||||
assign m_axis_tready_pipe = 1'b1;
|
||||
|
||||
assign m_axis_tdata_out = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep_out = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid_out = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast_out = LAST_ENABLE ? m_axis_tlast_reg : 1'b1;
|
||||
assign m_axis_tid_out = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest_out = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser_out = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_reg && !m_axis_tready_out;
|
||||
|
||||
out_fifo_half_full_reg <= $unsigned(out_fifo_wr_ptr_reg - out_fifo_rd_ptr_reg) >= 2**(OUTPUT_FIFO_ADDR_WIDTH-1);
|
||||
|
||||
if (!out_fifo_full && m_axis_tvalid_pipe) begin
|
||||
out_fifo_tdata[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tdata_pipe;
|
||||
out_fifo_tkeep[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tkeep_pipe;
|
||||
out_fifo_tlast[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tlast_pipe;
|
||||
out_fifo_tid[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tid_pipe;
|
||||
out_fifo_tdest[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tdest_pipe;
|
||||
out_fifo_tuser[out_fifo_wr_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]] <= m_axis_tuser_pipe;
|
||||
out_fifo_wr_ptr_reg <= out_fifo_wr_ptr_reg + 1;
|
||||
end
|
||||
|
||||
if (!out_fifo_empty && (!m_axis_tvalid_reg || m_axis_tready_out)) begin
|
||||
m_axis_tdata_reg <= out_fifo_tdata[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
m_axis_tkeep_reg <= out_fifo_tkeep[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
m_axis_tvalid_reg <= 1'b1;
|
||||
m_axis_tlast_reg <= out_fifo_tlast[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
m_axis_tid_reg <= out_fifo_tid[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
m_axis_tdest_reg <= out_fifo_tdest[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
m_axis_tuser_reg <= out_fifo_tuser[out_fifo_rd_ptr_reg[OUTPUT_FIFO_ADDR_WIDTH-1:0]];
|
||||
out_fifo_rd_ptr_reg <= out_fifo_rd_ptr_reg + 1;
|
||||
end
|
||||
|
||||
if (m_rst) begin
|
||||
out_fifo_wr_ptr_reg <= 0;
|
||||
out_fifo_rd_ptr_reg <= 0;
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if (PAUSE_ENABLE) begin : pause
|
||||
|
||||
// Pause logic
|
||||
reg pause_reg = 1'b0;
|
||||
reg pause_frame_reg = 1'b0;
|
||||
|
||||
reg s_pause_req_sync1_reg;
|
||||
reg s_pause_req_sync2_reg;
|
||||
reg s_pause_req_sync3_reg;
|
||||
reg s_pause_ack_sync1_reg;
|
||||
reg s_pause_ack_sync2_reg;
|
||||
reg s_pause_ack_sync3_reg;
|
||||
|
||||
always @(posedge s_clk) begin
|
||||
s_pause_req_sync1_reg <= s_pause_req;
|
||||
s_pause_ack_sync2_reg <= s_pause_ack_sync1_reg;
|
||||
s_pause_ack_sync3_reg <= s_pause_ack_sync2_reg;
|
||||
end
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
s_pause_req_sync2_reg <= s_pause_req_sync1_reg;
|
||||
s_pause_req_sync3_reg <= s_pause_req_sync2_reg;
|
||||
s_pause_ack_sync1_reg <= pause_reg;
|
||||
end
|
||||
|
||||
assign m_axis_tready_out = m_axis_tready && !pause_reg;
|
||||
assign m_axis_tvalid = m_axis_tvalid_out && !pause_reg;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_out;
|
||||
assign m_axis_tkeep = m_axis_tkeep_out;
|
||||
assign m_axis_tlast = m_axis_tlast_out;
|
||||
assign m_axis_tid = m_axis_tid_out;
|
||||
assign m_axis_tdest = m_axis_tdest_out;
|
||||
assign m_axis_tuser = m_axis_tuser_out;
|
||||
|
||||
assign s_pause_ack = s_pause_ack_sync3_reg;
|
||||
assign m_pause_ack = pause_reg;
|
||||
|
||||
always @(posedge m_clk) begin
|
||||
if (FRAME_PAUSE) begin
|
||||
if (pause_reg) begin
|
||||
// paused; update pause status
|
||||
pause_reg <= m_pause_req || s_pause_req_sync3_reg;
|
||||
end else if (m_axis_tvalid_out) begin
|
||||
// frame transfer; set frame bit
|
||||
pause_frame_reg <= 1'b1;
|
||||
if (m_axis_tready && m_axis_tlast) begin
|
||||
// end of frame; clear frame bit and update pause status
|
||||
pause_frame_reg <= 1'b0;
|
||||
pause_reg <= m_pause_req || s_pause_req_sync3_reg;
|
||||
end
|
||||
end else if (!pause_frame_reg) begin
|
||||
// idle; update pause status
|
||||
pause_reg <= m_pause_req || s_pause_req_sync3_reg;
|
||||
end
|
||||
end else begin
|
||||
pause_reg <= m_pause_req || s_pause_req_sync3_reg;
|
||||
end
|
||||
|
||||
if (m_rst) begin
|
||||
pause_frame_reg <= 1'b0;
|
||||
pause_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
assign m_axis_tready_out = m_axis_tready;
|
||||
assign m_axis_tvalid = m_axis_tvalid_out;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_out;
|
||||
assign m_axis_tkeep = m_axis_tkeep_out;
|
||||
assign m_axis_tlast = m_axis_tlast_out;
|
||||
assign m_axis_tid = m_axis_tid_out;
|
||||
assign m_axis_tdest = m_axis_tdest_out;
|
||||
assign m_axis_tuser = m_axis_tuser_out;
|
||||
|
||||
assign s_pause_ack = 1'b0;
|
||||
assign m_pause_ack = 1'b0;
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,377 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2019 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream asynchronous FIFO with width converter
|
||||
*/
|
||||
module axis_async_fifo_adapter #
|
||||
(
|
||||
// FIFO depth in words
|
||||
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
|
||||
// Rounded up to nearest power of 2 cycles
|
||||
parameter DEPTH = 4096,
|
||||
// Width of input AXI stream interface in bits
|
||||
parameter S_DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal on input interface
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter S_KEEP_ENABLE = (S_DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle) on input interface
|
||||
parameter S_KEEP_WIDTH = ((S_DATA_WIDTH+7)/8),
|
||||
// Width of output AXI stream interface in bits
|
||||
parameter M_DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal on output interface
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter M_KEEP_ENABLE = (M_DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle) on output interface
|
||||
parameter M_KEEP_WIDTH = ((M_DATA_WIDTH+7)/8),
|
||||
// Propagate tid signal
|
||||
parameter ID_ENABLE = 0,
|
||||
// tid signal width
|
||||
parameter ID_WIDTH = 8,
|
||||
// Propagate tdest signal
|
||||
parameter DEST_ENABLE = 0,
|
||||
// tdest signal width
|
||||
parameter DEST_WIDTH = 8,
|
||||
// Propagate tuser signal
|
||||
parameter USER_ENABLE = 1,
|
||||
// tuser signal width
|
||||
parameter USER_WIDTH = 1,
|
||||
// number of RAM pipeline registers in FIFO
|
||||
parameter RAM_PIPELINE = 1,
|
||||
// use output FIFO
|
||||
// When set, the RAM read enable and pipeline clock enables are removed
|
||||
parameter OUTPUT_FIFO_ENABLE = 0,
|
||||
// Frame FIFO mode - operate on frames instead of cycles
|
||||
// When set, m_axis_tvalid will not be deasserted within a frame
|
||||
// Requires LAST_ENABLE set
|
||||
parameter FRAME_FIFO = 0,
|
||||
// tuser value for bad frame marker
|
||||
parameter USER_BAD_FRAME_VALUE = 1'b1,
|
||||
// tuser mask for bad frame marker
|
||||
parameter USER_BAD_FRAME_MASK = 1'b1,
|
||||
// Drop frames larger than FIFO
|
||||
// Requires FRAME_FIFO set
|
||||
parameter DROP_OVERSIZE_FRAME = FRAME_FIFO,
|
||||
// Drop frames marked bad
|
||||
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
||||
parameter DROP_BAD_FRAME = 0,
|
||||
// Drop incoming frames when full
|
||||
// When set, s_axis_tready is always asserted
|
||||
// Requires FRAME_FIFO and DROP_OVERSIZE_FRAME set
|
||||
parameter DROP_WHEN_FULL = 0,
|
||||
// Mark incoming frames as bad frames when full
|
||||
// When set, s_axis_tready is always asserted
|
||||
// Requires FRAME_FIFO to be clear
|
||||
parameter MARK_WHEN_FULL = 0,
|
||||
// Enable pause request input
|
||||
parameter PAUSE_ENABLE = 0,
|
||||
// Pause between frames
|
||||
parameter FRAME_PAUSE = FRAME_FIFO
|
||||
)
|
||||
(
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire s_clk,
|
||||
input wire s_rst,
|
||||
input wire [S_DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [S_KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [ID_WIDTH-1:0] s_axis_tid,
|
||||
input wire [DEST_WIDTH-1:0] s_axis_tdest,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
input wire m_clk,
|
||||
input wire m_rst,
|
||||
output wire [M_DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [M_KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire [ID_WIDTH-1:0] m_axis_tid,
|
||||
output wire [DEST_WIDTH-1:0] m_axis_tdest,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser,
|
||||
|
||||
/*
|
||||
* Pause
|
||||
*/
|
||||
input wire s_pause_req,
|
||||
output wire s_pause_ack,
|
||||
input wire m_pause_req,
|
||||
output wire m_pause_ack,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire [$clog2(DEPTH):0] s_status_depth,
|
||||
output wire [$clog2(DEPTH):0] s_status_depth_commit,
|
||||
output wire s_status_overflow,
|
||||
output wire s_status_bad_frame,
|
||||
output wire s_status_good_frame,
|
||||
output wire [$clog2(DEPTH):0] m_status_depth,
|
||||
output wire [$clog2(DEPTH):0] m_status_depth_commit,
|
||||
output wire m_status_overflow,
|
||||
output wire m_status_bad_frame,
|
||||
output wire m_status_good_frame
|
||||
);
|
||||
|
||||
// force keep width to 1 when disabled
|
||||
localparam S_BYTE_LANES = S_KEEP_ENABLE ? S_KEEP_WIDTH : 1;
|
||||
localparam M_BYTE_LANES = M_KEEP_ENABLE ? M_KEEP_WIDTH : 1;
|
||||
|
||||
// bus byte sizes (must be identical)
|
||||
localparam S_BYTE_SIZE = S_DATA_WIDTH / S_BYTE_LANES;
|
||||
localparam M_BYTE_SIZE = M_DATA_WIDTH / M_BYTE_LANES;
|
||||
// output bus is wider
|
||||
localparam EXPAND_BUS = M_BYTE_LANES > S_BYTE_LANES;
|
||||
// total data and keep widths
|
||||
localparam DATA_WIDTH = EXPAND_BUS ? M_DATA_WIDTH : S_DATA_WIDTH;
|
||||
localparam KEEP_WIDTH = EXPAND_BUS ? M_BYTE_LANES : S_BYTE_LANES;
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (S_BYTE_SIZE * S_BYTE_LANES != S_DATA_WIDTH) begin
|
||||
$error("Error: input data width not evenly divisible (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (M_BYTE_SIZE * M_BYTE_LANES != M_DATA_WIDTH) begin
|
||||
$error("Error: output data width not evenly divisible (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (S_BYTE_SIZE != M_BYTE_SIZE) begin
|
||||
$error("Error: byte size mismatch (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
wire [DATA_WIDTH-1:0] pre_fifo_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] pre_fifo_axis_tkeep;
|
||||
wire pre_fifo_axis_tvalid;
|
||||
wire pre_fifo_axis_tready;
|
||||
wire pre_fifo_axis_tlast;
|
||||
wire [ID_WIDTH-1:0] pre_fifo_axis_tid;
|
||||
wire [DEST_WIDTH-1:0] pre_fifo_axis_tdest;
|
||||
wire [USER_WIDTH-1:0] pre_fifo_axis_tuser;
|
||||
|
||||
wire [DATA_WIDTH-1:0] post_fifo_axis_tdata;
|
||||
wire [KEEP_WIDTH-1:0] post_fifo_axis_tkeep;
|
||||
wire post_fifo_axis_tvalid;
|
||||
wire post_fifo_axis_tready;
|
||||
wire post_fifo_axis_tlast;
|
||||
wire [ID_WIDTH-1:0] post_fifo_axis_tid;
|
||||
wire [DEST_WIDTH-1:0] post_fifo_axis_tdest;
|
||||
wire [USER_WIDTH-1:0] post_fifo_axis_tuser;
|
||||
|
||||
generate
|
||||
|
||||
if (M_BYTE_LANES > S_BYTE_LANES) begin : upsize_pre
|
||||
|
||||
// output wider, adapt width before FIFO
|
||||
|
||||
axis_adapter #(
|
||||
.S_DATA_WIDTH(S_DATA_WIDTH),
|
||||
.S_KEEP_ENABLE(S_KEEP_ENABLE),
|
||||
.S_KEEP_WIDTH(S_KEEP_WIDTH),
|
||||
.M_DATA_WIDTH(M_DATA_WIDTH),
|
||||
.M_KEEP_ENABLE(M_KEEP_ENABLE),
|
||||
.M_KEEP_WIDTH(M_KEEP_WIDTH),
|
||||
.ID_ENABLE(ID_ENABLE),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.DEST_ENABLE(DEST_ENABLE),
|
||||
.DEST_WIDTH(DEST_WIDTH),
|
||||
.USER_ENABLE(USER_ENABLE),
|
||||
.USER_WIDTH(USER_WIDTH)
|
||||
)
|
||||
adapter_inst (
|
||||
.clk(s_clk),
|
||||
.rst(s_rst),
|
||||
// AXI input
|
||||
.s_axis_tdata(s_axis_tdata),
|
||||
.s_axis_tkeep(s_axis_tkeep),
|
||||
.s_axis_tvalid(s_axis_tvalid),
|
||||
.s_axis_tready(s_axis_tready),
|
||||
.s_axis_tlast(s_axis_tlast),
|
||||
.s_axis_tid(s_axis_tid),
|
||||
.s_axis_tdest(s_axis_tdest),
|
||||
.s_axis_tuser(s_axis_tuser),
|
||||
// AXI output
|
||||
.m_axis_tdata(pre_fifo_axis_tdata),
|
||||
.m_axis_tkeep(pre_fifo_axis_tkeep),
|
||||
.m_axis_tvalid(pre_fifo_axis_tvalid),
|
||||
.m_axis_tready(pre_fifo_axis_tready),
|
||||
.m_axis_tlast(pre_fifo_axis_tlast),
|
||||
.m_axis_tid(pre_fifo_axis_tid),
|
||||
.m_axis_tdest(pre_fifo_axis_tdest),
|
||||
.m_axis_tuser(pre_fifo_axis_tuser)
|
||||
);
|
||||
|
||||
end else begin : bypass_pre
|
||||
|
||||
assign pre_fifo_axis_tdata = s_axis_tdata;
|
||||
assign pre_fifo_axis_tkeep = s_axis_tkeep;
|
||||
assign pre_fifo_axis_tvalid = s_axis_tvalid;
|
||||
assign s_axis_tready = pre_fifo_axis_tready;
|
||||
assign pre_fifo_axis_tlast = s_axis_tlast;
|
||||
assign pre_fifo_axis_tid = s_axis_tid;
|
||||
assign pre_fifo_axis_tdest = s_axis_tdest;
|
||||
assign pre_fifo_axis_tuser = s_axis_tuser;
|
||||
|
||||
end
|
||||
|
||||
axis_async_fifo #(
|
||||
.DEPTH(DEPTH),
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_ENABLE(EXPAND_BUS ? M_KEEP_ENABLE : S_KEEP_ENABLE),
|
||||
.KEEP_WIDTH(KEEP_WIDTH),
|
||||
.LAST_ENABLE(1),
|
||||
.ID_ENABLE(ID_ENABLE),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.DEST_ENABLE(DEST_ENABLE),
|
||||
.DEST_WIDTH(DEST_WIDTH),
|
||||
.USER_ENABLE(USER_ENABLE),
|
||||
.USER_WIDTH(USER_WIDTH),
|
||||
.RAM_PIPELINE(RAM_PIPELINE),
|
||||
.OUTPUT_FIFO_ENABLE(OUTPUT_FIFO_ENABLE),
|
||||
.FRAME_FIFO(FRAME_FIFO),
|
||||
.USER_BAD_FRAME_VALUE(USER_BAD_FRAME_VALUE),
|
||||
.USER_BAD_FRAME_MASK(USER_BAD_FRAME_MASK),
|
||||
.DROP_OVERSIZE_FRAME(DROP_OVERSIZE_FRAME),
|
||||
.DROP_BAD_FRAME(DROP_BAD_FRAME),
|
||||
.DROP_WHEN_FULL(DROP_WHEN_FULL),
|
||||
.MARK_WHEN_FULL(MARK_WHEN_FULL),
|
||||
.PAUSE_ENABLE(PAUSE_ENABLE),
|
||||
.FRAME_PAUSE(FRAME_PAUSE)
|
||||
)
|
||||
fifo_inst (
|
||||
// AXI input
|
||||
.s_clk(s_clk),
|
||||
.s_rst(s_rst),
|
||||
.s_axis_tdata(pre_fifo_axis_tdata),
|
||||
.s_axis_tkeep(pre_fifo_axis_tkeep),
|
||||
.s_axis_tvalid(pre_fifo_axis_tvalid),
|
||||
.s_axis_tready(pre_fifo_axis_tready),
|
||||
.s_axis_tlast(pre_fifo_axis_tlast),
|
||||
.s_axis_tid(pre_fifo_axis_tid),
|
||||
.s_axis_tdest(pre_fifo_axis_tdest),
|
||||
.s_axis_tuser(pre_fifo_axis_tuser),
|
||||
// AXI output
|
||||
.m_clk(m_clk),
|
||||
.m_rst(m_rst),
|
||||
.m_axis_tdata(post_fifo_axis_tdata),
|
||||
.m_axis_tkeep(post_fifo_axis_tkeep),
|
||||
.m_axis_tvalid(post_fifo_axis_tvalid),
|
||||
.m_axis_tready(post_fifo_axis_tready),
|
||||
.m_axis_tlast(post_fifo_axis_tlast),
|
||||
.m_axis_tid(post_fifo_axis_tid),
|
||||
.m_axis_tdest(post_fifo_axis_tdest),
|
||||
.m_axis_tuser(post_fifo_axis_tuser),
|
||||
// Pause
|
||||
.s_pause_req(s_pause_req),
|
||||
.s_pause_ack(s_pause_ack),
|
||||
.m_pause_req(m_pause_req),
|
||||
.m_pause_ack(m_pause_ack),
|
||||
// Status
|
||||
.s_status_depth(s_status_depth),
|
||||
.s_status_depth_commit(s_status_depth_commit),
|
||||
.s_status_overflow(s_status_overflow),
|
||||
.s_status_bad_frame(s_status_bad_frame),
|
||||
.s_status_good_frame(s_status_good_frame),
|
||||
.m_status_depth(m_status_depth),
|
||||
.m_status_depth_commit(m_status_depth_commit),
|
||||
.m_status_overflow(m_status_overflow),
|
||||
.m_status_bad_frame(m_status_bad_frame),
|
||||
.m_status_good_frame(m_status_good_frame)
|
||||
);
|
||||
|
||||
if (M_BYTE_LANES < S_BYTE_LANES) begin : downsize_post
|
||||
|
||||
// input wider, adapt width after FIFO
|
||||
|
||||
axis_adapter #(
|
||||
.S_DATA_WIDTH(S_DATA_WIDTH),
|
||||
.S_KEEP_ENABLE(S_KEEP_ENABLE),
|
||||
.S_KEEP_WIDTH(S_KEEP_WIDTH),
|
||||
.M_DATA_WIDTH(M_DATA_WIDTH),
|
||||
.M_KEEP_ENABLE(M_KEEP_ENABLE),
|
||||
.M_KEEP_WIDTH(M_KEEP_WIDTH),
|
||||
.ID_ENABLE(ID_ENABLE),
|
||||
.ID_WIDTH(ID_WIDTH),
|
||||
.DEST_ENABLE(DEST_ENABLE),
|
||||
.DEST_WIDTH(DEST_WIDTH),
|
||||
.USER_ENABLE(USER_ENABLE),
|
||||
.USER_WIDTH(USER_WIDTH)
|
||||
)
|
||||
adapter_inst (
|
||||
.clk(m_clk),
|
||||
.rst(m_rst),
|
||||
// AXI input
|
||||
.s_axis_tdata(post_fifo_axis_tdata),
|
||||
.s_axis_tkeep(post_fifo_axis_tkeep),
|
||||
.s_axis_tvalid(post_fifo_axis_tvalid),
|
||||
.s_axis_tready(post_fifo_axis_tready),
|
||||
.s_axis_tlast(post_fifo_axis_tlast),
|
||||
.s_axis_tid(post_fifo_axis_tid),
|
||||
.s_axis_tdest(post_fifo_axis_tdest),
|
||||
.s_axis_tuser(post_fifo_axis_tuser),
|
||||
// AXI output
|
||||
.m_axis_tdata(m_axis_tdata),
|
||||
.m_axis_tkeep(m_axis_tkeep),
|
||||
.m_axis_tvalid(m_axis_tvalid),
|
||||
.m_axis_tready(m_axis_tready),
|
||||
.m_axis_tlast(m_axis_tlast),
|
||||
.m_axis_tid(m_axis_tid),
|
||||
.m_axis_tdest(m_axis_tdest),
|
||||
.m_axis_tuser(m_axis_tuser)
|
||||
);
|
||||
|
||||
end else begin : bypass_post
|
||||
|
||||
assign m_axis_tdata = post_fifo_axis_tdata;
|
||||
assign m_axis_tkeep = post_fifo_axis_tkeep;
|
||||
assign m_axis_tvalid = post_fifo_axis_tvalid;
|
||||
assign post_fifo_axis_tready = m_axis_tready;
|
||||
assign m_axis_tlast = post_fifo_axis_tlast;
|
||||
assign m_axis_tid = post_fifo_axis_tid;
|
||||
assign m_axis_tdest = post_fifo_axis_tdest;
|
||||
assign m_axis_tuser = post_fifo_axis_tuser;
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,357 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015-2018 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream GMII frame receiver (GMII in, AXI out)
|
||||
*/
|
||||
module axis_gmii_rx #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter PTP_TS_ENABLE = 0,
|
||||
parameter PTP_TS_WIDTH = 96,
|
||||
parameter USER_WIDTH = (PTP_TS_ENABLE ? PTP_TS_WIDTH : 0) + 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* GMII input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] gmii_rxd,
|
||||
input wire gmii_rx_dv,
|
||||
input wire gmii_rx_er,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire m_axis_tvalid,
|
||||
output wire m_axis_tlast,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
input wire [PTP_TS_WIDTH-1:0] ptp_ts,
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
input wire clk_enable,
|
||||
input wire mii_select,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire cfg_rx_enable,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire start_packet,
|
||||
output wire error_bad_frame,
|
||||
output wire error_bad_fcs
|
||||
);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 8) begin
|
||||
$error("Error: Interface width must be 8");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
localparam [7:0]
|
||||
ETH_PRE = 8'h55,
|
||||
ETH_SFD = 8'hD5;
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_PAYLOAD = 3'd1,
|
||||
STATE_WAIT_LAST = 3'd2;
|
||||
|
||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
// datapath control signals
|
||||
reg reset_crc;
|
||||
reg update_crc;
|
||||
|
||||
reg mii_odd = 1'b0;
|
||||
reg in_frame = 1'b0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] gmii_rxd_d0 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] gmii_rxd_d1 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] gmii_rxd_d2 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] gmii_rxd_d3 = {DATA_WIDTH{1'b0}};
|
||||
reg [DATA_WIDTH-1:0] gmii_rxd_d4 = {DATA_WIDTH{1'b0}};
|
||||
|
||||
reg gmii_rx_dv_d0 = 1'b0;
|
||||
reg gmii_rx_dv_d1 = 1'b0;
|
||||
reg gmii_rx_dv_d2 = 1'b0;
|
||||
reg gmii_rx_dv_d3 = 1'b0;
|
||||
reg gmii_rx_dv_d4 = 1'b0;
|
||||
|
||||
reg gmii_rx_er_d0 = 1'b0;
|
||||
reg gmii_rx_er_d1 = 1'b0;
|
||||
reg gmii_rx_er_d2 = 1'b0;
|
||||
reg gmii_rx_er_d3 = 1'b0;
|
||||
reg gmii_rx_er_d4 = 1'b0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}}, m_axis_tdata_next;
|
||||
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
|
||||
reg m_axis_tlast_reg = 1'b0, m_axis_tlast_next;
|
||||
reg m_axis_tuser_reg = 1'b0, m_axis_tuser_next;
|
||||
|
||||
reg start_packet_int_reg = 1'b0;
|
||||
reg start_packet_reg = 1'b0;
|
||||
reg error_bad_frame_reg = 1'b0, error_bad_frame_next;
|
||||
reg error_bad_fcs_reg = 1'b0, error_bad_fcs_next;
|
||||
|
||||
reg [PTP_TS_WIDTH-1:0] ptp_ts_reg = 0;
|
||||
|
||||
reg [31:0] crc_state = 32'hFFFFFFFF;
|
||||
wire [31:0] crc_next;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tuser = PTP_TS_ENABLE ? {ptp_ts_reg, m_axis_tuser_reg} : m_axis_tuser_reg;
|
||||
|
||||
assign start_packet = start_packet_reg;
|
||||
assign error_bad_frame = error_bad_frame_reg;
|
||||
assign error_bad_fcs = error_bad_fcs_reg;
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(8),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_8 (
|
||||
.data_in(gmii_rxd_d4),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next)
|
||||
);
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
reset_crc = 1'b0;
|
||||
update_crc = 1'b0;
|
||||
|
||||
m_axis_tdata_next = {DATA_WIDTH{1'b0}};
|
||||
m_axis_tvalid_next = 1'b0;
|
||||
m_axis_tlast_next = 1'b0;
|
||||
m_axis_tuser_next = 1'b0;
|
||||
|
||||
error_bad_frame_next = 1'b0;
|
||||
error_bad_fcs_next = 1'b0;
|
||||
|
||||
if (!clk_enable) begin
|
||||
// clock disabled - hold state
|
||||
state_next = state_reg;
|
||||
end else if (mii_select && !mii_odd) begin
|
||||
// MII even cycle - hold state
|
||||
state_next = state_reg;
|
||||
end else begin
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for packet
|
||||
reset_crc = 1'b1;
|
||||
|
||||
if (gmii_rx_dv_d4 && !gmii_rx_er_d4 && gmii_rxd_d4 == ETH_SFD && cfg_rx_enable) begin
|
||||
state_next = STATE_PAYLOAD;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_PAYLOAD: begin
|
||||
// read payload
|
||||
update_crc = 1'b1;
|
||||
|
||||
m_axis_tdata_next = gmii_rxd_d4;
|
||||
m_axis_tvalid_next = 1'b1;
|
||||
|
||||
if (gmii_rx_dv_d4 && gmii_rx_er_d4) begin
|
||||
// error
|
||||
m_axis_tlast_next = 1'b1;
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
state_next = STATE_WAIT_LAST;
|
||||
end else if (!gmii_rx_dv) begin
|
||||
// end of packet
|
||||
m_axis_tlast_next = 1'b1;
|
||||
if (gmii_rx_er_d0 || gmii_rx_er_d1 || gmii_rx_er_d2 || gmii_rx_er_d3) begin
|
||||
// error received in FCS bytes
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
end else if ({gmii_rxd_d0, gmii_rxd_d1, gmii_rxd_d2, gmii_rxd_d3} == ~crc_next) begin
|
||||
// FCS good
|
||||
m_axis_tuser_next = 1'b0;
|
||||
end else begin
|
||||
// FCS bad
|
||||
m_axis_tuser_next = 1'b1;
|
||||
error_bad_frame_next = 1'b1;
|
||||
error_bad_fcs_next = 1'b1;
|
||||
end
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
state_next = STATE_PAYLOAD;
|
||||
end
|
||||
end
|
||||
STATE_WAIT_LAST: begin
|
||||
// wait for end of packet
|
||||
|
||||
if (~gmii_rx_dv) begin
|
||||
state_next = STATE_IDLE;
|
||||
end else begin
|
||||
state_next = STATE_WAIT_LAST;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
m_axis_tdata_reg <= m_axis_tdata_next;
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_next;
|
||||
m_axis_tlast_reg <= m_axis_tlast_next;
|
||||
m_axis_tuser_reg <= m_axis_tuser_next;
|
||||
|
||||
start_packet_int_reg <= 1'b0;
|
||||
start_packet_reg <= 1'b0;
|
||||
|
||||
if (start_packet_int_reg) begin
|
||||
ptp_ts_reg <= ptp_ts;
|
||||
start_packet_reg <= 1'b1;
|
||||
end
|
||||
|
||||
if (clk_enable) begin
|
||||
if (mii_select) begin
|
||||
mii_odd <= !mii_odd;
|
||||
|
||||
if (in_frame) begin
|
||||
in_frame <= gmii_rx_dv;
|
||||
end else if (gmii_rx_dv && {gmii_rxd[3:0], gmii_rxd_d0[7:4]} == ETH_SFD) begin
|
||||
in_frame <= 1'b1;
|
||||
start_packet_int_reg <= 1'b1;
|
||||
mii_odd <= 1'b1;
|
||||
end
|
||||
|
||||
gmii_rxd_d0 <= {gmii_rxd[3:0], gmii_rxd_d0[7:4]};
|
||||
|
||||
if (mii_odd) begin
|
||||
gmii_rxd_d1 <= gmii_rxd_d0;
|
||||
gmii_rxd_d2 <= gmii_rxd_d1;
|
||||
gmii_rxd_d3 <= gmii_rxd_d2;
|
||||
gmii_rxd_d4 <= gmii_rxd_d3;
|
||||
|
||||
gmii_rx_dv_d0 <= gmii_rx_dv & gmii_rx_dv_d0;
|
||||
gmii_rx_dv_d1 <= gmii_rx_dv_d0 & gmii_rx_dv;
|
||||
gmii_rx_dv_d2 <= gmii_rx_dv_d1 & gmii_rx_dv;
|
||||
gmii_rx_dv_d3 <= gmii_rx_dv_d2 & gmii_rx_dv;
|
||||
gmii_rx_dv_d4 <= gmii_rx_dv_d3 & gmii_rx_dv;
|
||||
|
||||
gmii_rx_er_d0 <= gmii_rx_er | gmii_rx_er_d0;
|
||||
gmii_rx_er_d1 <= gmii_rx_er_d0;
|
||||
gmii_rx_er_d2 <= gmii_rx_er_d1;
|
||||
gmii_rx_er_d3 <= gmii_rx_er_d2;
|
||||
gmii_rx_er_d4 <= gmii_rx_er_d3;
|
||||
end else begin
|
||||
gmii_rx_dv_d0 <= gmii_rx_dv;
|
||||
gmii_rx_er_d0 <= gmii_rx_er;
|
||||
end
|
||||
end else begin
|
||||
if (in_frame) begin
|
||||
in_frame <= gmii_rx_dv;
|
||||
end else if (gmii_rx_dv && gmii_rxd == ETH_SFD) begin
|
||||
in_frame <= 1'b1;
|
||||
start_packet_int_reg <= 1'b1;
|
||||
end
|
||||
|
||||
gmii_rxd_d0 <= gmii_rxd;
|
||||
gmii_rxd_d1 <= gmii_rxd_d0;
|
||||
gmii_rxd_d2 <= gmii_rxd_d1;
|
||||
gmii_rxd_d3 <= gmii_rxd_d2;
|
||||
gmii_rxd_d4 <= gmii_rxd_d3;
|
||||
|
||||
gmii_rx_dv_d0 <= gmii_rx_dv;
|
||||
gmii_rx_dv_d1 <= gmii_rx_dv_d0 & gmii_rx_dv;
|
||||
gmii_rx_dv_d2 <= gmii_rx_dv_d1 & gmii_rx_dv;
|
||||
gmii_rx_dv_d3 <= gmii_rx_dv_d2 & gmii_rx_dv;
|
||||
gmii_rx_dv_d4 <= gmii_rx_dv_d3 & gmii_rx_dv;
|
||||
|
||||
gmii_rx_er_d0 <= gmii_rx_er;
|
||||
gmii_rx_er_d1 <= gmii_rx_er_d0;
|
||||
gmii_rx_er_d2 <= gmii_rx_er_d1;
|
||||
gmii_rx_er_d3 <= gmii_rx_er_d2;
|
||||
gmii_rx_er_d4 <= gmii_rx_er_d3;
|
||||
end
|
||||
end
|
||||
|
||||
if (reset_crc) begin
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
end else if (update_crc) begin
|
||||
crc_state <= crc_next;
|
||||
end
|
||||
|
||||
error_bad_frame_reg <= error_bad_frame_next;
|
||||
error_bad_fcs_reg <= error_bad_fcs_next;
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
|
||||
start_packet_int_reg <= 1'b0;
|
||||
start_packet_reg <= 1'b0;
|
||||
error_bad_frame_reg <= 1'b0;
|
||||
error_bad_fcs_reg <= 1'b0;
|
||||
|
||||
in_frame <= 1'b0;
|
||||
mii_odd <= 1'b0;
|
||||
|
||||
gmii_rx_dv_d0 <= 1'b0;
|
||||
gmii_rx_dv_d1 <= 1'b0;
|
||||
gmii_rx_dv_d2 <= 1'b0;
|
||||
gmii_rx_dv_d3 <= 1'b0;
|
||||
gmii_rx_dv_d4 <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,457 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015-2018 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream GMII frame transmitter (AXI in, GMII out)
|
||||
*/
|
||||
module axis_gmii_tx #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter PTP_TS_ENABLE = 0,
|
||||
parameter PTP_TS_WIDTH = 96,
|
||||
parameter PTP_TS_CTRL_IN_TUSER = 0,
|
||||
parameter PTP_TAG_ENABLE = PTP_TS_ENABLE,
|
||||
parameter PTP_TAG_WIDTH = 16,
|
||||
parameter USER_WIDTH = (PTP_TS_ENABLE ? (PTP_TAG_ENABLE ? PTP_TAG_WIDTH : 0) + (PTP_TS_CTRL_IN_TUSER ? 1 : 0) : 0) + 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* GMII output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] gmii_txd,
|
||||
output wire gmii_tx_en,
|
||||
output wire gmii_tx_er,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
input wire [PTP_TS_WIDTH-1:0] ptp_ts,
|
||||
output wire [PTP_TS_WIDTH-1:0] m_axis_ptp_ts,
|
||||
output wire [PTP_TAG_WIDTH-1:0] m_axis_ptp_ts_tag,
|
||||
output wire m_axis_ptp_ts_valid,
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
input wire clk_enable,
|
||||
input wire mii_select,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] cfg_ifg,
|
||||
input wire cfg_tx_enable,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire start_packet,
|
||||
output wire error_underflow
|
||||
);
|
||||
|
||||
parameter MIN_LEN_WIDTH = $clog2(MIN_FRAME_LENGTH-4-1+1);
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (DATA_WIDTH != 8) begin
|
||||
$error("Error: Interface width must be 8");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
localparam [7:0]
|
||||
ETH_PRE = 8'h55,
|
||||
ETH_SFD = 8'hD5;
|
||||
|
||||
localparam [2:0]
|
||||
STATE_IDLE = 3'd0,
|
||||
STATE_PREAMBLE = 3'd1,
|
||||
STATE_PAYLOAD = 3'd2,
|
||||
STATE_LAST = 3'd3,
|
||||
STATE_PAD = 3'd4,
|
||||
STATE_FCS = 3'd5,
|
||||
STATE_IFG = 3'd6;
|
||||
|
||||
reg [2:0] state_reg = STATE_IDLE, state_next;
|
||||
|
||||
// datapath control signals
|
||||
reg reset_crc;
|
||||
reg update_crc;
|
||||
|
||||
reg [7:0] s_tdata_reg = 8'd0, s_tdata_next;
|
||||
|
||||
reg mii_odd_reg = 1'b0, mii_odd_next;
|
||||
reg [3:0] mii_msn_reg = 4'b0, mii_msn_next;
|
||||
|
||||
reg frame_reg = 1'b0, frame_next;
|
||||
reg frame_error_reg = 1'b0, frame_error_next;
|
||||
reg [7:0] frame_ptr_reg = 0, frame_ptr_next;
|
||||
reg [MIN_LEN_WIDTH-1:0] frame_min_count_reg = 0, frame_min_count_next;
|
||||
|
||||
reg [7:0] gmii_txd_reg = 8'd0, gmii_txd_next;
|
||||
reg gmii_tx_en_reg = 1'b0, gmii_tx_en_next;
|
||||
reg gmii_tx_er_reg = 1'b0, gmii_tx_er_next;
|
||||
|
||||
reg s_axis_tready_reg = 1'b0, s_axis_tready_next;
|
||||
|
||||
reg [PTP_TS_WIDTH-1:0] m_axis_ptp_ts_reg = 0, m_axis_ptp_ts_next;
|
||||
reg [PTP_TAG_WIDTH-1:0] m_axis_ptp_ts_tag_reg = 0, m_axis_ptp_ts_tag_next;
|
||||
reg m_axis_ptp_ts_valid_reg = 1'b0, m_axis_ptp_ts_valid_next;
|
||||
|
||||
reg start_packet_int_reg = 1'b0, start_packet_int_next;
|
||||
reg start_packet_reg = 1'b0, start_packet_next;
|
||||
reg error_underflow_reg = 1'b0, error_underflow_next;
|
||||
|
||||
reg [31:0] crc_state = 32'hFFFFFFFF;
|
||||
wire [31:0] crc_next;
|
||||
|
||||
assign s_axis_tready = s_axis_tready_reg;
|
||||
|
||||
assign gmii_txd = gmii_txd_reg;
|
||||
assign gmii_tx_en = gmii_tx_en_reg;
|
||||
assign gmii_tx_er = gmii_tx_er_reg;
|
||||
|
||||
assign m_axis_ptp_ts = PTP_TS_ENABLE ? m_axis_ptp_ts_reg : 0;
|
||||
assign m_axis_ptp_ts_tag = PTP_TAG_ENABLE ? m_axis_ptp_ts_tag_reg : 0;
|
||||
assign m_axis_ptp_ts_valid = PTP_TS_ENABLE || PTP_TAG_ENABLE ? m_axis_ptp_ts_valid_reg : 1'b0;
|
||||
|
||||
assign start_packet = start_packet_reg;
|
||||
assign error_underflow = error_underflow_reg;
|
||||
|
||||
lfsr #(
|
||||
.LFSR_WIDTH(32),
|
||||
.LFSR_POLY(32'h4c11db7),
|
||||
.LFSR_CONFIG("GALOIS"),
|
||||
.LFSR_FEED_FORWARD(0),
|
||||
.REVERSE(1),
|
||||
.DATA_WIDTH(8),
|
||||
.STYLE("AUTO")
|
||||
)
|
||||
eth_crc_8 (
|
||||
.data_in(s_tdata_reg),
|
||||
.state_in(crc_state),
|
||||
.data_out(),
|
||||
.state_out(crc_next)
|
||||
);
|
||||
|
||||
always @* begin
|
||||
state_next = STATE_IDLE;
|
||||
|
||||
reset_crc = 1'b0;
|
||||
update_crc = 1'b0;
|
||||
|
||||
mii_odd_next = mii_odd_reg;
|
||||
mii_msn_next = mii_msn_reg;
|
||||
|
||||
frame_next = frame_reg;
|
||||
frame_error_next = frame_error_reg;
|
||||
frame_ptr_next = frame_ptr_reg;
|
||||
frame_min_count_next = frame_min_count_reg;
|
||||
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
s_tdata_next = s_tdata_reg;
|
||||
|
||||
m_axis_ptp_ts_next = m_axis_ptp_ts_reg;
|
||||
m_axis_ptp_ts_tag_next = m_axis_ptp_ts_tag_reg;
|
||||
m_axis_ptp_ts_valid_next = 1'b0;
|
||||
|
||||
if (start_packet_reg && PTP_TS_ENABLE) begin
|
||||
m_axis_ptp_ts_next = ptp_ts;
|
||||
if (PTP_TS_CTRL_IN_TUSER) begin
|
||||
m_axis_ptp_ts_tag_next = s_axis_tuser >> 2;
|
||||
m_axis_ptp_ts_valid_next = s_axis_tuser[1];
|
||||
end else begin
|
||||
m_axis_ptp_ts_tag_next = s_axis_tuser >> 1;
|
||||
m_axis_ptp_ts_valid_next = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
gmii_txd_next = {DATA_WIDTH{1'b0}};
|
||||
gmii_tx_en_next = 1'b0;
|
||||
gmii_tx_er_next = 1'b0;
|
||||
|
||||
start_packet_int_next = start_packet_int_reg;
|
||||
start_packet_next = 1'b0;
|
||||
error_underflow_next = 1'b0;
|
||||
|
||||
if (s_axis_tvalid && s_axis_tready) begin
|
||||
frame_next = !s_axis_tlast;
|
||||
end
|
||||
|
||||
if (!clk_enable) begin
|
||||
// clock disabled - hold state and outputs
|
||||
gmii_txd_next = gmii_txd_reg;
|
||||
gmii_tx_en_next = gmii_tx_en_reg;
|
||||
gmii_tx_er_next = gmii_tx_er_reg;
|
||||
state_next = state_reg;
|
||||
end else if (mii_select && mii_odd_reg) begin
|
||||
// MII odd cycle - hold state, output MSN
|
||||
mii_odd_next = 1'b0;
|
||||
gmii_txd_next = {4'd0, mii_msn_reg};
|
||||
gmii_tx_en_next = gmii_tx_en_reg;
|
||||
gmii_tx_er_next = gmii_tx_er_reg;
|
||||
state_next = state_reg;
|
||||
if (start_packet_int_reg) begin
|
||||
start_packet_int_next = 1'b0;
|
||||
start_packet_next = 1'b1;
|
||||
end
|
||||
end else begin
|
||||
case (state_reg)
|
||||
STATE_IDLE: begin
|
||||
// idle state - wait for packet
|
||||
reset_crc = 1'b1;
|
||||
|
||||
mii_odd_next = 1'b0;
|
||||
frame_ptr_next = 1;
|
||||
|
||||
frame_error_next = 1'b0;
|
||||
frame_min_count_next = MIN_FRAME_LENGTH-4-1;
|
||||
|
||||
if (s_axis_tvalid && cfg_tx_enable) begin
|
||||
mii_odd_next = 1'b1;
|
||||
gmii_txd_next = ETH_PRE;
|
||||
gmii_tx_en_next = 1'b1;
|
||||
state_next = STATE_PREAMBLE;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
STATE_PREAMBLE: begin
|
||||
// send preamble
|
||||
reset_crc = 1'b1;
|
||||
|
||||
mii_odd_next = 1'b1;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
|
||||
gmii_txd_next = ETH_PRE;
|
||||
gmii_tx_en_next = 1'b1;
|
||||
|
||||
if (frame_ptr_reg == 6) begin
|
||||
s_axis_tready_next = 1'b1;
|
||||
s_tdata_next = s_axis_tdata;
|
||||
state_next = STATE_PREAMBLE;
|
||||
end else if (frame_ptr_reg == 7) begin
|
||||
// end of preamble; start payload
|
||||
frame_ptr_next = 0;
|
||||
if (s_axis_tready_reg) begin
|
||||
s_axis_tready_next = 1'b1;
|
||||
s_tdata_next = s_axis_tdata;
|
||||
end
|
||||
gmii_txd_next = ETH_SFD;
|
||||
if (mii_select) begin
|
||||
start_packet_int_next = 1'b1;
|
||||
end else begin
|
||||
start_packet_next = 1'b1;
|
||||
end
|
||||
state_next = STATE_PAYLOAD;
|
||||
end else begin
|
||||
state_next = STATE_PREAMBLE;
|
||||
end
|
||||
end
|
||||
STATE_PAYLOAD: begin
|
||||
// send payload
|
||||
|
||||
update_crc = 1'b1;
|
||||
s_axis_tready_next = 1'b1;
|
||||
|
||||
mii_odd_next = 1'b1;
|
||||
|
||||
if (frame_min_count_reg) begin
|
||||
frame_min_count_next = frame_min_count_reg - 1;
|
||||
end
|
||||
|
||||
gmii_txd_next = s_tdata_reg;
|
||||
gmii_tx_en_next = 1'b1;
|
||||
|
||||
s_tdata_next = s_axis_tdata;
|
||||
|
||||
if (!s_axis_tvalid || s_axis_tlast) begin
|
||||
s_axis_tready_next = frame_next; // drop frame
|
||||
frame_error_next = !s_axis_tvalid || s_axis_tuser[0];
|
||||
error_underflow_next = !s_axis_tvalid;
|
||||
|
||||
state_next = STATE_LAST;
|
||||
end else begin
|
||||
state_next = STATE_PAYLOAD;
|
||||
end
|
||||
end
|
||||
STATE_LAST: begin
|
||||
// last payload word
|
||||
|
||||
update_crc = 1'b1;
|
||||
s_axis_tready_next = 1'b0;
|
||||
|
||||
mii_odd_next = 1'b1;
|
||||
|
||||
gmii_txd_next = s_tdata_reg;
|
||||
gmii_tx_en_next = 1'b1;
|
||||
|
||||
if (ENABLE_PADDING && frame_min_count_reg) begin
|
||||
frame_min_count_next = frame_min_count_reg - 1;
|
||||
s_tdata_next = 8'd0;
|
||||
state_next = STATE_PAD;
|
||||
end else begin
|
||||
frame_ptr_next = 0;
|
||||
state_next = STATE_FCS;
|
||||
end
|
||||
end
|
||||
STATE_PAD: begin
|
||||
// send padding
|
||||
s_axis_tready_next = frame_next; // drop frame
|
||||
|
||||
update_crc = 1'b1;
|
||||
mii_odd_next = 1'b1;
|
||||
|
||||
gmii_txd_next = 8'd0;
|
||||
gmii_tx_en_next = 1'b1;
|
||||
|
||||
s_tdata_next = 8'd0;
|
||||
|
||||
if (frame_min_count_reg) begin
|
||||
frame_min_count_next = frame_min_count_reg - 1;
|
||||
state_next = STATE_PAD;
|
||||
end else begin
|
||||
frame_ptr_next = 0;
|
||||
state_next = STATE_FCS;
|
||||
end
|
||||
end
|
||||
STATE_FCS: begin
|
||||
// send FCS
|
||||
s_axis_tready_next = frame_next; // drop frame
|
||||
|
||||
mii_odd_next = 1'b1;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
|
||||
case (frame_ptr_reg)
|
||||
2'd0: gmii_txd_next = ~crc_state[7:0];
|
||||
2'd1: gmii_txd_next = ~crc_state[15:8];
|
||||
2'd2: gmii_txd_next = ~crc_state[23:16];
|
||||
2'd3: gmii_txd_next = ~crc_state[31:24];
|
||||
endcase
|
||||
gmii_tx_en_next = 1'b1;
|
||||
gmii_tx_er_next = frame_error_reg;
|
||||
|
||||
if (frame_ptr_reg < 3) begin
|
||||
state_next = STATE_FCS;
|
||||
end else begin
|
||||
frame_ptr_next = 0;
|
||||
state_next = STATE_IFG;
|
||||
end
|
||||
end
|
||||
STATE_IFG: begin
|
||||
// send IFG
|
||||
s_axis_tready_next = frame_next; // drop frame
|
||||
|
||||
mii_odd_next = 1'b1;
|
||||
frame_ptr_next = frame_ptr_reg + 1;
|
||||
|
||||
if (frame_ptr_reg < cfg_ifg-1 || frame_reg) begin
|
||||
state_next = STATE_IFG;
|
||||
end else begin
|
||||
state_next = STATE_IDLE;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
if (mii_select) begin
|
||||
mii_msn_next = gmii_txd_next[7:4];
|
||||
gmii_txd_next[7:4] = 4'd0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
state_reg <= state_next;
|
||||
|
||||
frame_reg <= frame_next;
|
||||
frame_error_reg <= frame_error_next;
|
||||
frame_ptr_reg <= frame_ptr_next;
|
||||
frame_min_count_reg <= frame_min_count_next;
|
||||
|
||||
m_axis_ptp_ts_reg <= m_axis_ptp_ts_next;
|
||||
m_axis_ptp_ts_tag_reg <= m_axis_ptp_ts_tag_next;
|
||||
m_axis_ptp_ts_valid_reg <= m_axis_ptp_ts_valid_next;
|
||||
|
||||
mii_odd_reg <= mii_odd_next;
|
||||
mii_msn_reg <= mii_msn_next;
|
||||
|
||||
s_tdata_reg <= s_tdata_next;
|
||||
|
||||
s_axis_tready_reg <= s_axis_tready_next;
|
||||
|
||||
gmii_txd_reg <= gmii_txd_next;
|
||||
gmii_tx_en_reg <= gmii_tx_en_next;
|
||||
gmii_tx_er_reg <= gmii_tx_er_next;
|
||||
|
||||
if (reset_crc) begin
|
||||
crc_state <= 32'hFFFFFFFF;
|
||||
end else if (update_crc) begin
|
||||
crc_state <= crc_next;
|
||||
end
|
||||
|
||||
start_packet_int_reg <= start_packet_int_next;
|
||||
start_packet_reg <= start_packet_next;
|
||||
error_underflow_reg <= error_underflow_next;
|
||||
|
||||
if (rst) begin
|
||||
state_reg <= STATE_IDLE;
|
||||
|
||||
frame_reg <= 1'b0;
|
||||
|
||||
s_axis_tready_reg <= 1'b0;
|
||||
|
||||
m_axis_ptp_ts_valid_reg <= 1'b0;
|
||||
|
||||
gmii_tx_en_reg <= 1'b0;
|
||||
gmii_tx_er_reg <= 1'b0;
|
||||
|
||||
start_packet_int_reg <= 1'b0;
|
||||
start_packet_reg <= 1'b0;
|
||||
error_underflow_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,408 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2014-2020 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* AXI4-Stream ethernet frame transmitter (Ethernet frame in, AXI out)
|
||||
*/
|
||||
module eth_axis_tx #
|
||||
(
|
||||
// Width of AXI stream interfaces in bits
|
||||
parameter DATA_WIDTH = 8,
|
||||
// Propagate tkeep signal
|
||||
// If disabled, tkeep assumed to be 1'b1
|
||||
parameter KEEP_ENABLE = (DATA_WIDTH>8),
|
||||
// tkeep signal width (words per cycle)
|
||||
parameter KEEP_WIDTH = (DATA_WIDTH/8)
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* Ethernet frame input
|
||||
*/
|
||||
input wire s_eth_hdr_valid,
|
||||
output wire s_eth_hdr_ready,
|
||||
input wire [47:0] s_eth_dest_mac,
|
||||
input wire [47:0] s_eth_src_mac,
|
||||
input wire [15:0] s_eth_type,
|
||||
input wire [DATA_WIDTH-1:0] s_eth_payload_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_eth_payload_axis_tkeep,
|
||||
input wire s_eth_payload_axis_tvalid,
|
||||
output wire s_eth_payload_axis_tready,
|
||||
input wire s_eth_payload_axis_tlast,
|
||||
input wire s_eth_payload_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire m_axis_tuser,
|
||||
|
||||
/*
|
||||
* Status signals
|
||||
*/
|
||||
output wire busy
|
||||
);
|
||||
|
||||
parameter BYTE_LANES = KEEP_ENABLE ? KEEP_WIDTH : 1;
|
||||
|
||||
parameter HDR_SIZE = 14;
|
||||
|
||||
parameter CYCLE_COUNT = (HDR_SIZE+BYTE_LANES-1)/BYTE_LANES;
|
||||
|
||||
parameter PTR_WIDTH = $clog2(CYCLE_COUNT);
|
||||
|
||||
parameter OFFSET = HDR_SIZE % BYTE_LANES;
|
||||
|
||||
// bus width assertions
|
||||
initial begin
|
||||
if (BYTE_LANES * 8 != DATA_WIDTH) begin
|
||||
$error("Error: AXI stream interface requires byte (8-bit) granularity (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
|
||||
Ethernet frame
|
||||
|
||||
Field Length
|
||||
Destination MAC address 6 octets
|
||||
Source MAC address 6 octets
|
||||
Ethertype 2 octets
|
||||
|
||||
This module receives an Ethernet frame with header fields in parallel along
|
||||
with the payload in an AXI stream, combines the header with the payload, and
|
||||
transmits the complete Ethernet frame on the output AXI stream interface.
|
||||
|
||||
*/
|
||||
|
||||
// datapath control signals
|
||||
reg store_eth_hdr;
|
||||
|
||||
reg send_eth_header_reg = 1'b0, send_eth_header_next;
|
||||
reg send_eth_payload_reg = 1'b0, send_eth_payload_next;
|
||||
reg [PTR_WIDTH-1:0] ptr_reg = 0, ptr_next;
|
||||
|
||||
reg flush_save;
|
||||
reg transfer_in_save;
|
||||
|
||||
reg [47:0] eth_dest_mac_reg = 48'd0;
|
||||
reg [47:0] eth_src_mac_reg = 48'd0;
|
||||
reg [15:0] eth_type_reg = 16'd0;
|
||||
|
||||
reg s_eth_hdr_ready_reg = 1'b0, s_eth_hdr_ready_next;
|
||||
reg s_eth_payload_axis_tready_reg = 1'b0, s_eth_payload_axis_tready_next;
|
||||
|
||||
reg busy_reg = 1'b0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] save_eth_payload_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] save_eth_payload_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg save_eth_payload_axis_tlast_reg = 1'b0;
|
||||
reg save_eth_payload_axis_tuser_reg = 1'b0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] shift_eth_payload_axis_tdata;
|
||||
reg [KEEP_WIDTH-1:0] shift_eth_payload_axis_tkeep;
|
||||
reg shift_eth_payload_axis_tvalid;
|
||||
reg shift_eth_payload_axis_tlast;
|
||||
reg shift_eth_payload_axis_tuser;
|
||||
reg shift_eth_payload_axis_input_tready;
|
||||
reg shift_eth_payload_axis_extra_cycle_reg = 1'b0;
|
||||
|
||||
// internal datapath
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_int;
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_int;
|
||||
reg m_axis_tvalid_int;
|
||||
reg m_axis_tready_int_reg = 1'b0;
|
||||
reg m_axis_tlast_int;
|
||||
reg m_axis_tuser_int;
|
||||
wire m_axis_tready_int_early;
|
||||
|
||||
assign s_eth_hdr_ready = s_eth_hdr_ready_reg;
|
||||
assign s_eth_payload_axis_tready = s_eth_payload_axis_tready_reg;
|
||||
|
||||
assign busy = busy_reg;
|
||||
|
||||
always @* begin
|
||||
if (OFFSET == 0) begin
|
||||
// passthrough if no overlap
|
||||
shift_eth_payload_axis_tdata = s_eth_payload_axis_tdata;
|
||||
shift_eth_payload_axis_tkeep = s_eth_payload_axis_tkeep;
|
||||
shift_eth_payload_axis_tvalid = s_eth_payload_axis_tvalid;
|
||||
shift_eth_payload_axis_tlast = s_eth_payload_axis_tlast;
|
||||
shift_eth_payload_axis_tuser = s_eth_payload_axis_tuser;
|
||||
shift_eth_payload_axis_input_tready = 1'b1;
|
||||
end else if (shift_eth_payload_axis_extra_cycle_reg) begin
|
||||
shift_eth_payload_axis_tdata = {s_eth_payload_axis_tdata, save_eth_payload_axis_tdata_reg} >> ((KEEP_WIDTH-OFFSET)*8);
|
||||
shift_eth_payload_axis_tkeep = {{KEEP_WIDTH{1'b0}}, save_eth_payload_axis_tkeep_reg} >> (KEEP_WIDTH-OFFSET);
|
||||
shift_eth_payload_axis_tvalid = 1'b1;
|
||||
shift_eth_payload_axis_tlast = save_eth_payload_axis_tlast_reg;
|
||||
shift_eth_payload_axis_tuser = save_eth_payload_axis_tuser_reg;
|
||||
shift_eth_payload_axis_input_tready = flush_save;
|
||||
end else begin
|
||||
shift_eth_payload_axis_tdata = {s_eth_payload_axis_tdata, save_eth_payload_axis_tdata_reg} >> ((KEEP_WIDTH-OFFSET)*8);
|
||||
shift_eth_payload_axis_tkeep = {s_eth_payload_axis_tkeep, save_eth_payload_axis_tkeep_reg} >> (KEEP_WIDTH-OFFSET);
|
||||
shift_eth_payload_axis_tvalid = s_eth_payload_axis_tvalid;
|
||||
shift_eth_payload_axis_tlast = (s_eth_payload_axis_tlast && ((s_eth_payload_axis_tkeep & ({KEEP_WIDTH{1'b1}} << (KEEP_WIDTH-OFFSET))) == 0));
|
||||
shift_eth_payload_axis_tuser = (s_eth_payload_axis_tuser && ((s_eth_payload_axis_tkeep & ({KEEP_WIDTH{1'b1}} << (KEEP_WIDTH-OFFSET))) == 0));
|
||||
shift_eth_payload_axis_input_tready = !(s_eth_payload_axis_tlast && s_eth_payload_axis_tready && s_eth_payload_axis_tvalid);
|
||||
end
|
||||
end
|
||||
|
||||
always @* begin
|
||||
send_eth_header_next = send_eth_header_reg;
|
||||
send_eth_payload_next = send_eth_payload_reg;
|
||||
ptr_next = ptr_reg;
|
||||
|
||||
s_eth_hdr_ready_next = 1'b0;
|
||||
s_eth_payload_axis_tready_next = 1'b0;
|
||||
|
||||
store_eth_hdr = 1'b0;
|
||||
|
||||
flush_save = 1'b0;
|
||||
transfer_in_save = 1'b0;
|
||||
|
||||
m_axis_tdata_int = {DATA_WIDTH{1'b0}};
|
||||
m_axis_tkeep_int = {KEEP_WIDTH{1'b0}};
|
||||
m_axis_tvalid_int = 1'b0;
|
||||
m_axis_tlast_int = 1'b0;
|
||||
m_axis_tuser_int = 1'b0;
|
||||
|
||||
if (s_eth_hdr_ready && s_eth_hdr_valid) begin
|
||||
store_eth_hdr = 1'b1;
|
||||
ptr_next = 0;
|
||||
send_eth_header_next = 1'b1;
|
||||
send_eth_payload_next = (OFFSET != 0) && (CYCLE_COUNT == 1);
|
||||
s_eth_payload_axis_tready_next = send_eth_payload_next && m_axis_tready_int_early;
|
||||
end
|
||||
|
||||
if (send_eth_payload_reg) begin
|
||||
s_eth_payload_axis_tready_next = m_axis_tready_int_early && shift_eth_payload_axis_input_tready;
|
||||
|
||||
m_axis_tdata_int = shift_eth_payload_axis_tdata;
|
||||
m_axis_tkeep_int = shift_eth_payload_axis_tkeep;
|
||||
m_axis_tlast_int = shift_eth_payload_axis_tlast;
|
||||
m_axis_tuser_int = shift_eth_payload_axis_tuser;
|
||||
|
||||
if ((s_eth_payload_axis_tready && s_eth_payload_axis_tvalid) || (m_axis_tready_int_reg && shift_eth_payload_axis_extra_cycle_reg)) begin
|
||||
transfer_in_save = 1'b1;
|
||||
|
||||
m_axis_tvalid_int = 1'b1;
|
||||
|
||||
if (shift_eth_payload_axis_tlast) begin
|
||||
flush_save = 1'b1;
|
||||
s_eth_payload_axis_tready_next = 1'b0;
|
||||
ptr_next = 0;
|
||||
send_eth_payload_next = 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (m_axis_tready_int_reg && (!OFFSET || !send_eth_payload_reg || m_axis_tvalid_int)) begin
|
||||
if (send_eth_header_reg) begin
|
||||
ptr_next = ptr_reg + 1;
|
||||
|
||||
if ((OFFSET != 0) && (CYCLE_COUNT == 1 || ptr_next == CYCLE_COUNT-1) && !send_eth_payload_reg) begin
|
||||
send_eth_payload_next = 1'b1;
|
||||
s_eth_payload_axis_tready_next = m_axis_tready_int_early && shift_eth_payload_axis_input_tready;
|
||||
end
|
||||
|
||||
m_axis_tvalid_int = 1'b1;
|
||||
|
||||
`define _HEADER_FIELD_(offset, field) \
|
||||
if (ptr_reg == offset/BYTE_LANES) begin \
|
||||
m_axis_tdata_int[(offset%BYTE_LANES)*8 +: 8] = field; \
|
||||
m_axis_tkeep_int[offset%BYTE_LANES] = 1'b1; \
|
||||
end
|
||||
|
||||
`_HEADER_FIELD_(0, eth_dest_mac_reg[5*8 +: 8])
|
||||
`_HEADER_FIELD_(1, eth_dest_mac_reg[4*8 +: 8])
|
||||
`_HEADER_FIELD_(2, eth_dest_mac_reg[3*8 +: 8])
|
||||
`_HEADER_FIELD_(3, eth_dest_mac_reg[2*8 +: 8])
|
||||
`_HEADER_FIELD_(4, eth_dest_mac_reg[1*8 +: 8])
|
||||
`_HEADER_FIELD_(5, eth_dest_mac_reg[0*8 +: 8])
|
||||
`_HEADER_FIELD_(6, eth_src_mac_reg[5*8 +: 8])
|
||||
`_HEADER_FIELD_(7, eth_src_mac_reg[4*8 +: 8])
|
||||
`_HEADER_FIELD_(8, eth_src_mac_reg[3*8 +: 8])
|
||||
`_HEADER_FIELD_(9, eth_src_mac_reg[2*8 +: 8])
|
||||
`_HEADER_FIELD_(10, eth_src_mac_reg[1*8 +: 8])
|
||||
`_HEADER_FIELD_(11, eth_src_mac_reg[0*8 +: 8])
|
||||
`_HEADER_FIELD_(12, eth_type_reg[1*8 +: 8])
|
||||
`_HEADER_FIELD_(13, eth_type_reg[0*8 +: 8])
|
||||
|
||||
if (ptr_reg == 13/BYTE_LANES) begin
|
||||
if (!send_eth_payload_reg) begin
|
||||
s_eth_payload_axis_tready_next = m_axis_tready_int_early;
|
||||
send_eth_payload_next = 1'b1;
|
||||
end
|
||||
send_eth_header_next = 1'b0;
|
||||
end
|
||||
|
||||
`undef _HEADER_FIELD_
|
||||
end
|
||||
end
|
||||
|
||||
s_eth_hdr_ready_next = !(send_eth_header_next || send_eth_payload_next);
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
send_eth_header_reg <= send_eth_header_next;
|
||||
send_eth_payload_reg <= send_eth_payload_next;
|
||||
ptr_reg <= ptr_next;
|
||||
|
||||
s_eth_hdr_ready_reg <= s_eth_hdr_ready_next;
|
||||
s_eth_payload_axis_tready_reg <= s_eth_payload_axis_tready_next;
|
||||
|
||||
busy_reg <= send_eth_header_next || send_eth_payload_next;
|
||||
|
||||
if (store_eth_hdr) begin
|
||||
eth_dest_mac_reg <= s_eth_dest_mac;
|
||||
eth_src_mac_reg <= s_eth_src_mac;
|
||||
eth_type_reg <= s_eth_type;
|
||||
end
|
||||
|
||||
if (transfer_in_save) begin
|
||||
save_eth_payload_axis_tdata_reg <= s_eth_payload_axis_tdata;
|
||||
save_eth_payload_axis_tkeep_reg <= s_eth_payload_axis_tkeep;
|
||||
save_eth_payload_axis_tuser_reg <= s_eth_payload_axis_tuser;
|
||||
end
|
||||
|
||||
if (flush_save) begin
|
||||
save_eth_payload_axis_tlast_reg <= 1'b0;
|
||||
shift_eth_payload_axis_extra_cycle_reg <= 1'b0;
|
||||
end else if (transfer_in_save) begin
|
||||
save_eth_payload_axis_tlast_reg <= s_eth_payload_axis_tlast;
|
||||
shift_eth_payload_axis_extra_cycle_reg <= OFFSET ? s_eth_payload_axis_tlast && ((s_eth_payload_axis_tkeep & ({KEEP_WIDTH{1'b1}} << (KEEP_WIDTH-OFFSET))) != 0) : 1'b0;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
send_eth_header_reg <= 1'b0;
|
||||
send_eth_payload_reg <= 1'b0;
|
||||
ptr_reg <= 0;
|
||||
s_eth_hdr_ready_reg <= 1'b0;
|
||||
s_eth_payload_axis_tready_reg <= 1'b0;
|
||||
busy_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg m_axis_tuser_reg = 1'b0;
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
|
||||
reg temp_m_axis_tlast_reg = 1'b0;
|
||||
reg temp_m_axis_tuser_reg = 1'b0;
|
||||
|
||||
// datapath control
|
||||
reg store_axis_int_to_output;
|
||||
reg store_axis_int_to_temp;
|
||||
reg store_axis_temp_to_output;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tuser = m_axis_tuser_reg;
|
||||
|
||||
// enable ready input next cycle if output is ready or if both output registers are empty
|
||||
assign m_axis_tready_int_early = m_axis_tready || (!temp_m_axis_tvalid_reg && !m_axis_tvalid_reg);
|
||||
|
||||
always @* begin
|
||||
// transfer sink ready state to source
|
||||
m_axis_tvalid_next = m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
|
||||
store_axis_int_to_output = 1'b0;
|
||||
store_axis_int_to_temp = 1'b0;
|
||||
store_axis_temp_to_output = 1'b0;
|
||||
|
||||
if (m_axis_tready_int_reg) begin
|
||||
// input is ready
|
||||
if (m_axis_tready || !m_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_output = 1'b1;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_temp = 1'b1;
|
||||
end
|
||||
end else if (m_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = 1'b0;
|
||||
store_axis_temp_to_output = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_next;
|
||||
m_axis_tready_int_reg <= m_axis_tready_int_early;
|
||||
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
|
||||
|
||||
// datapath
|
||||
if (store_axis_int_to_output) begin
|
||||
m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end else if (store_axis_temp_to_output) begin
|
||||
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
|
||||
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
|
||||
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
|
||||
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
|
||||
end
|
||||
|
||||
if (store_axis_int_to_temp) begin
|
||||
temp_m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
temp_m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
temp_m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
temp_m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tready_int_reg <= 1'b0;
|
||||
temp_m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,643 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015-2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* 1G Ethernet MAC
|
||||
*/
|
||||
module eth_mac_1g #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter PTP_TS_ENABLE = 0,
|
||||
parameter PTP_TS_FMT_TOD = 1,
|
||||
parameter PTP_TS_WIDTH = PTP_TS_FMT_TOD ? 96 : 64,
|
||||
parameter TX_PTP_TS_CTRL_IN_TUSER = 0,
|
||||
parameter TX_PTP_TAG_ENABLE = PTP_TS_ENABLE,
|
||||
parameter TX_PTP_TAG_WIDTH = 16,
|
||||
parameter TX_USER_WIDTH = (PTP_TS_ENABLE ? (TX_PTP_TAG_ENABLE ? TX_PTP_TAG_WIDTH : 0) + (TX_PTP_TS_CTRL_IN_TUSER ? 1 : 0) : 0) + 1,
|
||||
parameter RX_USER_WIDTH = (PTP_TS_ENABLE ? PTP_TS_WIDTH : 0) + 1,
|
||||
parameter PFC_ENABLE = 0,
|
||||
parameter PAUSE_ENABLE = PFC_ENABLE
|
||||
)
|
||||
(
|
||||
input wire rx_clk,
|
||||
input wire rx_rst,
|
||||
input wire tx_clk,
|
||||
input wire tx_rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] tx_axis_tdata,
|
||||
input wire tx_axis_tvalid,
|
||||
output wire tx_axis_tready,
|
||||
input wire tx_axis_tlast,
|
||||
input wire [TX_USER_WIDTH-1:0] tx_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] rx_axis_tdata,
|
||||
output wire rx_axis_tvalid,
|
||||
output wire rx_axis_tlast,
|
||||
output wire [RX_USER_WIDTH-1:0] rx_axis_tuser,
|
||||
|
||||
/*
|
||||
* GMII interface
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] gmii_rxd,
|
||||
input wire gmii_rx_dv,
|
||||
input wire gmii_rx_er,
|
||||
output wire [DATA_WIDTH-1:0] gmii_txd,
|
||||
output wire gmii_tx_en,
|
||||
output wire gmii_tx_er,
|
||||
|
||||
/*
|
||||
* PTP
|
||||
*/
|
||||
input wire [PTP_TS_WIDTH-1:0] tx_ptp_ts,
|
||||
input wire [PTP_TS_WIDTH-1:0] rx_ptp_ts,
|
||||
output wire [PTP_TS_WIDTH-1:0] tx_axis_ptp_ts,
|
||||
output wire [TX_PTP_TAG_WIDTH-1:0] tx_axis_ptp_ts_tag,
|
||||
output wire tx_axis_ptp_ts_valid,
|
||||
|
||||
/*
|
||||
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
|
||||
*/
|
||||
input wire tx_lfc_req,
|
||||
input wire tx_lfc_resend,
|
||||
input wire rx_lfc_en,
|
||||
output wire rx_lfc_req,
|
||||
input wire rx_lfc_ack,
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
|
||||
*/
|
||||
input wire [7:0] tx_pfc_req,
|
||||
input wire tx_pfc_resend,
|
||||
input wire [7:0] rx_pfc_en,
|
||||
output wire [7:0] rx_pfc_req,
|
||||
input wire [7:0] rx_pfc_ack,
|
||||
|
||||
/*
|
||||
* Pause interface
|
||||
*/
|
||||
input wire tx_lfc_pause_en,
|
||||
input wire tx_pause_req,
|
||||
output wire tx_pause_ack,
|
||||
|
||||
/*
|
||||
* Control
|
||||
*/
|
||||
input wire rx_clk_enable,
|
||||
input wire tx_clk_enable,
|
||||
input wire rx_mii_select,
|
||||
input wire tx_mii_select,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_start_packet,
|
||||
output wire tx_error_underflow,
|
||||
output wire rx_start_packet,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
output wire stat_tx_mcf,
|
||||
output wire stat_rx_mcf,
|
||||
output wire stat_tx_lfc_pkt,
|
||||
output wire stat_tx_lfc_xon,
|
||||
output wire stat_tx_lfc_xoff,
|
||||
output wire stat_tx_lfc_paused,
|
||||
output wire stat_tx_pfc_pkt,
|
||||
output wire [7:0] stat_tx_pfc_xon,
|
||||
output wire [7:0] stat_tx_pfc_xoff,
|
||||
output wire [7:0] stat_tx_pfc_paused,
|
||||
output wire stat_rx_lfc_pkt,
|
||||
output wire stat_rx_lfc_xon,
|
||||
output wire stat_rx_lfc_xoff,
|
||||
output wire stat_rx_lfc_paused,
|
||||
output wire stat_rx_pfc_pkt,
|
||||
output wire [7:0] stat_rx_pfc_xon,
|
||||
output wire [7:0] stat_rx_pfc_xoff,
|
||||
output wire [7:0] stat_rx_pfc_paused,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] cfg_ifg,
|
||||
input wire cfg_tx_enable,
|
||||
input wire cfg_rx_enable,
|
||||
input wire [47:0] cfg_mcf_rx_eth_dst_mcast,
|
||||
input wire cfg_mcf_rx_check_eth_dst_mcast,
|
||||
input wire [47:0] cfg_mcf_rx_eth_dst_ucast,
|
||||
input wire cfg_mcf_rx_check_eth_dst_ucast,
|
||||
input wire [47:0] cfg_mcf_rx_eth_src,
|
||||
input wire cfg_mcf_rx_check_eth_src,
|
||||
input wire [15:0] cfg_mcf_rx_eth_type,
|
||||
input wire [15:0] cfg_mcf_rx_opcode_lfc,
|
||||
input wire cfg_mcf_rx_check_opcode_lfc,
|
||||
input wire [15:0] cfg_mcf_rx_opcode_pfc,
|
||||
input wire cfg_mcf_rx_check_opcode_pfc,
|
||||
input wire cfg_mcf_rx_forward,
|
||||
input wire cfg_mcf_rx_enable,
|
||||
input wire [47:0] cfg_tx_lfc_eth_dst,
|
||||
input wire [47:0] cfg_tx_lfc_eth_src,
|
||||
input wire [15:0] cfg_tx_lfc_eth_type,
|
||||
input wire [15:0] cfg_tx_lfc_opcode,
|
||||
input wire cfg_tx_lfc_en,
|
||||
input wire [15:0] cfg_tx_lfc_quanta,
|
||||
input wire [15:0] cfg_tx_lfc_refresh,
|
||||
input wire [47:0] cfg_tx_pfc_eth_dst,
|
||||
input wire [47:0] cfg_tx_pfc_eth_src,
|
||||
input wire [15:0] cfg_tx_pfc_eth_type,
|
||||
input wire [15:0] cfg_tx_pfc_opcode,
|
||||
input wire cfg_tx_pfc_en,
|
||||
input wire [8*16-1:0] cfg_tx_pfc_quanta,
|
||||
input wire [8*16-1:0] cfg_tx_pfc_refresh,
|
||||
input wire [15:0] cfg_rx_lfc_opcode,
|
||||
input wire cfg_rx_lfc_en,
|
||||
input wire [15:0] cfg_rx_pfc_opcode,
|
||||
input wire cfg_rx_pfc_en
|
||||
);
|
||||
|
||||
parameter MAC_CTRL_ENABLE = PAUSE_ENABLE || PFC_ENABLE;
|
||||
parameter TX_USER_WIDTH_INT = MAC_CTRL_ENABLE ? (PTP_TS_ENABLE ? (TX_PTP_TAG_ENABLE ? TX_PTP_TAG_WIDTH : 0) + 1 : 0) + 1 : TX_USER_WIDTH;
|
||||
|
||||
wire [DATA_WIDTH-1:0] tx_axis_tdata_int;
|
||||
wire tx_axis_tvalid_int;
|
||||
wire tx_axis_tready_int;
|
||||
wire tx_axis_tlast_int;
|
||||
wire [TX_USER_WIDTH_INT-1:0] tx_axis_tuser_int;
|
||||
|
||||
wire [DATA_WIDTH-1:0] rx_axis_tdata_int;
|
||||
wire rx_axis_tvalid_int;
|
||||
wire rx_axis_tlast_int;
|
||||
wire [RX_USER_WIDTH-1:0] rx_axis_tuser_int;
|
||||
|
||||
axis_gmii_rx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.PTP_TS_ENABLE(PTP_TS_ENABLE),
|
||||
.PTP_TS_WIDTH(PTP_TS_WIDTH),
|
||||
.USER_WIDTH(RX_USER_WIDTH)
|
||||
)
|
||||
axis_gmii_rx_inst (
|
||||
.clk(rx_clk),
|
||||
.rst(rx_rst),
|
||||
.gmii_rxd(gmii_rxd),
|
||||
.gmii_rx_dv(gmii_rx_dv),
|
||||
.gmii_rx_er(gmii_rx_er),
|
||||
.m_axis_tdata(rx_axis_tdata_int),
|
||||
.m_axis_tvalid(rx_axis_tvalid_int),
|
||||
.m_axis_tlast(rx_axis_tlast_int),
|
||||
.m_axis_tuser(rx_axis_tuser_int),
|
||||
.ptp_ts(rx_ptp_ts),
|
||||
.clk_enable(rx_clk_enable),
|
||||
.mii_select(rx_mii_select),
|
||||
.cfg_rx_enable(cfg_rx_enable),
|
||||
.start_packet(rx_start_packet),
|
||||
.error_bad_frame(rx_error_bad_frame),
|
||||
.error_bad_fcs(rx_error_bad_fcs)
|
||||
);
|
||||
|
||||
axis_gmii_tx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH),
|
||||
.PTP_TS_ENABLE(PTP_TS_ENABLE),
|
||||
.PTP_TS_WIDTH(PTP_TS_WIDTH),
|
||||
.PTP_TS_CTRL_IN_TUSER(MAC_CTRL_ENABLE ? PTP_TS_ENABLE : TX_PTP_TS_CTRL_IN_TUSER),
|
||||
.PTP_TAG_ENABLE(TX_PTP_TAG_ENABLE),
|
||||
.PTP_TAG_WIDTH(TX_PTP_TAG_WIDTH),
|
||||
.USER_WIDTH(TX_USER_WIDTH_INT)
|
||||
)
|
||||
axis_gmii_tx_inst (
|
||||
.clk(tx_clk),
|
||||
.rst(tx_rst),
|
||||
.s_axis_tdata(tx_axis_tdata_int),
|
||||
.s_axis_tvalid(tx_axis_tvalid_int),
|
||||
.s_axis_tready(tx_axis_tready_int),
|
||||
.s_axis_tlast(tx_axis_tlast_int),
|
||||
.s_axis_tuser(tx_axis_tuser_int),
|
||||
.gmii_txd(gmii_txd),
|
||||
.gmii_tx_en(gmii_tx_en),
|
||||
.gmii_tx_er(gmii_tx_er),
|
||||
.ptp_ts(tx_ptp_ts),
|
||||
.m_axis_ptp_ts(tx_axis_ptp_ts),
|
||||
.m_axis_ptp_ts_tag(tx_axis_ptp_ts_tag),
|
||||
.m_axis_ptp_ts_valid(tx_axis_ptp_ts_valid),
|
||||
.clk_enable(tx_clk_enable),
|
||||
.mii_select(tx_mii_select),
|
||||
.cfg_ifg(cfg_ifg),
|
||||
.cfg_tx_enable(cfg_tx_enable),
|
||||
.start_packet(tx_start_packet),
|
||||
.error_underflow(tx_error_underflow)
|
||||
);
|
||||
|
||||
generate
|
||||
|
||||
if (MAC_CTRL_ENABLE) begin : mac_ctrl
|
||||
|
||||
localparam MCF_PARAMS_SIZE = PFC_ENABLE ? 18 : 2;
|
||||
|
||||
wire tx_mcf_valid;
|
||||
wire tx_mcf_ready;
|
||||
wire [47:0] tx_mcf_eth_dst;
|
||||
wire [47:0] tx_mcf_eth_src;
|
||||
wire [15:0] tx_mcf_eth_type;
|
||||
wire [15:0] tx_mcf_opcode;
|
||||
wire [MCF_PARAMS_SIZE*8-1:0] tx_mcf_params;
|
||||
|
||||
wire rx_mcf_valid;
|
||||
wire [47:0] rx_mcf_eth_dst;
|
||||
wire [47:0] rx_mcf_eth_src;
|
||||
wire [15:0] rx_mcf_eth_type;
|
||||
wire [15:0] rx_mcf_opcode;
|
||||
wire [MCF_PARAMS_SIZE*8-1:0] rx_mcf_params;
|
||||
|
||||
// terminate LFC pause requests from RX internally on TX side
|
||||
wire tx_pause_req_int;
|
||||
wire rx_lfc_ack_int;
|
||||
|
||||
reg tx_lfc_req_sync_reg_1 = 1'b0;
|
||||
reg tx_lfc_req_sync_reg_2 = 1'b0;
|
||||
reg tx_lfc_req_sync_reg_3 = 1'b0;
|
||||
|
||||
always @(posedge rx_clk or posedge rx_rst) begin
|
||||
if (rx_rst) begin
|
||||
tx_lfc_req_sync_reg_1 <= 1'b0;
|
||||
end else begin
|
||||
tx_lfc_req_sync_reg_1 <= rx_lfc_req;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge tx_clk or posedge tx_rst) begin
|
||||
if (tx_rst) begin
|
||||
tx_lfc_req_sync_reg_2 <= 1'b0;
|
||||
tx_lfc_req_sync_reg_3 <= 1'b0;
|
||||
end else begin
|
||||
tx_lfc_req_sync_reg_2 <= tx_lfc_req_sync_reg_1;
|
||||
tx_lfc_req_sync_reg_3 <= tx_lfc_req_sync_reg_2;
|
||||
end
|
||||
end
|
||||
|
||||
reg rx_lfc_ack_sync_reg_1 = 1'b0;
|
||||
reg rx_lfc_ack_sync_reg_2 = 1'b0;
|
||||
reg rx_lfc_ack_sync_reg_3 = 1'b0;
|
||||
|
||||
always @(posedge tx_clk or posedge tx_rst) begin
|
||||
if (tx_rst) begin
|
||||
rx_lfc_ack_sync_reg_1 <= 1'b0;
|
||||
end else begin
|
||||
rx_lfc_ack_sync_reg_1 <= tx_lfc_pause_en ? tx_pause_ack : 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge rx_clk or posedge rx_rst) begin
|
||||
if (rx_rst) begin
|
||||
rx_lfc_ack_sync_reg_2 <= 1'b0;
|
||||
rx_lfc_ack_sync_reg_3 <= 1'b0;
|
||||
end else begin
|
||||
rx_lfc_ack_sync_reg_2 <= rx_lfc_ack_sync_reg_1;
|
||||
rx_lfc_ack_sync_reg_3 <= rx_lfc_ack_sync_reg_2;
|
||||
end
|
||||
end
|
||||
|
||||
assign tx_pause_req_int = tx_pause_req || (tx_lfc_pause_en ? tx_lfc_req_sync_reg_3 : 0);
|
||||
|
||||
assign rx_lfc_ack_int = rx_lfc_ack || rx_lfc_ack_sync_reg_3;
|
||||
|
||||
// handle PTP TS enable bit in tuser
|
||||
wire [TX_USER_WIDTH_INT-1:0] tx_axis_tuser_in;
|
||||
|
||||
if (PTP_TS_ENABLE && !TX_PTP_TS_CTRL_IN_TUSER) begin
|
||||
assign tx_axis_tuser_in = {tx_axis_tuser[TX_USER_WIDTH-1:1], 1'b1, tx_axis_tuser[0]};
|
||||
end else begin
|
||||
assign tx_axis_tuser_in = tx_axis_tuser;
|
||||
end
|
||||
|
||||
mac_ctrl_tx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_ENABLE(0),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(TX_USER_WIDTH_INT),
|
||||
.MCF_PARAMS_SIZE(MCF_PARAMS_SIZE)
|
||||
)
|
||||
mac_ctrl_tx_inst (
|
||||
.clk(tx_clk),
|
||||
.rst(tx_rst),
|
||||
|
||||
/*
|
||||
* AXI stream input
|
||||
*/
|
||||
.s_axis_tdata(tx_axis_tdata),
|
||||
.s_axis_tkeep(1'b1),
|
||||
.s_axis_tvalid(tx_axis_tvalid),
|
||||
.s_axis_tready(tx_axis_tready),
|
||||
.s_axis_tlast(tx_axis_tlast),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(tx_axis_tuser_in),
|
||||
|
||||
/*
|
||||
* AXI stream output
|
||||
*/
|
||||
.m_axis_tdata(tx_axis_tdata_int),
|
||||
.m_axis_tkeep(),
|
||||
.m_axis_tvalid(tx_axis_tvalid_int),
|
||||
.m_axis_tready(tx_axis_tready_int),
|
||||
.m_axis_tlast(tx_axis_tlast_int),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(tx_axis_tuser_int),
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
.mcf_valid(tx_mcf_valid),
|
||||
.mcf_ready(tx_mcf_ready),
|
||||
.mcf_eth_dst(tx_mcf_eth_dst),
|
||||
.mcf_eth_src(tx_mcf_eth_src),
|
||||
.mcf_eth_type(tx_mcf_eth_type),
|
||||
.mcf_opcode(tx_mcf_opcode),
|
||||
.mcf_params(tx_mcf_params),
|
||||
.mcf_id(0),
|
||||
.mcf_dest(0),
|
||||
.mcf_user(0),
|
||||
|
||||
/*
|
||||
* Pause interface
|
||||
*/
|
||||
.tx_pause_req(tx_pause_req_int),
|
||||
.tx_pause_ack(tx_pause_ack),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.stat_tx_mcf(stat_tx_mcf)
|
||||
);
|
||||
|
||||
mac_ctrl_rx #(
|
||||
.DATA_WIDTH(DATA_WIDTH),
|
||||
.KEEP_ENABLE(0),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(RX_USER_WIDTH),
|
||||
.USE_READY(0),
|
||||
.MCF_PARAMS_SIZE(MCF_PARAMS_SIZE)
|
||||
)
|
||||
mac_ctrl_rx_inst (
|
||||
.clk(rx_clk),
|
||||
.rst(rx_rst),
|
||||
|
||||
/*
|
||||
* AXI stream input
|
||||
*/
|
||||
.s_axis_tdata(rx_axis_tdata_int),
|
||||
.s_axis_tkeep(1'b1),
|
||||
.s_axis_tvalid(rx_axis_tvalid_int),
|
||||
.s_axis_tready(),
|
||||
.s_axis_tlast(rx_axis_tlast_int),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(rx_axis_tuser_int),
|
||||
|
||||
/*
|
||||
* AXI stream output
|
||||
*/
|
||||
.m_axis_tdata(rx_axis_tdata),
|
||||
.m_axis_tkeep(),
|
||||
.m_axis_tvalid(rx_axis_tvalid),
|
||||
.m_axis_tready(1'b1),
|
||||
.m_axis_tlast(rx_axis_tlast),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(rx_axis_tuser),
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
.mcf_valid(rx_mcf_valid),
|
||||
.mcf_eth_dst(rx_mcf_eth_dst),
|
||||
.mcf_eth_src(rx_mcf_eth_src),
|
||||
.mcf_eth_type(rx_mcf_eth_type),
|
||||
.mcf_opcode(rx_mcf_opcode),
|
||||
.mcf_params(rx_mcf_params),
|
||||
.mcf_id(),
|
||||
.mcf_dest(),
|
||||
.mcf_user(),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_mcf_rx_eth_dst_mcast(cfg_mcf_rx_eth_dst_mcast),
|
||||
.cfg_mcf_rx_check_eth_dst_mcast(cfg_mcf_rx_check_eth_dst_mcast),
|
||||
.cfg_mcf_rx_eth_dst_ucast(cfg_mcf_rx_eth_dst_ucast),
|
||||
.cfg_mcf_rx_check_eth_dst_ucast(cfg_mcf_rx_check_eth_dst_ucast),
|
||||
.cfg_mcf_rx_eth_src(cfg_mcf_rx_eth_src),
|
||||
.cfg_mcf_rx_check_eth_src(cfg_mcf_rx_check_eth_src),
|
||||
.cfg_mcf_rx_eth_type(cfg_mcf_rx_eth_type),
|
||||
.cfg_mcf_rx_opcode_lfc(cfg_mcf_rx_opcode_lfc),
|
||||
.cfg_mcf_rx_check_opcode_lfc(cfg_mcf_rx_check_opcode_lfc),
|
||||
.cfg_mcf_rx_opcode_pfc(cfg_mcf_rx_opcode_pfc),
|
||||
.cfg_mcf_rx_check_opcode_pfc(cfg_mcf_rx_check_opcode_pfc),
|
||||
.cfg_mcf_rx_forward(cfg_mcf_rx_forward),
|
||||
.cfg_mcf_rx_enable(cfg_mcf_rx_enable),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.stat_rx_mcf(stat_rx_mcf)
|
||||
);
|
||||
|
||||
mac_pause_ctrl_tx #(
|
||||
.MCF_PARAMS_SIZE(MCF_PARAMS_SIZE),
|
||||
.PFC_ENABLE(PFC_ENABLE)
|
||||
)
|
||||
mac_pause_ctrl_tx_inst (
|
||||
.clk(tx_clk),
|
||||
.rst(tx_rst),
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
.mcf_valid(tx_mcf_valid),
|
||||
.mcf_ready(tx_mcf_ready),
|
||||
.mcf_eth_dst(tx_mcf_eth_dst),
|
||||
.mcf_eth_src(tx_mcf_eth_src),
|
||||
.mcf_eth_type(tx_mcf_eth_type),
|
||||
.mcf_opcode(tx_mcf_opcode),
|
||||
.mcf_params(tx_mcf_params),
|
||||
|
||||
/*
|
||||
* Pause (IEEE 802.3 annex 31B)
|
||||
*/
|
||||
.tx_lfc_req(tx_lfc_req),
|
||||
.tx_lfc_resend(tx_lfc_resend),
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D)
|
||||
*/
|
||||
.tx_pfc_req(tx_pfc_req),
|
||||
.tx_pfc_resend(tx_pfc_resend),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_tx_lfc_eth_dst(cfg_tx_lfc_eth_dst),
|
||||
.cfg_tx_lfc_eth_src(cfg_tx_lfc_eth_src),
|
||||
.cfg_tx_lfc_eth_type(cfg_tx_lfc_eth_type),
|
||||
.cfg_tx_lfc_opcode(cfg_tx_lfc_opcode),
|
||||
.cfg_tx_lfc_en(cfg_tx_lfc_en),
|
||||
.cfg_tx_lfc_quanta(cfg_tx_lfc_quanta),
|
||||
.cfg_tx_lfc_refresh(cfg_tx_lfc_refresh),
|
||||
.cfg_tx_pfc_eth_dst(cfg_tx_pfc_eth_dst),
|
||||
.cfg_tx_pfc_eth_src(cfg_tx_pfc_eth_src),
|
||||
.cfg_tx_pfc_eth_type(cfg_tx_pfc_eth_type),
|
||||
.cfg_tx_pfc_opcode(cfg_tx_pfc_opcode),
|
||||
.cfg_tx_pfc_en(cfg_tx_pfc_en),
|
||||
.cfg_tx_pfc_quanta(cfg_tx_pfc_quanta),
|
||||
.cfg_tx_pfc_refresh(cfg_tx_pfc_refresh),
|
||||
.cfg_quanta_step(tx_mii_select ? (4*256)/512 : (8*256)/512),
|
||||
.cfg_quanta_clk_en(tx_clk_enable),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.stat_tx_lfc_pkt(stat_tx_lfc_pkt),
|
||||
.stat_tx_lfc_xon(stat_tx_lfc_xon),
|
||||
.stat_tx_lfc_xoff(stat_tx_lfc_xoff),
|
||||
.stat_tx_lfc_paused(stat_tx_lfc_paused),
|
||||
.stat_tx_pfc_pkt(stat_tx_pfc_pkt),
|
||||
.stat_tx_pfc_xon(stat_tx_pfc_xon),
|
||||
.stat_tx_pfc_xoff(stat_tx_pfc_xoff),
|
||||
.stat_tx_pfc_paused(stat_tx_pfc_paused)
|
||||
);
|
||||
|
||||
mac_pause_ctrl_rx #(
|
||||
.MCF_PARAMS_SIZE(18),
|
||||
.PFC_ENABLE(PFC_ENABLE)
|
||||
)
|
||||
mac_pause_ctrl_rx_inst (
|
||||
.clk(rx_clk),
|
||||
.rst(rx_rst),
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
.mcf_valid(rx_mcf_valid),
|
||||
.mcf_eth_dst(rx_mcf_eth_dst),
|
||||
.mcf_eth_src(rx_mcf_eth_src),
|
||||
.mcf_eth_type(rx_mcf_eth_type),
|
||||
.mcf_opcode(rx_mcf_opcode),
|
||||
.mcf_params(rx_mcf_params),
|
||||
|
||||
/*
|
||||
* Pause (IEEE 802.3 annex 31B)
|
||||
*/
|
||||
.rx_lfc_en(rx_lfc_en),
|
||||
.rx_lfc_req(rx_lfc_req),
|
||||
.rx_lfc_ack(rx_lfc_ack_int),
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D)
|
||||
*/
|
||||
.rx_pfc_en(rx_pfc_en),
|
||||
.rx_pfc_req(rx_pfc_req),
|
||||
.rx_pfc_ack(rx_pfc_ack),
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
.cfg_rx_lfc_opcode(cfg_rx_lfc_opcode),
|
||||
.cfg_rx_lfc_en(cfg_rx_lfc_en),
|
||||
.cfg_rx_pfc_opcode(cfg_rx_pfc_opcode),
|
||||
.cfg_rx_pfc_en(cfg_rx_pfc_en),
|
||||
.cfg_quanta_step(rx_mii_select ? (4*256)/512 : (8*256)/512),
|
||||
.cfg_quanta_clk_en(rx_clk_enable),
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
.stat_rx_lfc_pkt(stat_rx_lfc_pkt),
|
||||
.stat_rx_lfc_xon(stat_rx_lfc_xon),
|
||||
.stat_rx_lfc_xoff(stat_rx_lfc_xoff),
|
||||
.stat_rx_lfc_paused(stat_rx_lfc_paused),
|
||||
.stat_rx_pfc_pkt(stat_rx_pfc_pkt),
|
||||
.stat_rx_pfc_xon(stat_rx_pfc_xon),
|
||||
.stat_rx_pfc_xoff(stat_rx_pfc_xoff),
|
||||
.stat_rx_pfc_paused(stat_rx_pfc_paused)
|
||||
);
|
||||
|
||||
end else begin
|
||||
|
||||
assign tx_axis_tdata_int = tx_axis_tdata;
|
||||
assign tx_axis_tvalid_int = tx_axis_tvalid;
|
||||
assign tx_axis_tready = tx_axis_tready_int;
|
||||
assign tx_axis_tlast_int = tx_axis_tlast;
|
||||
assign tx_axis_tuser_int = tx_axis_tuser;
|
||||
|
||||
assign rx_axis_tdata = rx_axis_tdata_int;
|
||||
assign rx_axis_tvalid = rx_axis_tvalid_int;
|
||||
assign rx_axis_tlast = rx_axis_tlast_int;
|
||||
assign rx_axis_tuser = rx_axis_tuser_int;
|
||||
|
||||
assign rx_lfc_req = 0;
|
||||
assign rx_pfc_req = 0;
|
||||
assign tx_pause_ack = 0;
|
||||
|
||||
assign stat_tx_mcf = 0;
|
||||
assign stat_rx_mcf = 0;
|
||||
assign stat_tx_lfc_pkt = 0;
|
||||
assign stat_tx_lfc_xon = 0;
|
||||
assign stat_tx_lfc_xoff = 0;
|
||||
assign stat_tx_lfc_paused = 0;
|
||||
assign stat_tx_pfc_pkt = 0;
|
||||
assign stat_tx_pfc_xon = 0;
|
||||
assign stat_tx_pfc_xoff = 0;
|
||||
assign stat_tx_pfc_paused = 0;
|
||||
assign stat_rx_lfc_pkt = 0;
|
||||
assign stat_rx_lfc_xon = 0;
|
||||
assign stat_rx_lfc_xoff = 0;
|
||||
assign stat_rx_lfc_paused = 0;
|
||||
assign stat_rx_pfc_pkt = 0;
|
||||
assign stat_rx_pfc_xon = 0;
|
||||
assign stat_rx_pfc_xoff = 0;
|
||||
assign stat_rx_pfc_paused = 0;
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,175 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2019 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* 10M/100M Ethernet MAC with MII interface
|
||||
*/
|
||||
module eth_mac_mii #
|
||||
(
|
||||
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
|
||||
parameter TARGET = "GENERIC",
|
||||
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
|
||||
// Use BUFR for Virtex-5, Virtex-6, 7-series
|
||||
// Use BUFG for Ultrascale
|
||||
// Use BUFIO2 for Spartan-6
|
||||
parameter CLOCK_INPUT_STYLE = "BUFIO2",
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64
|
||||
)
|
||||
(
|
||||
input wire rst,
|
||||
output wire rx_clk,
|
||||
output wire rx_rst,
|
||||
output wire tx_clk,
|
||||
output wire tx_rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [7:0] tx_axis_tdata,
|
||||
input wire tx_axis_tvalid,
|
||||
output wire tx_axis_tready,
|
||||
input wire tx_axis_tlast,
|
||||
input wire tx_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [7:0] rx_axis_tdata,
|
||||
output wire rx_axis_tvalid,
|
||||
output wire rx_axis_tlast,
|
||||
output wire rx_axis_tuser,
|
||||
|
||||
/*
|
||||
* MII interface
|
||||
*/
|
||||
input wire mii_rx_clk,
|
||||
input wire [3:0] mii_rxd,
|
||||
input wire mii_rx_dv,
|
||||
input wire mii_rx_er,
|
||||
input wire mii_tx_clk,
|
||||
output wire [3:0] mii_txd,
|
||||
output wire mii_tx_en,
|
||||
output wire mii_tx_er,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_start_packet,
|
||||
output wire tx_error_underflow,
|
||||
output wire rx_start_packet,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] cfg_ifg,
|
||||
input wire cfg_tx_enable,
|
||||
input wire cfg_rx_enable
|
||||
);
|
||||
|
||||
wire [3:0] mac_mii_rxd;
|
||||
wire mac_mii_rx_dv;
|
||||
wire mac_mii_rx_er;
|
||||
wire [3:0] mac_mii_txd;
|
||||
wire mac_mii_tx_en;
|
||||
wire mac_mii_tx_er;
|
||||
|
||||
mii_phy_if #(
|
||||
.TARGET(TARGET),
|
||||
.CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE)
|
||||
)
|
||||
mii_phy_if_inst (
|
||||
.rst(rst),
|
||||
|
||||
.mac_mii_rx_clk(rx_clk),
|
||||
.mac_mii_rx_rst(rx_rst),
|
||||
.mac_mii_rxd(mac_mii_rxd),
|
||||
.mac_mii_rx_dv(mac_mii_rx_dv),
|
||||
.mac_mii_rx_er(mac_mii_rx_er),
|
||||
.mac_mii_tx_clk(tx_clk),
|
||||
.mac_mii_tx_rst(tx_rst),
|
||||
.mac_mii_txd(mac_mii_txd),
|
||||
.mac_mii_tx_en(mac_mii_tx_en),
|
||||
.mac_mii_tx_er(mac_mii_tx_er),
|
||||
|
||||
.phy_mii_rx_clk(mii_rx_clk),
|
||||
.phy_mii_rxd(mii_rxd),
|
||||
.phy_mii_rx_dv(mii_rx_dv),
|
||||
.phy_mii_rx_er(mii_rx_er),
|
||||
.phy_mii_tx_clk(mii_tx_clk),
|
||||
.phy_mii_txd(mii_txd),
|
||||
.phy_mii_tx_en(mii_tx_en),
|
||||
.phy_mii_tx_er(mii_tx_er)
|
||||
);
|
||||
// *** there a bunch of missing pins
|
||||
/* verilator lint_off PINMISSING */
|
||||
eth_mac_1g #(
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH)
|
||||
)
|
||||
eth_mac_1g_inst (
|
||||
.tx_clk(tx_clk),
|
||||
.tx_rst(tx_rst),
|
||||
.rx_clk(rx_clk),
|
||||
.rx_rst(rx_rst),
|
||||
.tx_axis_tdata(tx_axis_tdata),
|
||||
.tx_axis_tvalid(tx_axis_tvalid),
|
||||
.tx_axis_tready(tx_axis_tready),
|
||||
.tx_axis_tlast(tx_axis_tlast),
|
||||
.tx_axis_tuser(tx_axis_tuser),
|
||||
.rx_axis_tdata(rx_axis_tdata),
|
||||
.rx_axis_tvalid(rx_axis_tvalid),
|
||||
.rx_axis_tlast(rx_axis_tlast),
|
||||
.rx_axis_tuser(rx_axis_tuser),
|
||||
.gmii_rxd(mac_mii_rxd),
|
||||
.gmii_rx_dv(mac_mii_rx_dv),
|
||||
.gmii_rx_er(mac_mii_rx_er),
|
||||
.gmii_txd(mac_mii_txd),
|
||||
.gmii_tx_en(mac_mii_tx_en),
|
||||
.gmii_tx_er(mac_mii_tx_er),
|
||||
.rx_clk_enable(1'b1),
|
||||
.tx_clk_enable(1'b1),
|
||||
.rx_mii_select(1'b1),
|
||||
.tx_mii_select(1'b1),
|
||||
.tx_start_packet(tx_start_packet),
|
||||
.tx_error_underflow(tx_error_underflow),
|
||||
.rx_start_packet(rx_start_packet),
|
||||
.rx_error_bad_frame(rx_error_bad_frame),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs),
|
||||
.cfg_ifg(cfg_ifg),
|
||||
.cfg_tx_enable(cfg_tx_enable),
|
||||
.cfg_rx_enable(cfg_rx_enable)
|
||||
);
|
||||
/* verilator lint_on PINMISSING */
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,339 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2019 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* 10M/100M Ethernet MAC with MII interface and TX and RX FIFOs
|
||||
*/
|
||||
module eth_mac_mii_fifo #
|
||||
(
|
||||
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
|
||||
parameter TARGET = "GENERIC",
|
||||
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
|
||||
// Use BUFR for Virtex-5, Virtex-6, 7-series
|
||||
// Use BUFG for Ultrascale
|
||||
// Use BUFIO2 for Spartan-6
|
||||
parameter CLOCK_INPUT_STYLE = "BUFIO2",
|
||||
parameter AXIS_DATA_WIDTH = 8,
|
||||
parameter AXIS_KEEP_ENABLE = (AXIS_DATA_WIDTH>8),
|
||||
parameter AXIS_KEEP_WIDTH = (AXIS_DATA_WIDTH/8),
|
||||
parameter ENABLE_PADDING = 1,
|
||||
parameter MIN_FRAME_LENGTH = 64,
|
||||
parameter TX_FIFO_DEPTH = 4096,
|
||||
parameter TX_FIFO_RAM_PIPELINE = 1,
|
||||
parameter TX_FRAME_FIFO = 1,
|
||||
parameter TX_DROP_OVERSIZE_FRAME = TX_FRAME_FIFO,
|
||||
parameter TX_DROP_BAD_FRAME = TX_DROP_OVERSIZE_FRAME,
|
||||
parameter TX_DROP_WHEN_FULL = 0,
|
||||
parameter RX_FIFO_DEPTH = 4096,
|
||||
parameter RX_FIFO_RAM_PIPELINE = 1,
|
||||
parameter RX_FRAME_FIFO = 1,
|
||||
parameter RX_DROP_OVERSIZE_FRAME = RX_FRAME_FIFO,
|
||||
parameter RX_DROP_BAD_FRAME = RX_DROP_OVERSIZE_FRAME,
|
||||
parameter RX_DROP_WHEN_FULL = RX_DROP_OVERSIZE_FRAME
|
||||
)
|
||||
(
|
||||
input wire rst,
|
||||
input wire logic_clk,
|
||||
input wire logic_rst,
|
||||
|
||||
/*
|
||||
* AXI input
|
||||
*/
|
||||
input wire [AXIS_DATA_WIDTH-1:0] tx_axis_tdata,
|
||||
input wire [AXIS_KEEP_WIDTH-1:0] tx_axis_tkeep,
|
||||
input wire tx_axis_tvalid,
|
||||
output wire tx_axis_tready,
|
||||
input wire tx_axis_tlast,
|
||||
input wire tx_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI output
|
||||
*/
|
||||
output wire [AXIS_DATA_WIDTH-1:0] rx_axis_tdata,
|
||||
output wire [AXIS_KEEP_WIDTH-1:0] rx_axis_tkeep,
|
||||
output wire rx_axis_tvalid,
|
||||
input wire rx_axis_tready,
|
||||
output wire rx_axis_tlast,
|
||||
output wire rx_axis_tuser,
|
||||
|
||||
/*
|
||||
* MII interface
|
||||
*/
|
||||
input wire mii_rx_clk,
|
||||
input wire [3:0] mii_rxd,
|
||||
input wire mii_rx_dv,
|
||||
input wire mii_rx_er,
|
||||
input wire mii_tx_clk,
|
||||
output wire [3:0] mii_txd,
|
||||
output wire mii_tx_en,
|
||||
output wire mii_tx_er,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire tx_error_underflow,
|
||||
output wire tx_fifo_overflow,
|
||||
output wire tx_fifo_bad_frame,
|
||||
output wire tx_fifo_good_frame,
|
||||
output wire rx_error_bad_frame,
|
||||
output wire rx_error_bad_fcs,
|
||||
output wire rx_fifo_overflow,
|
||||
output wire rx_fifo_bad_frame,
|
||||
output wire rx_fifo_good_frame,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [7:0] cfg_ifg,
|
||||
input wire cfg_tx_enable,
|
||||
input wire cfg_rx_enable
|
||||
);
|
||||
|
||||
wire tx_clk;
|
||||
wire rx_clk;
|
||||
wire tx_rst;
|
||||
wire rx_rst;
|
||||
|
||||
wire [7:0] tx_fifo_axis_tdata;
|
||||
wire tx_fifo_axis_tvalid;
|
||||
wire tx_fifo_axis_tready;
|
||||
wire tx_fifo_axis_tlast;
|
||||
wire tx_fifo_axis_tuser;
|
||||
|
||||
wire [7:0] rx_fifo_axis_tdata;
|
||||
wire rx_fifo_axis_tvalid;
|
||||
wire rx_fifo_axis_tlast;
|
||||
wire rx_fifo_axis_tuser;
|
||||
|
||||
// synchronize MAC status signals into logic clock domain
|
||||
wire tx_error_underflow_int;
|
||||
|
||||
reg [0:0] tx_sync_reg_1 = 1'b0;
|
||||
reg [0:0] tx_sync_reg_2 = 1'b0;
|
||||
reg [0:0] tx_sync_reg_3 = 1'b0;
|
||||
reg [0:0] tx_sync_reg_4 = 1'b0;
|
||||
|
||||
assign tx_error_underflow = tx_sync_reg_3[0] ^ tx_sync_reg_4[0];
|
||||
|
||||
always @(posedge tx_clk or posedge tx_rst) begin
|
||||
if (tx_rst) begin
|
||||
tx_sync_reg_1 <= 1'b0;
|
||||
end else begin
|
||||
tx_sync_reg_1 <= tx_sync_reg_1 ^ {tx_error_underflow_int};
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge logic_clk or posedge logic_rst) begin
|
||||
if (logic_rst) begin
|
||||
tx_sync_reg_2 <= 1'b0;
|
||||
tx_sync_reg_3 <= 1'b0;
|
||||
tx_sync_reg_4 <= 1'b0;
|
||||
end else begin
|
||||
tx_sync_reg_2 <= tx_sync_reg_1;
|
||||
tx_sync_reg_3 <= tx_sync_reg_2;
|
||||
tx_sync_reg_4 <= tx_sync_reg_3;
|
||||
end
|
||||
end
|
||||
|
||||
wire rx_error_bad_frame_int;
|
||||
wire rx_error_bad_fcs_int;
|
||||
|
||||
reg [1:0] rx_sync_reg_1 = 2'd0;
|
||||
reg [1:0] rx_sync_reg_2 = 2'd0;
|
||||
reg [1:0] rx_sync_reg_3 = 2'd0;
|
||||
reg [1:0] rx_sync_reg_4 = 2'd0;
|
||||
|
||||
assign rx_error_bad_frame = rx_sync_reg_3[0] ^ rx_sync_reg_4[0];
|
||||
assign rx_error_bad_fcs = rx_sync_reg_3[1] ^ rx_sync_reg_4[1];
|
||||
|
||||
always @(posedge rx_clk or posedge rx_rst) begin
|
||||
if (rx_rst) begin
|
||||
rx_sync_reg_1 <= 2'd0;
|
||||
end else begin
|
||||
rx_sync_reg_1 <= rx_sync_reg_1 ^ {rx_error_bad_fcs_int, rx_error_bad_frame_int};
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge logic_clk or posedge logic_rst) begin
|
||||
if (logic_rst) begin
|
||||
rx_sync_reg_2 <= 2'd0;
|
||||
rx_sync_reg_3 <= 2'd0;
|
||||
rx_sync_reg_4 <= 2'd0;
|
||||
end else begin
|
||||
rx_sync_reg_2 <= rx_sync_reg_1;
|
||||
rx_sync_reg_3 <= rx_sync_reg_2;
|
||||
rx_sync_reg_4 <= rx_sync_reg_3;
|
||||
end
|
||||
end
|
||||
|
||||
// *** there are a bunch of missing pins
|
||||
/* verilator lint_off PINMISSING */
|
||||
eth_mac_mii #(
|
||||
.TARGET(TARGET),
|
||||
.CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE),
|
||||
.ENABLE_PADDING(ENABLE_PADDING),
|
||||
.MIN_FRAME_LENGTH(MIN_FRAME_LENGTH)
|
||||
)
|
||||
eth_mac_1g_mii_inst (
|
||||
.rst(rst),
|
||||
.tx_clk(tx_clk),
|
||||
.tx_rst(tx_rst),
|
||||
.rx_clk(rx_clk),
|
||||
.rx_rst(rx_rst),
|
||||
.tx_axis_tdata(tx_fifo_axis_tdata),
|
||||
.tx_axis_tvalid(tx_fifo_axis_tvalid),
|
||||
.tx_axis_tready(tx_fifo_axis_tready),
|
||||
.tx_axis_tlast(tx_fifo_axis_tlast),
|
||||
.tx_axis_tuser(tx_fifo_axis_tuser),
|
||||
.rx_axis_tdata(rx_fifo_axis_tdata),
|
||||
.rx_axis_tvalid(rx_fifo_axis_tvalid),
|
||||
.rx_axis_tlast(rx_fifo_axis_tlast),
|
||||
.rx_axis_tuser(rx_fifo_axis_tuser),
|
||||
.mii_rx_clk(mii_rx_clk),
|
||||
.mii_rxd(mii_rxd),
|
||||
.mii_rx_dv(mii_rx_dv),
|
||||
.mii_rx_er(mii_rx_er),
|
||||
.mii_tx_clk(mii_tx_clk),
|
||||
.mii_txd(mii_txd),
|
||||
.mii_tx_en(mii_tx_en),
|
||||
.mii_tx_er(mii_tx_er),
|
||||
.tx_error_underflow(tx_error_underflow_int),
|
||||
.rx_error_bad_frame(rx_error_bad_frame_int),
|
||||
.rx_error_bad_fcs(rx_error_bad_fcs_int),
|
||||
.cfg_ifg(cfg_ifg),
|
||||
.cfg_tx_enable(cfg_tx_enable),
|
||||
.cfg_rx_enable(cfg_rx_enable)
|
||||
);
|
||||
|
||||
axis_async_fifo_adapter #(
|
||||
.DEPTH(TX_FIFO_DEPTH),
|
||||
.S_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.S_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.S_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.M_DATA_WIDTH(8),
|
||||
.M_KEEP_ENABLE(0),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(1),
|
||||
.RAM_PIPELINE(TX_FIFO_RAM_PIPELINE),
|
||||
.FRAME_FIFO(TX_FRAME_FIFO),
|
||||
.USER_BAD_FRAME_VALUE(1'b1),
|
||||
.USER_BAD_FRAME_MASK(1'b1),
|
||||
.DROP_OVERSIZE_FRAME(TX_DROP_OVERSIZE_FRAME),
|
||||
.DROP_BAD_FRAME(TX_DROP_BAD_FRAME),
|
||||
.DROP_WHEN_FULL(TX_DROP_WHEN_FULL)
|
||||
)
|
||||
tx_fifo (
|
||||
// AXI input
|
||||
.s_clk(logic_clk),
|
||||
.s_rst(logic_rst),
|
||||
.s_axis_tdata(tx_axis_tdata),
|
||||
.s_axis_tkeep(tx_axis_tkeep),
|
||||
.s_axis_tvalid(tx_axis_tvalid),
|
||||
.s_axis_tready(tx_axis_tready),
|
||||
.s_axis_tlast(tx_axis_tlast),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(tx_axis_tuser),
|
||||
// AXI output
|
||||
.m_clk(tx_clk),
|
||||
.m_rst(tx_rst),
|
||||
.m_axis_tdata(tx_fifo_axis_tdata),
|
||||
.m_axis_tkeep(),
|
||||
.m_axis_tvalid(tx_fifo_axis_tvalid),
|
||||
.m_axis_tready(tx_fifo_axis_tready),
|
||||
.m_axis_tlast(tx_fifo_axis_tlast),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(tx_fifo_axis_tuser),
|
||||
// Status
|
||||
.s_status_overflow(tx_fifo_overflow),
|
||||
.s_status_bad_frame(tx_fifo_bad_frame),
|
||||
.s_status_good_frame(tx_fifo_good_frame),
|
||||
.m_status_overflow(),
|
||||
.m_status_bad_frame(),
|
||||
.m_status_good_frame()
|
||||
);
|
||||
|
||||
axis_async_fifo_adapter #(
|
||||
.DEPTH(RX_FIFO_DEPTH),
|
||||
.S_DATA_WIDTH(8),
|
||||
.S_KEEP_ENABLE(0),
|
||||
.M_DATA_WIDTH(AXIS_DATA_WIDTH),
|
||||
.M_KEEP_ENABLE(AXIS_KEEP_ENABLE),
|
||||
.M_KEEP_WIDTH(AXIS_KEEP_WIDTH),
|
||||
.ID_ENABLE(0),
|
||||
.DEST_ENABLE(0),
|
||||
.USER_ENABLE(1),
|
||||
.USER_WIDTH(1),
|
||||
.RAM_PIPELINE(RX_FIFO_RAM_PIPELINE),
|
||||
.FRAME_FIFO(RX_FRAME_FIFO),
|
||||
.USER_BAD_FRAME_VALUE(1'b1),
|
||||
.USER_BAD_FRAME_MASK(1'b1),
|
||||
.DROP_OVERSIZE_FRAME(RX_DROP_OVERSIZE_FRAME),
|
||||
.DROP_BAD_FRAME(RX_DROP_BAD_FRAME),
|
||||
.DROP_WHEN_FULL(RX_DROP_WHEN_FULL)
|
||||
)
|
||||
rx_fifo (
|
||||
// AXI input
|
||||
.s_clk(rx_clk),
|
||||
.s_rst(rx_rst),
|
||||
.s_axis_tdata(rx_fifo_axis_tdata),
|
||||
.s_axis_tkeep(0),
|
||||
.s_axis_tvalid(rx_fifo_axis_tvalid),
|
||||
.s_axis_tready(),
|
||||
.s_axis_tlast(rx_fifo_axis_tlast),
|
||||
.s_axis_tid(0),
|
||||
.s_axis_tdest(0),
|
||||
.s_axis_tuser(rx_fifo_axis_tuser),
|
||||
// AXI output
|
||||
.m_clk(logic_clk),
|
||||
.m_rst(logic_rst),
|
||||
.m_axis_tdata(rx_axis_tdata),
|
||||
.m_axis_tkeep(rx_axis_tkeep),
|
||||
.m_axis_tvalid(rx_axis_tvalid),
|
||||
.m_axis_tready(rx_axis_tready),
|
||||
.m_axis_tlast(rx_axis_tlast),
|
||||
.m_axis_tid(),
|
||||
.m_axis_tdest(),
|
||||
.m_axis_tuser(rx_axis_tuser),
|
||||
// Status
|
||||
.s_status_overflow(),
|
||||
.s_status_bad_frame(),
|
||||
.s_status_good_frame(),
|
||||
.m_status_overflow(rx_fifo_overflow),
|
||||
.m_status_bad_frame(rx_fifo_bad_frame),
|
||||
.m_status_good_frame(rx_fifo_good_frame)
|
||||
);
|
||||
/* verilator lint_on PINMISSING */
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
446
src/rvvi/lfsr.sv
446
src/rvvi/lfsr.sv
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016-2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* Parametrizable combinatorial parallel LFSR/CRC
|
||||
*/
|
||||
module lfsr #
|
||||
(
|
||||
// width of LFSR
|
||||
parameter LFSR_WIDTH = 31,
|
||||
// LFSR polynomial
|
||||
parameter LFSR_POLY = 31'h10000001,
|
||||
// LFSR configuration: "GALOIS", "FIBONACCI"
|
||||
parameter LFSR_CONFIG = "FIBONACCI",
|
||||
// LFSR feed forward enable
|
||||
parameter LFSR_FEED_FORWARD = 0,
|
||||
// bit-reverse input and output
|
||||
parameter REVERSE = 0,
|
||||
// width of data input
|
||||
parameter DATA_WIDTH = 8,
|
||||
// implementation style: "AUTO", "LOOP", "REDUCTION"
|
||||
parameter STYLE = "AUTO"
|
||||
)
|
||||
(
|
||||
input wire [DATA_WIDTH-1:0] data_in,
|
||||
input wire [LFSR_WIDTH-1:0] state_in,
|
||||
output wire [DATA_WIDTH-1:0] data_out,
|
||||
output wire [LFSR_WIDTH-1:0] state_out
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
Fully parametrizable combinatorial parallel LFSR/CRC module. Implements an unrolled LFSR
|
||||
next state computation, shifting DATA_WIDTH bits per pass through the module. Input data
|
||||
is XORed with LFSR feedback path, tie data_in to zero if this is not required.
|
||||
|
||||
Works in two parts: statically computes a set of bit masks, then uses these bit masks to
|
||||
select bits for XORing to compute the next state.
|
||||
|
||||
Ports:
|
||||
|
||||
data_in
|
||||
|
||||
Data bits to be shifted through the LFSR (DATA_WIDTH bits)
|
||||
|
||||
state_in
|
||||
|
||||
LFSR/CRC current state input (LFSR_WIDTH bits)
|
||||
|
||||
data_out
|
||||
|
||||
Data bits shifted out of LFSR (DATA_WIDTH bits)
|
||||
|
||||
state_out
|
||||
|
||||
LFSR/CRC next state output (LFSR_WIDTH bits)
|
||||
|
||||
Parameters:
|
||||
|
||||
LFSR_WIDTH
|
||||
|
||||
Specify width of LFSR/CRC register
|
||||
|
||||
LFSR_POLY
|
||||
|
||||
Specify the LFSR/CRC polynomial in hex format. For example, the polynomial
|
||||
|
||||
x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1
|
||||
|
||||
would be represented as
|
||||
|
||||
32'h04c11db7
|
||||
|
||||
Note that the largest term (x^32) is suppressed. This term is generated automatically based
|
||||
on LFSR_WIDTH.
|
||||
|
||||
LFSR_CONFIG
|
||||
|
||||
Specify the LFSR configuration, either Fibonacci or Galois. Fibonacci is generally used
|
||||
for linear-feedback shift registers (LFSR) for pseudorandom binary sequence (PRBS) generators,
|
||||
scramblers, and descrambers, while Galois is generally used for cyclic redundancy check
|
||||
generators and checkers.
|
||||
|
||||
Fibonacci style (example for 64b66b scrambler, 0x8000000001)
|
||||
|
||||
DIN (LSB first)
|
||||
|
|
||||
V
|
||||
(+)<---------------------------(+)<-----------------------------.
|
||||
| ^ |
|
||||
| .----. .----. .----. | .----. .----. .----. |
|
||||
+->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--'
|
||||
| '----' '----' '----' '----' '----' '----'
|
||||
V
|
||||
DOUT
|
||||
|
||||
Galois style (example for CRC16, 0x8005)
|
||||
|
||||
,-------------------+-------------------------+----------(+)<-- DIN (MSB first)
|
||||
| | | ^
|
||||
| .----. .----. V .----. .----. V .----. |
|
||||
`->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |--+---> DOUT
|
||||
'----' '----' '----' '----' '----'
|
||||
|
||||
LFSR_FEED_FORWARD
|
||||
|
||||
Generate feed forward instead of feed back LFSR. Enable this for PRBS checking and self-
|
||||
synchronous descrambling.
|
||||
|
||||
Fibonacci feed-forward style (example for 64b66b descrambler, 0x8000000001)
|
||||
|
||||
DIN (LSB first)
|
||||
|
|
||||
| .----. .----. .----. .----. .----. .----.
|
||||
+->| 0 |->| 1 |->...->| 38 |-+->| 39 |->...->| 56 |->| 57 |--.
|
||||
| '----' '----' '----' | '----' '----' '----' |
|
||||
| V |
|
||||
(+)<---------------------------(+)------------------------------'
|
||||
|
|
||||
V
|
||||
DOUT
|
||||
|
||||
Galois feed-forward style
|
||||
|
||||
,-------------------+-------------------------+------------+--- DIN (MSB first)
|
||||
| | | |
|
||||
| .----. .----. V .----. .----. V .----. V
|
||||
`->| 0 |->| 1 |->(+)->| 2 |->...->| 14 |->(+)->| 15 |->(+)-> DOUT
|
||||
'----' '----' '----' '----' '----'
|
||||
|
||||
REVERSE
|
||||
|
||||
Bit-reverse LFSR input and output. Shifts MSB first by default, set REVERSE for LSB first.
|
||||
|
||||
DATA_WIDTH
|
||||
|
||||
Specify width of input and output data bus. The module will perform one shift per input
|
||||
data bit, so if the input data bus is not required tie data_in to zero and set DATA_WIDTH
|
||||
to the required number of shifts per clock cycle.
|
||||
|
||||
STYLE
|
||||
|
||||
Specify implementation style. Can be "AUTO", "LOOP", or "REDUCTION". When "AUTO"
|
||||
is selected, implemenation will be "LOOP" or "REDUCTION" based on synthesis translate
|
||||
directives. "REDUCTION" and "LOOP" are functionally identical, however they simulate
|
||||
and synthesize differently. "REDUCTION" is implemented with a loop over a Verilog
|
||||
reduction operator. "LOOP" is implemented as a doubly-nested loop with no reduction
|
||||
operator. "REDUCTION" is very fast for simulation in iverilog and synthesizes well in
|
||||
Quartus but synthesizes poorly in ISE, likely due to large inferred XOR gates causing
|
||||
problems with the optimizer. "LOOP" synthesizes will in both ISE and Quartus. "AUTO"
|
||||
will default to "REDUCTION" when simulating and "LOOP" for synthesizers that obey
|
||||
synthesis translate directives.
|
||||
|
||||
Settings for common LFSR/CRC implementations:
|
||||
|
||||
Name Configuration Length Polynomial Initial value Notes
|
||||
CRC16-IBM Galois, bit-reverse 16 16'h8005 16'hffff
|
||||
CRC16-CCITT Galois 16 16'h1021 16'h1d0f
|
||||
CRC32 Galois, bit-reverse 32 32'h04c11db7 32'hffffffff Ethernet FCS; invert final output
|
||||
CRC32C Galois, bit-reverse 32 32'h1edc6f41 32'hffffffff iSCSI, Intel CRC32 instruction; invert final output
|
||||
PRBS6 Fibonacci 6 6'h21 any
|
||||
PRBS7 Fibonacci 7 7'h41 any
|
||||
PRBS9 Fibonacci 9 9'h021 any ITU V.52
|
||||
PRBS10 Fibonacci 10 10'h081 any ITU
|
||||
PRBS11 Fibonacci 11 11'h201 any ITU O.152
|
||||
PRBS15 Fibonacci, inverted 15 15'h4001 any ITU O.152
|
||||
PRBS17 Fibonacci 17 17'h04001 any
|
||||
PRBS20 Fibonacci 20 20'h00009 any ITU V.57
|
||||
PRBS23 Fibonacci, inverted 23 23'h040001 any ITU O.151
|
||||
PRBS29 Fibonacci, inverted 29 29'h08000001 any
|
||||
PRBS31 Fibonacci, inverted 31 31'h10000001 any
|
||||
64b66b Fibonacci, bit-reverse 58 58'h8000000001 any 10G Ethernet
|
||||
128b130b Galois, bit-reverse 23 23'h210125 any PCIe gen 3
|
||||
|
||||
*/
|
||||
|
||||
function [LFSR_WIDTH+DATA_WIDTH-1:0] lfsr_mask(input [31:0] index);
|
||||
reg [LFSR_WIDTH-1:0] lfsr_mask_state[LFSR_WIDTH-1:0];
|
||||
reg [DATA_WIDTH-1:0] lfsr_mask_data[LFSR_WIDTH-1:0];
|
||||
reg [LFSR_WIDTH-1:0] output_mask_state[DATA_WIDTH-1:0];
|
||||
reg [DATA_WIDTH-1:0] output_mask_data[DATA_WIDTH-1:0];
|
||||
|
||||
reg [LFSR_WIDTH-1:0] state_val;
|
||||
reg [DATA_WIDTH-1:0] data_val;
|
||||
|
||||
reg [DATA_WIDTH-1:0] data_mask;
|
||||
|
||||
integer i, j;
|
||||
|
||||
begin
|
||||
// init bit masks
|
||||
for (i = 0; i < LFSR_WIDTH; i = i + 1) begin
|
||||
lfsr_mask_state[i] = 0;
|
||||
lfsr_mask_state[i][i] = 1'b1;
|
||||
lfsr_mask_data[i] = 0;
|
||||
end
|
||||
for (i = 0; i < DATA_WIDTH; i = i + 1) begin
|
||||
output_mask_state[i] = 0;
|
||||
if (i < LFSR_WIDTH) begin
|
||||
output_mask_state[i][i] = 1'b1;
|
||||
end
|
||||
output_mask_data[i] = 0;
|
||||
end
|
||||
|
||||
// simulate shift register
|
||||
if (LFSR_CONFIG == "FIBONACCI") begin
|
||||
// Fibonacci configuration
|
||||
for (data_mask = {1'b1, {DATA_WIDTH-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_WIDTH-1];
|
||||
data_val = lfsr_mask_data[LFSR_WIDTH-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// add XOR inputs from correct indicies
|
||||
for (j = 1; j < LFSR_WIDTH; j = j + 1) begin
|
||||
if ((LFSR_POLY >> j) & 1) begin
|
||||
state_val = lfsr_mask_state[j-1] ^ state_val;
|
||||
data_val = lfsr_mask_data[j-1] ^ data_val;
|
||||
end
|
||||
end
|
||||
|
||||
// shift
|
||||
for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = {LFSR_WIDTH{1'b0}};
|
||||
data_val = data_mask;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
end
|
||||
end else if (LFSR_CONFIG == "GALOIS") begin
|
||||
// Galois configuration
|
||||
for (data_mask = {1'b1, {DATA_WIDTH-1{1'b0}}}; data_mask != 0; data_mask = data_mask >> 1) begin
|
||||
// determine shift in value
|
||||
// current value in last FF, XOR with input data bit (MSB first)
|
||||
state_val = lfsr_mask_state[LFSR_WIDTH-1];
|
||||
data_val = lfsr_mask_data[LFSR_WIDTH-1];
|
||||
data_val = data_val ^ data_mask;
|
||||
|
||||
// shift
|
||||
for (j = LFSR_WIDTH-1; j > 0; j = j - 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j-1];
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j-1];
|
||||
end
|
||||
for (j = DATA_WIDTH-1; j > 0; j = j - 1) begin
|
||||
output_mask_state[j] = output_mask_state[j-1];
|
||||
output_mask_data[j] = output_mask_data[j-1];
|
||||
end
|
||||
output_mask_state[0] = state_val;
|
||||
output_mask_data[0] = data_val;
|
||||
if (LFSR_FEED_FORWARD) begin
|
||||
// only shift in new input data
|
||||
state_val = {LFSR_WIDTH{1'b0}};
|
||||
data_val = data_mask;
|
||||
end
|
||||
lfsr_mask_state[0] = state_val;
|
||||
lfsr_mask_data[0] = data_val;
|
||||
|
||||
// add XOR inputs at correct indicies
|
||||
for (j = 1; j < LFSR_WIDTH; j = j + 1) begin
|
||||
if ((LFSR_POLY >> j) & 1) begin
|
||||
lfsr_mask_state[j] = lfsr_mask_state[j] ^ state_val;
|
||||
lfsr_mask_data[j] = lfsr_mask_data[j] ^ data_val;
|
||||
end
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
$error("Error: unknown configuration setting!");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// reverse bits if selected
|
||||
if (REVERSE) begin
|
||||
if (index < LFSR_WIDTH) begin
|
||||
state_val = 0;
|
||||
for (i = 0; i < LFSR_WIDTH; i = i + 1) begin
|
||||
state_val[i] = lfsr_mask_state[LFSR_WIDTH-index-1][LFSR_WIDTH-i-1];
|
||||
end
|
||||
|
||||
data_val = 0;
|
||||
for (i = 0; i < DATA_WIDTH; i = i + 1) begin
|
||||
data_val[i] = lfsr_mask_data[LFSR_WIDTH-index-1][DATA_WIDTH-i-1];
|
||||
end
|
||||
end else begin
|
||||
state_val = 0;
|
||||
for (i = 0; i < LFSR_WIDTH; i = i + 1) begin
|
||||
state_val[i] = output_mask_state[DATA_WIDTH-(index-LFSR_WIDTH)-1][LFSR_WIDTH-i-1];
|
||||
end
|
||||
|
||||
data_val = 0;
|
||||
for (i = 0; i < DATA_WIDTH; i = i + 1) begin
|
||||
data_val[i] = output_mask_data[DATA_WIDTH-(index-LFSR_WIDTH)-1][DATA_WIDTH-i-1];
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
if (index < LFSR_WIDTH) begin
|
||||
state_val = lfsr_mask_state[index];
|
||||
data_val = lfsr_mask_data[index];
|
||||
end else begin
|
||||
state_val = output_mask_state[index-LFSR_WIDTH];
|
||||
data_val = output_mask_data[index-LFSR_WIDTH];
|
||||
end
|
||||
end
|
||||
lfsr_mask = {data_val, state_val};
|
||||
end
|
||||
endfunction
|
||||
|
||||
// synthesis translate_off
|
||||
`define SIMULATION
|
||||
// synthesis translate_on
|
||||
|
||||
`ifdef SIMULATION
|
||||
// "AUTO" style is "REDUCTION" for faster simulation
|
||||
parameter STYLE_INT = (STYLE == "AUTO") ? "REDUCTION" : STYLE;
|
||||
`else
|
||||
// "AUTO" style is "LOOP" for better synthesis result
|
||||
parameter STYLE_INT = (STYLE == "AUTO") ? "LOOP" : STYLE;
|
||||
`endif
|
||||
|
||||
genvar n;
|
||||
|
||||
generate
|
||||
|
||||
if (STYLE_INT == "REDUCTION") begin
|
||||
|
||||
// use Verilog reduction operator
|
||||
// fast in iverilog
|
||||
// significantly larger than generated code with ISE (inferred wide XORs may be tripping up optimizer)
|
||||
// slightly smaller than generated code with Quartus
|
||||
// --> better for simulation
|
||||
|
||||
for (n = 0; n < LFSR_WIDTH; n = n + 1) begin : lfsr_state
|
||||
wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n);
|
||||
assign state_out[n] = ^({data_in, state_in} & mask);
|
||||
end
|
||||
for (n = 0; n < DATA_WIDTH; n = n + 1) begin : lfsr_data
|
||||
wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n+LFSR_WIDTH);
|
||||
assign data_out[n] = ^({data_in, state_in} & mask);
|
||||
end
|
||||
|
||||
end else if (STYLE_INT == "LOOP") begin
|
||||
|
||||
// use nested loops
|
||||
// very slow in iverilog
|
||||
// slightly smaller than generated code with ISE
|
||||
// same size as generated code with Quartus
|
||||
// --> better for synthesis
|
||||
|
||||
for (n = 0; n < LFSR_WIDTH; n = n + 1) begin : lfsr_state
|
||||
wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n);
|
||||
|
||||
reg state_reg;
|
||||
|
||||
assign state_out[n] = state_reg;
|
||||
|
||||
integer i;
|
||||
|
||||
always @* begin
|
||||
state_reg = 1'b0;
|
||||
for (i = 0; i < LFSR_WIDTH; i = i + 1) begin
|
||||
if (mask[i]) begin
|
||||
state_reg = state_reg ^ state_in[i];
|
||||
end
|
||||
end
|
||||
for (i = 0; i < DATA_WIDTH; i = i + 1) begin
|
||||
if (mask[i+LFSR_WIDTH]) begin
|
||||
state_reg = state_reg ^ data_in[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
for (n = 0; n < DATA_WIDTH; n = n + 1) begin : lfsr_data
|
||||
wire [LFSR_WIDTH+DATA_WIDTH-1:0] mask = lfsr_mask(n+LFSR_WIDTH);
|
||||
|
||||
reg data_reg;
|
||||
|
||||
assign data_out[n] = data_reg;
|
||||
|
||||
integer i;
|
||||
|
||||
always @* begin
|
||||
data_reg = 1'b0;
|
||||
for (i = 0; i < LFSR_WIDTH; i = i + 1) begin
|
||||
if (mask[i]) begin
|
||||
data_reg = data_reg ^ state_in[i];
|
||||
end
|
||||
end
|
||||
for (i = 0; i < DATA_WIDTH; i = i + 1) begin
|
||||
if (mask[i+LFSR_WIDTH]) begin
|
||||
data_reg = data_reg ^ data_in[i];
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
initial begin
|
||||
$error("Error: unknown style setting!");
|
||||
$finish;
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,447 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* MAC control receive
|
||||
*/
|
||||
module mac_ctrl_rx #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter KEEP_ENABLE = DATA_WIDTH>8,
|
||||
parameter KEEP_WIDTH = DATA_WIDTH/8,
|
||||
parameter ID_ENABLE = 0,
|
||||
parameter ID_WIDTH = 8,
|
||||
parameter DEST_ENABLE = 0,
|
||||
parameter DEST_WIDTH = 8,
|
||||
parameter USER_ENABLE = 1,
|
||||
parameter USER_WIDTH = 1,
|
||||
parameter USE_READY = 0,
|
||||
parameter MCF_PARAMS_SIZE = 18
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI stream input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [ID_WIDTH-1:0] s_axis_tid,
|
||||
input wire [DEST_WIDTH-1:0] s_axis_tdest,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI stream output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire [ID_WIDTH-1:0] m_axis_tid,
|
||||
output wire [DEST_WIDTH-1:0] m_axis_tdest,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser,
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
output wire mcf_valid,
|
||||
output wire [47:0] mcf_eth_dst,
|
||||
output wire [47:0] mcf_eth_src,
|
||||
output wire [15:0] mcf_eth_type,
|
||||
output wire [15:0] mcf_opcode,
|
||||
output wire [MCF_PARAMS_SIZE*8-1:0] mcf_params,
|
||||
output wire [ID_WIDTH-1:0] mcf_id,
|
||||
output wire [DEST_WIDTH-1:0] mcf_dest,
|
||||
output wire [USER_WIDTH-1:0] mcf_user,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [47:0] cfg_mcf_rx_eth_dst_mcast,
|
||||
input wire cfg_mcf_rx_check_eth_dst_mcast,
|
||||
input wire [47:0] cfg_mcf_rx_eth_dst_ucast,
|
||||
input wire cfg_mcf_rx_check_eth_dst_ucast,
|
||||
input wire [47:0] cfg_mcf_rx_eth_src,
|
||||
input wire cfg_mcf_rx_check_eth_src,
|
||||
input wire [15:0] cfg_mcf_rx_eth_type,
|
||||
input wire [15:0] cfg_mcf_rx_opcode_lfc,
|
||||
input wire cfg_mcf_rx_check_opcode_lfc,
|
||||
input wire [15:0] cfg_mcf_rx_opcode_pfc,
|
||||
input wire cfg_mcf_rx_check_opcode_pfc,
|
||||
input wire cfg_mcf_rx_forward,
|
||||
input wire cfg_mcf_rx_enable,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire stat_rx_mcf
|
||||
);
|
||||
|
||||
parameter BYTE_LANES = KEEP_ENABLE ? KEEP_WIDTH : 1;
|
||||
|
||||
parameter HDR_SIZE = 60;
|
||||
|
||||
parameter CYCLE_COUNT = (HDR_SIZE+BYTE_LANES-1)/BYTE_LANES;
|
||||
|
||||
parameter PTR_WIDTH = $clog2(CYCLE_COUNT);
|
||||
|
||||
parameter OFFSET = HDR_SIZE % BYTE_LANES;
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (BYTE_LANES * 8 != DATA_WIDTH) begin
|
||||
$error("Error: AXI stream interface requires byte (8-bit) granularity (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (MCF_PARAMS_SIZE > 44) begin
|
||||
$error("Error: Maximum MCF_PARAMS_SIZE is 44 bytes (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
|
||||
MAC control frame
|
||||
|
||||
Field Length
|
||||
Destination MAC address 6 octets [01:80:C2:00:00:01]
|
||||
Source MAC address 6 octets
|
||||
Ethertype 2 octets [0x8808]
|
||||
Opcode 2 octets
|
||||
Parameters 0-44 octets
|
||||
|
||||
This module manages the reception of MAC control frames. Incoming frames are
|
||||
checked based on the ethertype and (optionally) MAC addresses. Matching control
|
||||
frames are marked by setting tuser[0] on the data output and forwarded through
|
||||
a separate interface for processing.
|
||||
|
||||
*/
|
||||
|
||||
reg read_mcf_reg = 1'b1, read_mcf_next;
|
||||
reg mcf_frame_reg = 1'b0, mcf_frame_next;
|
||||
reg [PTR_WIDTH-1:0] ptr_reg = 0, ptr_next;
|
||||
|
||||
reg s_axis_tready_reg = 1'b0, s_axis_tready_next;
|
||||
|
||||
// internal datapath
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_int;
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_int;
|
||||
reg m_axis_tvalid_int;
|
||||
reg m_axis_tready_int_reg = 1'b0;
|
||||
reg m_axis_tlast_int;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_int;
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_int;
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_int;
|
||||
wire m_axis_tready_int_early;
|
||||
|
||||
reg mcf_valid_reg = 0, mcf_valid_next;
|
||||
reg [47:0] mcf_eth_dst_reg = 0, mcf_eth_dst_next;
|
||||
reg [47:0] mcf_eth_src_reg = 0, mcf_eth_src_next;
|
||||
reg [15:0] mcf_eth_type_reg = 0, mcf_eth_type_next;
|
||||
reg [15:0] mcf_opcode_reg = 0, mcf_opcode_next;
|
||||
reg [MCF_PARAMS_SIZE*8-1:0] mcf_params_reg = 0, mcf_params_next;
|
||||
reg [ID_WIDTH-1:0] mcf_id_reg = 0, mcf_id_next;
|
||||
reg [DEST_WIDTH-1:0] mcf_dest_reg = 0, mcf_dest_next;
|
||||
reg [USER_WIDTH-1:0] mcf_user_reg = 0, mcf_user_next;
|
||||
|
||||
reg stat_rx_mcf_reg = 1'b0, stat_rx_mcf_next;
|
||||
|
||||
assign s_axis_tready = s_axis_tready_reg;
|
||||
|
||||
assign mcf_valid = mcf_valid_reg;
|
||||
assign mcf_eth_dst = mcf_eth_dst_reg;
|
||||
assign mcf_eth_src = mcf_eth_src_reg;
|
||||
assign mcf_eth_type = mcf_eth_type_reg;
|
||||
assign mcf_opcode = mcf_opcode_reg;
|
||||
assign mcf_params = mcf_params_reg;
|
||||
assign mcf_id = mcf_id_reg;
|
||||
assign mcf_dest = mcf_dest_reg;
|
||||
assign mcf_user = mcf_user_reg;
|
||||
|
||||
assign stat_rx_mcf = stat_rx_mcf_reg;
|
||||
|
||||
wire mcf_eth_dst_mcast_match = mcf_eth_dst_next == cfg_mcf_rx_eth_dst_mcast;
|
||||
wire mcf_eth_dst_ucast_match = mcf_eth_dst_next == cfg_mcf_rx_eth_dst_ucast;
|
||||
wire mcf_eth_src_match = mcf_eth_src_next == cfg_mcf_rx_eth_src;
|
||||
wire mcf_eth_type_match = mcf_eth_type_next == cfg_mcf_rx_eth_type;
|
||||
wire mcf_opcode_lfc_match = mcf_opcode_next == cfg_mcf_rx_opcode_lfc;
|
||||
wire mcf_opcode_pfc_match = mcf_opcode_next == cfg_mcf_rx_opcode_pfc;
|
||||
|
||||
wire mcf_eth_dst_match = ((mcf_eth_dst_mcast_match && cfg_mcf_rx_check_eth_dst_mcast) ||
|
||||
(mcf_eth_dst_ucast_match && cfg_mcf_rx_check_eth_dst_ucast) ||
|
||||
(!cfg_mcf_rx_check_eth_dst_mcast && !cfg_mcf_rx_check_eth_dst_ucast));
|
||||
|
||||
wire mcf_opcode_match = ((mcf_opcode_lfc_match && cfg_mcf_rx_check_opcode_lfc) ||
|
||||
(mcf_opcode_pfc_match && cfg_mcf_rx_check_opcode_pfc) ||
|
||||
(!cfg_mcf_rx_check_opcode_lfc && !cfg_mcf_rx_check_opcode_pfc));
|
||||
|
||||
wire mcf_match = (mcf_eth_dst_match &&
|
||||
(mcf_eth_src_match || !cfg_mcf_rx_check_eth_src) &&
|
||||
mcf_eth_type_match && mcf_opcode_match);
|
||||
|
||||
integer k;
|
||||
|
||||
always @* begin
|
||||
read_mcf_next = read_mcf_reg;
|
||||
mcf_frame_next = mcf_frame_reg;
|
||||
ptr_next = ptr_reg;
|
||||
|
||||
// pass through data
|
||||
m_axis_tdata_int = s_axis_tdata;
|
||||
m_axis_tkeep_int = s_axis_tkeep;
|
||||
m_axis_tvalid_int = s_axis_tvalid;
|
||||
m_axis_tlast_int = s_axis_tlast;
|
||||
m_axis_tid_int = s_axis_tid;
|
||||
m_axis_tdest_int = s_axis_tdest;
|
||||
m_axis_tuser_int = s_axis_tuser;
|
||||
|
||||
s_axis_tready_next = m_axis_tready_int_early || !USE_READY;
|
||||
|
||||
mcf_valid_next = 1'b0;
|
||||
mcf_eth_dst_next = mcf_eth_dst_reg;
|
||||
mcf_eth_src_next = mcf_eth_src_reg;
|
||||
mcf_eth_type_next = mcf_eth_type_reg;
|
||||
mcf_opcode_next = mcf_opcode_reg;
|
||||
mcf_params_next = mcf_params_reg;
|
||||
mcf_id_next = mcf_id_reg;
|
||||
mcf_dest_next = mcf_dest_reg;
|
||||
mcf_user_next = mcf_user_reg;
|
||||
|
||||
stat_rx_mcf_next = 1'b0;
|
||||
|
||||
if ((s_axis_tready || !USE_READY) && s_axis_tvalid) begin
|
||||
if (read_mcf_reg) begin
|
||||
ptr_next = ptr_reg + 1;
|
||||
|
||||
mcf_id_next = s_axis_tid;
|
||||
mcf_dest_next = s_axis_tdest;
|
||||
mcf_user_next = s_axis_tuser;
|
||||
|
||||
`define _HEADER_FIELD_(offset, field) \
|
||||
if (ptr_reg == offset/BYTE_LANES) begin \
|
||||
field = s_axis_tdata[(offset%BYTE_LANES)*8 +: 8]; \
|
||||
end
|
||||
|
||||
`_HEADER_FIELD_(0, mcf_eth_dst_next[5*8 +: 8])
|
||||
`_HEADER_FIELD_(1, mcf_eth_dst_next[4*8 +: 8])
|
||||
`_HEADER_FIELD_(2, mcf_eth_dst_next[3*8 +: 8])
|
||||
`_HEADER_FIELD_(3, mcf_eth_dst_next[2*8 +: 8])
|
||||
`_HEADER_FIELD_(4, mcf_eth_dst_next[1*8 +: 8])
|
||||
`_HEADER_FIELD_(5, mcf_eth_dst_next[0*8 +: 8])
|
||||
`_HEADER_FIELD_(6, mcf_eth_src_next[5*8 +: 8])
|
||||
`_HEADER_FIELD_(7, mcf_eth_src_next[4*8 +: 8])
|
||||
`_HEADER_FIELD_(8, mcf_eth_src_next[3*8 +: 8])
|
||||
`_HEADER_FIELD_(9, mcf_eth_src_next[2*8 +: 8])
|
||||
`_HEADER_FIELD_(10, mcf_eth_src_next[1*8 +: 8])
|
||||
`_HEADER_FIELD_(11, mcf_eth_src_next[0*8 +: 8])
|
||||
`_HEADER_FIELD_(12, mcf_eth_type_next[1*8 +: 8])
|
||||
`_HEADER_FIELD_(13, mcf_eth_type_next[0*8 +: 8])
|
||||
`_HEADER_FIELD_(14, mcf_opcode_next[1*8 +: 8])
|
||||
`_HEADER_FIELD_(15, mcf_opcode_next[0*8 +: 8])
|
||||
|
||||
if (ptr_reg == 0/BYTE_LANES) begin
|
||||
// ensure params field gets cleared
|
||||
mcf_params_next = 0;
|
||||
end
|
||||
|
||||
for (k = 0; k < MCF_PARAMS_SIZE; k = k + 1) begin
|
||||
if (ptr_reg == (16+k)/BYTE_LANES) begin
|
||||
mcf_params_next[k*8 +: 8] = s_axis_tdata[((16+k)%BYTE_LANES)*8 +: 8];
|
||||
end
|
||||
end
|
||||
|
||||
if (ptr_reg == 15/BYTE_LANES && (!KEEP_ENABLE || s_axis_tkeep[13%BYTE_LANES])) begin
|
||||
// record match at end of opcode field
|
||||
mcf_frame_next = mcf_match && cfg_mcf_rx_enable;
|
||||
end
|
||||
|
||||
if (ptr_reg == (HDR_SIZE-1)/BYTE_LANES) begin
|
||||
read_mcf_next = 1'b0;
|
||||
end
|
||||
|
||||
`undef _HEADER_FIELD_
|
||||
end
|
||||
|
||||
if (s_axis_tlast) begin
|
||||
if (s_axis_tuser[0]) begin
|
||||
// frame marked invalid
|
||||
end else if (mcf_frame_next) begin
|
||||
if (!cfg_mcf_rx_forward) begin
|
||||
// mark frame invalid
|
||||
m_axis_tuser_int[0] = 1'b1;
|
||||
end
|
||||
// transfer out MAC control frame
|
||||
mcf_valid_next = 1'b1;
|
||||
stat_rx_mcf_next = 1'b1;
|
||||
end
|
||||
|
||||
read_mcf_next = 1'b1;
|
||||
mcf_frame_next = 1'b0;
|
||||
ptr_next = 0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
read_mcf_reg <= read_mcf_next;
|
||||
mcf_frame_reg <= mcf_frame_next;
|
||||
ptr_reg <= ptr_next;
|
||||
|
||||
s_axis_tready_reg <= s_axis_tready_next;
|
||||
|
||||
mcf_valid_reg <= mcf_valid_next;
|
||||
mcf_eth_dst_reg <= mcf_eth_dst_next;
|
||||
mcf_eth_src_reg <= mcf_eth_src_next;
|
||||
mcf_eth_type_reg <= mcf_eth_type_next;
|
||||
mcf_opcode_reg <= mcf_opcode_next;
|
||||
mcf_params_reg <= mcf_params_next;
|
||||
mcf_id_reg <= mcf_id_next;
|
||||
mcf_dest_reg <= mcf_dest_next;
|
||||
mcf_user_reg <= mcf_user_next;
|
||||
|
||||
stat_rx_mcf_reg <= stat_rx_mcf_next;
|
||||
|
||||
if (rst) begin
|
||||
read_mcf_reg <= 1'b1;
|
||||
mcf_frame_reg <= 1'b0;
|
||||
ptr_reg <= 0;
|
||||
s_axis_tready_reg <= 1'b0;
|
||||
mcf_valid_reg <= 1'b0;
|
||||
stat_rx_mcf_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
|
||||
reg temp_m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
// datapath control
|
||||
reg store_axis_int_to_output;
|
||||
reg store_axis_int_to_temp;
|
||||
reg store_axis_temp_to_output;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||
|
||||
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||
assign m_axis_tready_int_early = m_axis_tready || !USE_READY || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !m_axis_tvalid_int));
|
||||
|
||||
always @* begin
|
||||
// transfer sink ready state to source
|
||||
m_axis_tvalid_next = m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
|
||||
store_axis_int_to_output = 1'b0;
|
||||
store_axis_int_to_temp = 1'b0;
|
||||
store_axis_temp_to_output = 1'b0;
|
||||
|
||||
if (m_axis_tready_int_reg) begin
|
||||
// input is ready
|
||||
if (m_axis_tready || !USE_READY || !m_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_output = 1'b1;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_temp = 1'b1;
|
||||
end
|
||||
end else if (m_axis_tready || !USE_READY) begin
|
||||
// input is not ready, but output is ready
|
||||
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = 1'b0;
|
||||
store_axis_temp_to_output = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_next;
|
||||
m_axis_tready_int_reg <= m_axis_tready_int_early;
|
||||
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
|
||||
|
||||
// datapath
|
||||
if (store_axis_int_to_output) begin
|
||||
m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
m_axis_tid_reg <= m_axis_tid_int;
|
||||
m_axis_tdest_reg <= m_axis_tdest_int;
|
||||
m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end else if (store_axis_temp_to_output) begin
|
||||
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
|
||||
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
|
||||
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
|
||||
m_axis_tid_reg <= temp_m_axis_tid_reg;
|
||||
m_axis_tdest_reg <= temp_m_axis_tdest_reg;
|
||||
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
|
||||
end
|
||||
|
||||
if (store_axis_int_to_temp) begin
|
||||
temp_m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
temp_m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
temp_m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
temp_m_axis_tid_reg <= m_axis_tid_int;
|
||||
temp_m_axis_tdest_reg <= m_axis_tdest_int;
|
||||
temp_m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tready_int_reg <= 1'b0;
|
||||
temp_m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,420 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* MAC control transmit
|
||||
*/
|
||||
module mac_ctrl_tx #
|
||||
(
|
||||
parameter DATA_WIDTH = 8,
|
||||
parameter KEEP_ENABLE = DATA_WIDTH>8,
|
||||
parameter KEEP_WIDTH = DATA_WIDTH/8,
|
||||
parameter ID_ENABLE = 0,
|
||||
parameter ID_WIDTH = 8,
|
||||
parameter DEST_ENABLE = 0,
|
||||
parameter DEST_WIDTH = 8,
|
||||
parameter USER_ENABLE = 1,
|
||||
parameter USER_WIDTH = 1,
|
||||
parameter MCF_PARAMS_SIZE = 18
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* AXI stream input
|
||||
*/
|
||||
input wire [DATA_WIDTH-1:0] s_axis_tdata,
|
||||
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
|
||||
input wire s_axis_tvalid,
|
||||
output wire s_axis_tready,
|
||||
input wire s_axis_tlast,
|
||||
input wire [ID_WIDTH-1:0] s_axis_tid,
|
||||
input wire [DEST_WIDTH-1:0] s_axis_tdest,
|
||||
input wire [USER_WIDTH-1:0] s_axis_tuser,
|
||||
|
||||
/*
|
||||
* AXI stream output
|
||||
*/
|
||||
output wire [DATA_WIDTH-1:0] m_axis_tdata,
|
||||
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
|
||||
output wire m_axis_tvalid,
|
||||
input wire m_axis_tready,
|
||||
output wire m_axis_tlast,
|
||||
output wire [ID_WIDTH-1:0] m_axis_tid,
|
||||
output wire [DEST_WIDTH-1:0] m_axis_tdest,
|
||||
output wire [USER_WIDTH-1:0] m_axis_tuser,
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
input wire mcf_valid,
|
||||
output wire mcf_ready,
|
||||
input wire [47:0] mcf_eth_dst,
|
||||
input wire [47:0] mcf_eth_src,
|
||||
input wire [15:0] mcf_eth_type,
|
||||
input wire [15:0] mcf_opcode,
|
||||
input wire [MCF_PARAMS_SIZE*8-1:0] mcf_params,
|
||||
input wire [ID_WIDTH-1:0] mcf_id,
|
||||
input wire [DEST_WIDTH-1:0] mcf_dest,
|
||||
input wire [USER_WIDTH-1:0] mcf_user,
|
||||
|
||||
/*
|
||||
* Pause interface
|
||||
*/
|
||||
input wire tx_pause_req,
|
||||
output wire tx_pause_ack,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire stat_tx_mcf
|
||||
);
|
||||
|
||||
parameter BYTE_LANES = KEEP_ENABLE ? KEEP_WIDTH : 1;
|
||||
|
||||
parameter HDR_SIZE = 60;
|
||||
|
||||
parameter CYCLE_COUNT = (HDR_SIZE+BYTE_LANES-1)/BYTE_LANES;
|
||||
|
||||
parameter PTR_WIDTH = $clog2(CYCLE_COUNT);
|
||||
|
||||
parameter OFFSET = HDR_SIZE % BYTE_LANES;
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (BYTE_LANES * 8 != DATA_WIDTH) begin
|
||||
$error("Error: AXI stream interface requires byte (8-bit) granularity (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
|
||||
if (MCF_PARAMS_SIZE > 44) begin
|
||||
$error("Error: Maximum MCF_PARAMS_SIZE is 44 bytes (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
/*
|
||||
|
||||
MAC control frame
|
||||
|
||||
Field Length
|
||||
Destination MAC address 6 octets [01:80:C2:00:00:01]
|
||||
Source MAC address 6 octets
|
||||
Ethertype 2 octets [0x8808]
|
||||
Opcode 2 octets
|
||||
Parameters 0-44 octets
|
||||
|
||||
This module manages the transmission of MAC control frames. Control frames
|
||||
are accepted in parallel, serialized, and merged at a higher priority with
|
||||
data traffic.
|
||||
|
||||
*/
|
||||
|
||||
reg send_data_reg = 1'b0, send_data_next;
|
||||
reg send_mcf_reg = 1'b0, send_mcf_next;
|
||||
reg [PTR_WIDTH-1:0] ptr_reg = 0, ptr_next;
|
||||
|
||||
reg s_axis_tready_reg = 1'b0, s_axis_tready_next;
|
||||
reg mcf_ready_reg = 1'b0, mcf_ready_next;
|
||||
reg tx_pause_ack_reg = 1'b0, tx_pause_ack_next;
|
||||
reg stat_tx_mcf_reg = 1'b0, stat_tx_mcf_next;
|
||||
|
||||
// internal datapath
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_int;
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_int;
|
||||
reg m_axis_tvalid_int;
|
||||
reg m_axis_tready_int_reg = 1'b0;
|
||||
reg m_axis_tlast_int;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_int;
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_int;
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_int;
|
||||
wire m_axis_tready_int_early;
|
||||
|
||||
assign s_axis_tready = s_axis_tready_reg;
|
||||
assign mcf_ready = mcf_ready_reg;
|
||||
assign tx_pause_ack = tx_pause_ack_reg;
|
||||
assign stat_tx_mcf = stat_tx_mcf_reg;
|
||||
|
||||
integer k;
|
||||
|
||||
always @* begin
|
||||
send_data_next = send_data_reg;
|
||||
send_mcf_next = send_mcf_reg;
|
||||
ptr_next = ptr_reg;
|
||||
|
||||
s_axis_tready_next = 1'b0;
|
||||
mcf_ready_next = 1'b0;
|
||||
tx_pause_ack_next = tx_pause_ack_reg;
|
||||
stat_tx_mcf_next = 1'b0;
|
||||
|
||||
m_axis_tdata_int = 0;
|
||||
m_axis_tkeep_int = 0;
|
||||
m_axis_tvalid_int = 1'b0;
|
||||
m_axis_tlast_int = 1'b0;
|
||||
m_axis_tid_int = 0;
|
||||
m_axis_tdest_int = 0;
|
||||
m_axis_tuser_int = 0;
|
||||
|
||||
if (!send_data_reg && !send_mcf_reg) begin
|
||||
m_axis_tdata_int = s_axis_tdata;
|
||||
m_axis_tkeep_int = s_axis_tkeep;
|
||||
m_axis_tvalid_int = 1'b0;
|
||||
m_axis_tlast_int = s_axis_tlast;
|
||||
m_axis_tid_int = s_axis_tid;
|
||||
m_axis_tdest_int = s_axis_tdest;
|
||||
m_axis_tuser_int = s_axis_tuser;
|
||||
s_axis_tready_next = m_axis_tready_int_early && !tx_pause_req;
|
||||
tx_pause_ack_next = tx_pause_req;
|
||||
if (s_axis_tvalid && s_axis_tready) begin
|
||||
s_axis_tready_next = m_axis_tready_int_early;
|
||||
tx_pause_ack_next = 1'b0;
|
||||
m_axis_tvalid_int = 1'b1;
|
||||
if (s_axis_tlast) begin
|
||||
s_axis_tready_next = m_axis_tready_int_early && !mcf_valid && !mcf_ready;
|
||||
send_data_next = 1'b0;
|
||||
end else begin
|
||||
send_data_next = 1'b1;
|
||||
end
|
||||
end else if (mcf_valid) begin
|
||||
s_axis_tready_next = 1'b0;
|
||||
ptr_next = 0;
|
||||
send_mcf_next = 1'b1;
|
||||
mcf_ready_next = (CYCLE_COUNT == 1) && m_axis_tready_int_early;
|
||||
end
|
||||
end
|
||||
|
||||
if (send_data_reg) begin
|
||||
m_axis_tdata_int = s_axis_tdata;
|
||||
m_axis_tkeep_int = s_axis_tkeep;
|
||||
m_axis_tvalid_int = 1'b0;
|
||||
m_axis_tlast_int = s_axis_tlast;
|
||||
m_axis_tid_int = s_axis_tid;
|
||||
m_axis_tdest_int = s_axis_tdest;
|
||||
m_axis_tuser_int = s_axis_tuser;
|
||||
s_axis_tready_next = m_axis_tready_int_early;
|
||||
if (s_axis_tvalid && s_axis_tready) begin
|
||||
m_axis_tvalid_int = 1'b1;
|
||||
if (s_axis_tlast) begin
|
||||
s_axis_tready_next = m_axis_tready_int_early && !tx_pause_req;
|
||||
send_data_next = 1'b0;
|
||||
if (mcf_valid) begin
|
||||
s_axis_tready_next = 1'b0;
|
||||
ptr_next = 0;
|
||||
send_mcf_next = 1'b1;
|
||||
mcf_ready_next = (CYCLE_COUNT == 1) && m_axis_tready_int_early;
|
||||
end
|
||||
end else begin
|
||||
send_data_next = 1'b1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (send_mcf_reg) begin
|
||||
mcf_ready_next = (CYCLE_COUNT == 1 || ptr_reg == CYCLE_COUNT-1) && m_axis_tready_int_early;
|
||||
if (m_axis_tready_int_reg) begin
|
||||
ptr_next = ptr_reg + 1;
|
||||
|
||||
m_axis_tvalid_int = 1'b1;
|
||||
m_axis_tid_int = mcf_id;
|
||||
m_axis_tdest_int = mcf_dest;
|
||||
m_axis_tuser_int = mcf_user;
|
||||
|
||||
`define _HEADER_FIELD_(offset, field) \
|
||||
if (ptr_reg == offset/BYTE_LANES) begin \
|
||||
m_axis_tdata_int[(offset%BYTE_LANES)*8 +: 8] = field; \
|
||||
m_axis_tkeep_int[offset%BYTE_LANES] = 1'b1; \
|
||||
end
|
||||
|
||||
`_HEADER_FIELD_(0, mcf_eth_dst[5*8 +: 8])
|
||||
`_HEADER_FIELD_(1, mcf_eth_dst[4*8 +: 8])
|
||||
`_HEADER_FIELD_(2, mcf_eth_dst[3*8 +: 8])
|
||||
`_HEADER_FIELD_(3, mcf_eth_dst[2*8 +: 8])
|
||||
`_HEADER_FIELD_(4, mcf_eth_dst[1*8 +: 8])
|
||||
`_HEADER_FIELD_(5, mcf_eth_dst[0*8 +: 8])
|
||||
`_HEADER_FIELD_(6, mcf_eth_src[5*8 +: 8])
|
||||
`_HEADER_FIELD_(7, mcf_eth_src[4*8 +: 8])
|
||||
`_HEADER_FIELD_(8, mcf_eth_src[3*8 +: 8])
|
||||
`_HEADER_FIELD_(9, mcf_eth_src[2*8 +: 8])
|
||||
`_HEADER_FIELD_(10, mcf_eth_src[1*8 +: 8])
|
||||
`_HEADER_FIELD_(11, mcf_eth_src[0*8 +: 8])
|
||||
`_HEADER_FIELD_(12, mcf_eth_type[1*8 +: 8])
|
||||
`_HEADER_FIELD_(13, mcf_eth_type[0*8 +: 8])
|
||||
`_HEADER_FIELD_(14, mcf_opcode[1*8 +: 8])
|
||||
`_HEADER_FIELD_(15, mcf_opcode[0*8 +: 8])
|
||||
|
||||
for (k = 0; k < HDR_SIZE-16; k = k + 1) begin
|
||||
if (ptr_reg == (16+k)/BYTE_LANES) begin
|
||||
if (k < MCF_PARAMS_SIZE) begin
|
||||
m_axis_tdata_int[((16+k)%BYTE_LANES)*8 +: 8] = mcf_params[k*8 +: 8];
|
||||
end else begin
|
||||
m_axis_tdata_int[((16+k)%BYTE_LANES)*8 +: 8] = 0;
|
||||
end
|
||||
m_axis_tkeep_int[(16+k)%BYTE_LANES] = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
if (ptr_reg == (HDR_SIZE-1)/BYTE_LANES) begin
|
||||
s_axis_tready_next = m_axis_tready_int_early && !tx_pause_req;
|
||||
mcf_ready_next = 1'b0;
|
||||
m_axis_tlast_int = 1'b1;
|
||||
send_mcf_next = 1'b0;
|
||||
stat_tx_mcf_next = 1'b1;
|
||||
end else begin
|
||||
mcf_ready_next = (ptr_next == CYCLE_COUNT-1) && m_axis_tready_int_early;
|
||||
end
|
||||
|
||||
`undef _HEADER_FIELD_
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
send_data_reg <= send_data_next;
|
||||
send_mcf_reg <= send_mcf_next;
|
||||
ptr_reg <= ptr_next;
|
||||
|
||||
s_axis_tready_reg <= s_axis_tready_next;
|
||||
mcf_ready_reg <= mcf_ready_next;
|
||||
tx_pause_ack_reg <= tx_pause_ack_next;
|
||||
stat_tx_mcf_reg <= stat_tx_mcf_next;
|
||||
|
||||
if (rst) begin
|
||||
send_data_reg <= 1'b0;
|
||||
send_mcf_reg <= 1'b0;
|
||||
ptr_reg <= 0;
|
||||
s_axis_tready_reg <= 1'b0;
|
||||
mcf_ready_reg <= 1'b0;
|
||||
tx_pause_ack_reg <= 1'b0;
|
||||
stat_tx_mcf_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
// output datapath logic
|
||||
reg [DATA_WIDTH-1:0] m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg m_axis_tvalid_reg = 1'b0, m_axis_tvalid_next;
|
||||
reg m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
reg [DATA_WIDTH-1:0] temp_m_axis_tdata_reg = {DATA_WIDTH{1'b0}};
|
||||
reg [KEEP_WIDTH-1:0] temp_m_axis_tkeep_reg = {KEEP_WIDTH{1'b0}};
|
||||
reg temp_m_axis_tvalid_reg = 1'b0, temp_m_axis_tvalid_next;
|
||||
reg temp_m_axis_tlast_reg = 1'b0;
|
||||
reg [ID_WIDTH-1:0] temp_m_axis_tid_reg = {ID_WIDTH{1'b0}};
|
||||
reg [DEST_WIDTH-1:0] temp_m_axis_tdest_reg = {DEST_WIDTH{1'b0}};
|
||||
reg [USER_WIDTH-1:0] temp_m_axis_tuser_reg = {USER_WIDTH{1'b0}};
|
||||
|
||||
// datapath control
|
||||
reg store_axis_int_to_output;
|
||||
reg store_axis_int_to_temp;
|
||||
reg store_axis_temp_to_output;
|
||||
|
||||
assign m_axis_tdata = m_axis_tdata_reg;
|
||||
assign m_axis_tkeep = KEEP_ENABLE ? m_axis_tkeep_reg : {KEEP_WIDTH{1'b1}};
|
||||
assign m_axis_tvalid = m_axis_tvalid_reg;
|
||||
assign m_axis_tlast = m_axis_tlast_reg;
|
||||
assign m_axis_tid = ID_ENABLE ? m_axis_tid_reg : {ID_WIDTH{1'b0}};
|
||||
assign m_axis_tdest = DEST_ENABLE ? m_axis_tdest_reg : {DEST_WIDTH{1'b0}};
|
||||
assign m_axis_tuser = USER_ENABLE ? m_axis_tuser_reg : {USER_WIDTH{1'b0}};
|
||||
|
||||
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
|
||||
assign m_axis_tready_int_early = m_axis_tready || (!temp_m_axis_tvalid_reg && (!m_axis_tvalid_reg || !m_axis_tvalid_int));
|
||||
|
||||
always @* begin
|
||||
// transfer sink ready state to source
|
||||
m_axis_tvalid_next = m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
|
||||
store_axis_int_to_output = 1'b0;
|
||||
store_axis_int_to_temp = 1'b0;
|
||||
store_axis_temp_to_output = 1'b0;
|
||||
|
||||
if (m_axis_tready_int_reg) begin
|
||||
// input is ready
|
||||
if (m_axis_tready || !m_axis_tvalid_reg) begin
|
||||
// output is ready or currently not valid, transfer data to output
|
||||
m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_output = 1'b1;
|
||||
end else begin
|
||||
// output is not ready, store input in temp
|
||||
temp_m_axis_tvalid_next = m_axis_tvalid_int;
|
||||
store_axis_int_to_temp = 1'b1;
|
||||
end
|
||||
end else if (m_axis_tready) begin
|
||||
// input is not ready, but output is ready
|
||||
m_axis_tvalid_next = temp_m_axis_tvalid_reg;
|
||||
temp_m_axis_tvalid_next = 1'b0;
|
||||
store_axis_temp_to_output = 1'b1;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
m_axis_tvalid_reg <= m_axis_tvalid_next;
|
||||
m_axis_tready_int_reg <= m_axis_tready_int_early;
|
||||
temp_m_axis_tvalid_reg <= temp_m_axis_tvalid_next;
|
||||
|
||||
// datapath
|
||||
if (store_axis_int_to_output) begin
|
||||
m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
m_axis_tid_reg <= m_axis_tid_int;
|
||||
m_axis_tdest_reg <= m_axis_tdest_int;
|
||||
m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end else if (store_axis_temp_to_output) begin
|
||||
m_axis_tdata_reg <= temp_m_axis_tdata_reg;
|
||||
m_axis_tkeep_reg <= temp_m_axis_tkeep_reg;
|
||||
m_axis_tlast_reg <= temp_m_axis_tlast_reg;
|
||||
m_axis_tid_reg <= temp_m_axis_tid_reg;
|
||||
m_axis_tdest_reg <= temp_m_axis_tdest_reg;
|
||||
m_axis_tuser_reg <= temp_m_axis_tuser_reg;
|
||||
end
|
||||
|
||||
if (store_axis_int_to_temp) begin
|
||||
temp_m_axis_tdata_reg <= m_axis_tdata_int;
|
||||
temp_m_axis_tkeep_reg <= m_axis_tkeep_int;
|
||||
temp_m_axis_tlast_reg <= m_axis_tlast_int;
|
||||
temp_m_axis_tid_reg <= m_axis_tid_int;
|
||||
temp_m_axis_tdest_reg <= m_axis_tdest_int;
|
||||
temp_m_axis_tuser_reg <= m_axis_tuser_int;
|
||||
end
|
||||
|
||||
if (rst) begin
|
||||
m_axis_tvalid_reg <= 1'b0;
|
||||
m_axis_tready_int_reg <= 1'b0;
|
||||
temp_m_axis_tvalid_reg <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,220 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* PFC and pause frame receive handling
|
||||
*/
|
||||
module mac_pause_ctrl_rx #
|
||||
(
|
||||
parameter MCF_PARAMS_SIZE = 18,
|
||||
parameter PFC_ENABLE = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
input wire mcf_valid,
|
||||
input wire [47:0] mcf_eth_dst,
|
||||
input wire [47:0] mcf_eth_src,
|
||||
input wire [15:0] mcf_eth_type,
|
||||
input wire [15:0] mcf_opcode,
|
||||
input wire [MCF_PARAMS_SIZE*8-1:0] mcf_params,
|
||||
|
||||
/*
|
||||
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
|
||||
*/
|
||||
input wire rx_lfc_en,
|
||||
output wire rx_lfc_req,
|
||||
input wire rx_lfc_ack,
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D PFC)
|
||||
*/
|
||||
input wire [7:0] rx_pfc_en,
|
||||
output wire [7:0] rx_pfc_req,
|
||||
input wire [7:0] rx_pfc_ack,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [15:0] cfg_rx_lfc_opcode,
|
||||
input wire cfg_rx_lfc_en,
|
||||
input wire [15:0] cfg_rx_pfc_opcode,
|
||||
input wire cfg_rx_pfc_en,
|
||||
input wire [9:0] cfg_quanta_step,
|
||||
input wire cfg_quanta_clk_en,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire stat_rx_lfc_pkt,
|
||||
output wire stat_rx_lfc_xon,
|
||||
output wire stat_rx_lfc_xoff,
|
||||
output wire stat_rx_lfc_paused,
|
||||
output wire stat_rx_pfc_pkt,
|
||||
output wire [7:0] stat_rx_pfc_xon,
|
||||
output wire [7:0] stat_rx_pfc_xoff,
|
||||
output wire [7:0] stat_rx_pfc_paused
|
||||
);
|
||||
|
||||
localparam QFB = 8;
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (MCF_PARAMS_SIZE < (PFC_ENABLE ? 18 : 2)) begin
|
||||
$error("Error: MCF_PARAMS_SIZE too small for requested configuration (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
reg lfc_req_reg = 1'b0, lfc_req_next;
|
||||
reg [7:0] pfc_req_reg = 8'd0, pfc_req_next;
|
||||
|
||||
reg [16+QFB-1:0] lfc_quanta_reg = 0, lfc_quanta_next;
|
||||
reg [16+QFB-1:0] pfc_quanta_reg[0:7], pfc_quanta_next[0:7];
|
||||
|
||||
reg stat_rx_lfc_pkt_reg = 1'b0, stat_rx_lfc_pkt_next;
|
||||
reg stat_rx_lfc_xon_reg = 1'b0, stat_rx_lfc_xon_next;
|
||||
reg stat_rx_lfc_xoff_reg = 1'b0, stat_rx_lfc_xoff_next;
|
||||
reg stat_rx_pfc_pkt_reg = 1'b0, stat_rx_pfc_pkt_next;
|
||||
reg [7:0] stat_rx_pfc_xon_reg = 0, stat_rx_pfc_xon_next;
|
||||
reg [7:0] stat_rx_pfc_xoff_reg = 0, stat_rx_pfc_xoff_next;
|
||||
|
||||
assign rx_lfc_req = lfc_req_reg;
|
||||
assign rx_pfc_req = pfc_req_reg;
|
||||
|
||||
assign stat_rx_lfc_pkt = stat_rx_lfc_pkt_reg;
|
||||
assign stat_rx_lfc_xon = stat_rx_lfc_xon_reg;
|
||||
assign stat_rx_lfc_xoff = stat_rx_lfc_xoff_reg;
|
||||
assign stat_rx_lfc_paused = lfc_req_reg;
|
||||
assign stat_rx_pfc_pkt = stat_rx_pfc_pkt_reg;
|
||||
assign stat_rx_pfc_xon = stat_rx_pfc_xon_reg;
|
||||
assign stat_rx_pfc_xoff = stat_rx_pfc_xoff_reg;
|
||||
assign stat_rx_pfc_paused = pfc_req_reg;
|
||||
|
||||
integer k;
|
||||
|
||||
initial begin
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_quanta_reg[k] = 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @* begin
|
||||
stat_rx_lfc_pkt_next = 1'b0;
|
||||
stat_rx_lfc_xon_next = 1'b0;
|
||||
stat_rx_lfc_xoff_next = 1'b0;
|
||||
stat_rx_pfc_pkt_next = 1'b0;
|
||||
stat_rx_pfc_xon_next = 0;
|
||||
stat_rx_pfc_xoff_next = 0;
|
||||
|
||||
if (cfg_quanta_clk_en && rx_lfc_ack) begin
|
||||
if (lfc_quanta_reg > cfg_quanta_step) begin
|
||||
lfc_quanta_next = lfc_quanta_reg - cfg_quanta_step;
|
||||
end else begin
|
||||
lfc_quanta_next = 0;
|
||||
end
|
||||
end else begin
|
||||
lfc_quanta_next = lfc_quanta_reg;
|
||||
end
|
||||
|
||||
lfc_req_next = (lfc_quanta_reg != 0) && rx_lfc_en && cfg_rx_lfc_en;
|
||||
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
if (cfg_quanta_clk_en && rx_pfc_ack[k]) begin
|
||||
if (pfc_quanta_reg[k] > cfg_quanta_step) begin
|
||||
pfc_quanta_next[k] = pfc_quanta_reg[k] - cfg_quanta_step;
|
||||
end else begin
|
||||
pfc_quanta_next[k] = 0;
|
||||
end
|
||||
end else begin
|
||||
pfc_quanta_next[k] = pfc_quanta_reg[k];
|
||||
end
|
||||
|
||||
pfc_req_next[k] = (pfc_quanta_reg[k] != 0) && rx_pfc_en[k] && cfg_rx_pfc_en;
|
||||
end
|
||||
|
||||
if (mcf_valid) begin
|
||||
if (mcf_opcode == cfg_rx_lfc_opcode && cfg_rx_lfc_en) begin
|
||||
stat_rx_lfc_pkt_next = 1'b1;
|
||||
stat_rx_lfc_xon_next = {mcf_params[7:0], mcf_params[15:8]} == 0;
|
||||
stat_rx_lfc_xoff_next = {mcf_params[7:0], mcf_params[15:8]} != 0;
|
||||
lfc_quanta_next = {mcf_params[7:0], mcf_params[15:8], {QFB{1'b0}}};
|
||||
end else if (PFC_ENABLE && mcf_opcode == cfg_rx_pfc_opcode && cfg_rx_pfc_en) begin
|
||||
stat_rx_pfc_pkt_next = 1'b1;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
if (mcf_params[k+8]) begin
|
||||
stat_rx_pfc_xon_next[k] = {mcf_params[16+(k*16)+0 +: 8], mcf_params[16+(k*16)+8 +: 8]} == 0;
|
||||
stat_rx_pfc_xoff_next[k] = {mcf_params[16+(k*16)+0 +: 8], mcf_params[16+(k*16)+8 +: 8]} != 0;
|
||||
pfc_quanta_next[k] = {mcf_params[16+(k*16)+0 +: 8], mcf_params[16+(k*16)+8 +: 8], {QFB{1'b0}}};
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
lfc_req_reg <= lfc_req_next;
|
||||
pfc_req_reg <= pfc_req_next;
|
||||
|
||||
lfc_quanta_reg <= lfc_quanta_next;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_quanta_reg[k] <= pfc_quanta_next[k];
|
||||
end
|
||||
|
||||
stat_rx_lfc_pkt_reg <= stat_rx_lfc_pkt_next;
|
||||
stat_rx_lfc_xon_reg <= stat_rx_lfc_xon_next;
|
||||
stat_rx_lfc_xoff_reg <= stat_rx_lfc_xoff_next;
|
||||
stat_rx_pfc_pkt_reg <= stat_rx_pfc_pkt_next;
|
||||
stat_rx_pfc_xon_reg <= stat_rx_pfc_xon_next;
|
||||
stat_rx_pfc_xoff_reg <= stat_rx_pfc_xoff_next;
|
||||
|
||||
if (rst) begin
|
||||
lfc_req_reg <= 1'b0;
|
||||
pfc_req_reg <= 8'd0;
|
||||
lfc_quanta_reg <= 0;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_quanta_reg[k] <= 0;
|
||||
end
|
||||
|
||||
stat_rx_lfc_pkt_reg <= 1'b0;
|
||||
stat_rx_lfc_xon_reg <= 1'b0;
|
||||
stat_rx_lfc_xoff_reg <= 1'b0;
|
||||
stat_rx_pfc_pkt_reg <= 1'b0;
|
||||
stat_rx_pfc_xon_reg <= 0;
|
||||
stat_rx_pfc_xoff_reg <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,312 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2023 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* PFC and pause frame transmit handling
|
||||
*/
|
||||
module mac_pause_ctrl_tx #
|
||||
(
|
||||
parameter MCF_PARAMS_SIZE = 18,
|
||||
parameter PFC_ENABLE = 1
|
||||
)
|
||||
(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* MAC control frame interface
|
||||
*/
|
||||
output wire mcf_valid,
|
||||
input wire mcf_ready,
|
||||
output wire [47:0] mcf_eth_dst,
|
||||
output wire [47:0] mcf_eth_src,
|
||||
output wire [15:0] mcf_eth_type,
|
||||
output wire [15:0] mcf_opcode,
|
||||
output wire [MCF_PARAMS_SIZE*8-1:0] mcf_params,
|
||||
|
||||
/*
|
||||
* Link-level Flow Control (LFC) (IEEE 802.3 annex 31B PAUSE)
|
||||
*/
|
||||
input wire tx_lfc_req,
|
||||
input wire tx_lfc_resend,
|
||||
|
||||
/*
|
||||
* Priority Flow Control (PFC) (IEEE 802.3 annex 31D)
|
||||
*/
|
||||
input wire [7:0] tx_pfc_req,
|
||||
input wire tx_pfc_resend,
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
input wire [47:0] cfg_tx_lfc_eth_dst,
|
||||
input wire [47:0] cfg_tx_lfc_eth_src,
|
||||
input wire [15:0] cfg_tx_lfc_eth_type,
|
||||
input wire [15:0] cfg_tx_lfc_opcode,
|
||||
input wire cfg_tx_lfc_en,
|
||||
input wire [15:0] cfg_tx_lfc_quanta,
|
||||
input wire [15:0] cfg_tx_lfc_refresh,
|
||||
input wire [47:0] cfg_tx_pfc_eth_dst,
|
||||
input wire [47:0] cfg_tx_pfc_eth_src,
|
||||
input wire [15:0] cfg_tx_pfc_eth_type,
|
||||
input wire [15:0] cfg_tx_pfc_opcode,
|
||||
input wire cfg_tx_pfc_en,
|
||||
input wire [8*16-1:0] cfg_tx_pfc_quanta,
|
||||
input wire [8*16-1:0] cfg_tx_pfc_refresh,
|
||||
input wire [9:0] cfg_quanta_step,
|
||||
input wire cfg_quanta_clk_en,
|
||||
|
||||
/*
|
||||
* Status
|
||||
*/
|
||||
output wire stat_tx_lfc_pkt,
|
||||
output wire stat_tx_lfc_xon,
|
||||
output wire stat_tx_lfc_xoff,
|
||||
output wire stat_tx_lfc_paused,
|
||||
output wire stat_tx_pfc_pkt,
|
||||
output wire [7:0] stat_tx_pfc_xon,
|
||||
output wire [7:0] stat_tx_pfc_xoff,
|
||||
output wire [7:0] stat_tx_pfc_paused
|
||||
);
|
||||
|
||||
localparam QFB = 8;
|
||||
|
||||
// check configuration
|
||||
initial begin
|
||||
if (MCF_PARAMS_SIZE < (PFC_ENABLE ? 18 : 2)) begin
|
||||
$error("Error: MCF_PARAMS_SIZE too small for requested configuration (instance %m)");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
reg lfc_req_reg = 1'b0, lfc_req_next;
|
||||
reg lfc_act_reg = 1'b0, lfc_act_next;
|
||||
reg lfc_send_reg = 1'b0, lfc_send_next;
|
||||
reg [7:0] pfc_req_reg = 8'd0, pfc_req_next;
|
||||
reg [7:0] pfc_act_reg = 8'd0, pfc_act_next;
|
||||
reg [7:0] pfc_en_reg = 8'd0, pfc_en_next;
|
||||
reg pfc_send_reg = 1'b0, pfc_send_next;
|
||||
|
||||
reg [16+QFB-1:0] lfc_refresh_reg = 0, lfc_refresh_next;
|
||||
reg [16+QFB-1:0] pfc_refresh_reg[0:7], pfc_refresh_next[0:7];
|
||||
|
||||
reg stat_tx_lfc_pkt_reg = 1'b0, stat_tx_lfc_pkt_next;
|
||||
reg stat_tx_lfc_xon_reg = 1'b0, stat_tx_lfc_xon_next;
|
||||
reg stat_tx_lfc_xoff_reg = 1'b0, stat_tx_lfc_xoff_next;
|
||||
reg stat_tx_pfc_pkt_reg = 1'b0, stat_tx_pfc_pkt_next;
|
||||
reg [7:0] stat_tx_pfc_xon_reg = 0, stat_tx_pfc_xon_next;
|
||||
reg [7:0] stat_tx_pfc_xoff_reg = 0, stat_tx_pfc_xoff_next;
|
||||
|
||||
// MAC control interface
|
||||
reg mcf_pfc_sel_reg = PFC_ENABLE != 0, mcf_pfc_sel_next;
|
||||
reg mcf_valid_reg = 1'b0, mcf_valid_next;
|
||||
|
||||
wire [2*8-1:0] mcf_lfc_params;
|
||||
assign mcf_lfc_params[16*0 +: 16] = lfc_req_reg ? {cfg_tx_lfc_quanta[0 +: 8], cfg_tx_lfc_quanta[8 +: 8]} : 0;
|
||||
|
||||
wire [18*8-1:0] mcf_pfc_params;
|
||||
assign mcf_pfc_params[16*0 +: 16] = {pfc_en_reg, 8'd0};
|
||||
assign mcf_pfc_params[16*1 +: 16] = pfc_req_reg[0] ? {cfg_tx_pfc_quanta[16*0+0 +: 8], cfg_tx_pfc_quanta[16*0+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*2 +: 16] = pfc_req_reg[1] ? {cfg_tx_pfc_quanta[16*1+0 +: 8], cfg_tx_pfc_quanta[16*1+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*3 +: 16] = pfc_req_reg[2] ? {cfg_tx_pfc_quanta[16*2+0 +: 8], cfg_tx_pfc_quanta[16*2+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*4 +: 16] = pfc_req_reg[3] ? {cfg_tx_pfc_quanta[16*3+0 +: 8], cfg_tx_pfc_quanta[16*3+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*5 +: 16] = pfc_req_reg[4] ? {cfg_tx_pfc_quanta[16*4+0 +: 8], cfg_tx_pfc_quanta[16*4+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*6 +: 16] = pfc_req_reg[5] ? {cfg_tx_pfc_quanta[16*5+0 +: 8], cfg_tx_pfc_quanta[16*5+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*7 +: 16] = pfc_req_reg[6] ? {cfg_tx_pfc_quanta[16*6+0 +: 8], cfg_tx_pfc_quanta[16*6+8 +: 8]} : 0;
|
||||
assign mcf_pfc_params[16*8 +: 16] = pfc_req_reg[7] ? {cfg_tx_pfc_quanta[16*7+0 +: 8], cfg_tx_pfc_quanta[16*7+8 +: 8]} : 0;
|
||||
|
||||
assign mcf_valid = mcf_valid_reg;
|
||||
assign mcf_eth_dst = (PFC_ENABLE && mcf_pfc_sel_reg) ? cfg_tx_pfc_eth_dst : cfg_tx_lfc_eth_dst;
|
||||
assign mcf_eth_src = (PFC_ENABLE && mcf_pfc_sel_reg) ? cfg_tx_pfc_eth_src : cfg_tx_lfc_eth_src;
|
||||
assign mcf_eth_type = (PFC_ENABLE && mcf_pfc_sel_reg) ? cfg_tx_pfc_eth_type : cfg_tx_lfc_eth_type;
|
||||
assign mcf_opcode = (PFC_ENABLE && mcf_pfc_sel_reg) ? cfg_tx_pfc_opcode : cfg_tx_lfc_opcode;
|
||||
assign mcf_params = (PFC_ENABLE && mcf_pfc_sel_reg) ? mcf_pfc_params : mcf_lfc_params;
|
||||
|
||||
assign stat_tx_lfc_pkt = stat_tx_lfc_pkt_reg;
|
||||
assign stat_tx_lfc_xon = stat_tx_lfc_xon_reg;
|
||||
assign stat_tx_lfc_xoff = stat_tx_lfc_xoff_reg;
|
||||
assign stat_tx_lfc_paused = lfc_req_reg;
|
||||
assign stat_tx_pfc_pkt = stat_tx_pfc_pkt_reg;
|
||||
assign stat_tx_pfc_xon = stat_tx_pfc_xon_reg;
|
||||
assign stat_tx_pfc_xoff = stat_tx_pfc_xoff_reg;
|
||||
assign stat_tx_pfc_paused = pfc_req_reg;
|
||||
|
||||
integer k;
|
||||
|
||||
initial begin
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_refresh_reg[k] = 0;
|
||||
end
|
||||
end
|
||||
|
||||
always @* begin
|
||||
lfc_req_next = lfc_req_reg;
|
||||
lfc_act_next = lfc_act_reg;
|
||||
lfc_send_next = lfc_send_reg | tx_lfc_resend;
|
||||
pfc_req_next = pfc_req_reg;
|
||||
pfc_act_next = pfc_act_reg;
|
||||
pfc_en_next = pfc_en_reg;
|
||||
pfc_send_next = pfc_send_reg | tx_pfc_resend;
|
||||
|
||||
mcf_pfc_sel_next = mcf_pfc_sel_reg;
|
||||
mcf_valid_next = mcf_valid_reg && !mcf_ready;
|
||||
|
||||
stat_tx_lfc_pkt_next = 1'b0;
|
||||
stat_tx_lfc_xon_next = 1'b0;
|
||||
stat_tx_lfc_xoff_next = 1'b0;
|
||||
stat_tx_pfc_pkt_next = 1'b0;
|
||||
stat_tx_pfc_xon_next = 0;
|
||||
stat_tx_pfc_xoff_next = 0;
|
||||
|
||||
if (cfg_quanta_clk_en) begin
|
||||
if (lfc_refresh_reg > cfg_quanta_step) begin
|
||||
lfc_refresh_next = lfc_refresh_reg - cfg_quanta_step;
|
||||
end else begin
|
||||
lfc_refresh_next = 0;
|
||||
if (lfc_req_reg) begin
|
||||
lfc_send_next = 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
lfc_refresh_next = lfc_refresh_reg;
|
||||
end
|
||||
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
if (cfg_quanta_clk_en) begin
|
||||
if (pfc_refresh_reg[k] > cfg_quanta_step) begin
|
||||
pfc_refresh_next[k] = pfc_refresh_reg[k] - cfg_quanta_step;
|
||||
end else begin
|
||||
pfc_refresh_next[k] = 0;
|
||||
if (pfc_req_reg[k]) begin
|
||||
pfc_send_next = 1'b1;
|
||||
end
|
||||
end
|
||||
end else begin
|
||||
pfc_refresh_next[k] = pfc_refresh_reg[k];
|
||||
end
|
||||
end
|
||||
|
||||
if (cfg_tx_lfc_en) begin
|
||||
if (!mcf_valid_reg) begin
|
||||
if (lfc_req_reg != tx_lfc_req) begin
|
||||
lfc_req_next = tx_lfc_req;
|
||||
lfc_act_next = lfc_act_reg | tx_lfc_req;
|
||||
lfc_send_next = 1'b1;
|
||||
end
|
||||
|
||||
if (lfc_send_reg && !(PFC_ENABLE && cfg_tx_pfc_en && pfc_send_reg)) begin
|
||||
mcf_pfc_sel_next = 1'b0;
|
||||
mcf_valid_next = lfc_act_reg;
|
||||
lfc_act_next = lfc_req_reg;
|
||||
lfc_refresh_next = lfc_req_reg ? {cfg_tx_lfc_refresh, {QFB{1'b0}}} : 0;
|
||||
lfc_send_next = 1'b0;
|
||||
|
||||
stat_tx_lfc_pkt_next = lfc_act_reg;
|
||||
stat_tx_lfc_xon_next = lfc_act_reg && !lfc_req_reg;
|
||||
stat_tx_lfc_xoff_next = lfc_act_reg && lfc_req_reg;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if (PFC_ENABLE && cfg_tx_pfc_en) begin
|
||||
if (!mcf_valid_reg) begin
|
||||
if (pfc_req_reg != tx_pfc_req) begin
|
||||
pfc_req_next = tx_pfc_req;
|
||||
pfc_act_next = pfc_act_reg | tx_pfc_req;
|
||||
pfc_send_next = 1'b1;
|
||||
end
|
||||
|
||||
if (pfc_send_reg) begin
|
||||
mcf_pfc_sel_next = 1'b1;
|
||||
mcf_valid_next = pfc_act_reg != 0;
|
||||
pfc_en_next = pfc_act_reg;
|
||||
pfc_act_next = pfc_req_reg;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_refresh_next[k] = pfc_req_reg[k] ? {cfg_tx_pfc_refresh[16*k +: 16], {QFB{1'b0}}} : 0;
|
||||
end
|
||||
pfc_send_next = 1'b0;
|
||||
|
||||
stat_tx_pfc_pkt_next = pfc_act_reg != 0;
|
||||
stat_tx_pfc_xon_next = pfc_act_reg & ~pfc_req_reg;
|
||||
stat_tx_pfc_xoff_next = pfc_act_reg & pfc_req_reg;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
lfc_req_reg <= lfc_req_next;
|
||||
lfc_act_reg <= lfc_act_next;
|
||||
lfc_send_reg <= lfc_send_next;
|
||||
pfc_req_reg <= pfc_req_next;
|
||||
pfc_act_reg <= pfc_act_next;
|
||||
pfc_en_reg <= pfc_en_next;
|
||||
pfc_send_reg <= pfc_send_next;
|
||||
|
||||
mcf_pfc_sel_reg <= mcf_pfc_sel_next;
|
||||
mcf_valid_reg <= mcf_valid_next;
|
||||
|
||||
lfc_refresh_reg <= lfc_refresh_next;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_refresh_reg[k] <= pfc_refresh_next[k];
|
||||
end
|
||||
|
||||
stat_tx_lfc_pkt_reg <= stat_tx_lfc_pkt_next;
|
||||
stat_tx_lfc_xon_reg <= stat_tx_lfc_xon_next;
|
||||
stat_tx_lfc_xoff_reg <= stat_tx_lfc_xoff_next;
|
||||
stat_tx_pfc_pkt_reg <= stat_tx_pfc_pkt_next;
|
||||
stat_tx_pfc_xon_reg <= stat_tx_pfc_xon_next;
|
||||
stat_tx_pfc_xoff_reg <= stat_tx_pfc_xoff_next;
|
||||
|
||||
if (rst) begin
|
||||
lfc_req_reg <= 1'b0;
|
||||
lfc_act_reg <= 1'b0;
|
||||
lfc_send_reg <= 1'b0;
|
||||
pfc_req_reg <= 0;
|
||||
pfc_act_reg <= 0;
|
||||
pfc_send_reg <= 0;
|
||||
mcf_pfc_sel_reg <= PFC_ENABLE != 0;
|
||||
mcf_valid_reg <= 1'b0;
|
||||
lfc_refresh_reg <= 0;
|
||||
for (k = 0; k < 8; k = k + 1) begin
|
||||
pfc_refresh_reg[k] <= 0;
|
||||
end
|
||||
|
||||
stat_tx_lfc_pkt_reg <= 1'b0;
|
||||
stat_tx_lfc_xon_reg <= 1'b0;
|
||||
stat_tx_lfc_xoff_reg <= 1'b0;
|
||||
stat_tx_pfc_pkt_reg <= 1'b0;
|
||||
stat_tx_pfc_xon_reg <= 0;
|
||||
stat_tx_pfc_xoff_reg <= 0;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2019 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* MII PHY interface
|
||||
*/
|
||||
module mii_phy_if #
|
||||
(
|
||||
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
|
||||
parameter TARGET = "GENERIC",
|
||||
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
|
||||
// Use BUFR for Virtex-5, Virtex-6, 7-series
|
||||
// Use BUFG for Ultrascale
|
||||
// Use BUFIO2 for Spartan-6
|
||||
parameter CLOCK_INPUT_STYLE = "BUFIO2"
|
||||
)
|
||||
(
|
||||
input wire rst,
|
||||
|
||||
/*
|
||||
* MII interface to MAC
|
||||
*/
|
||||
output wire mac_mii_rx_clk,
|
||||
output wire mac_mii_rx_rst,
|
||||
output wire [3:0] mac_mii_rxd,
|
||||
output wire mac_mii_rx_dv,
|
||||
output wire mac_mii_rx_er,
|
||||
output wire mac_mii_tx_clk,
|
||||
output wire mac_mii_tx_rst,
|
||||
(* mark_debug = "true" *) input wire [3:0] mac_mii_txd,
|
||||
(* mark_debug = "true" *) input wire mac_mii_tx_en,
|
||||
input wire mac_mii_tx_er,
|
||||
|
||||
/*
|
||||
* MII interface to PHY
|
||||
*/
|
||||
input wire phy_mii_rx_clk,
|
||||
input wire [3:0] phy_mii_rxd,
|
||||
input wire phy_mii_rx_dv,
|
||||
input wire phy_mii_rx_er,
|
||||
input wire phy_mii_tx_clk,
|
||||
output wire [3:0] phy_mii_txd,
|
||||
output wire phy_mii_tx_en,
|
||||
output wire phy_mii_tx_er
|
||||
);
|
||||
|
||||
ssio_sdr_in #
|
||||
(
|
||||
.TARGET(TARGET),
|
||||
.CLOCK_INPUT_STYLE(CLOCK_INPUT_STYLE),
|
||||
.WIDTH(6)
|
||||
)
|
||||
rx_ssio_sdr_inst (
|
||||
.input_clk(phy_mii_rx_clk),
|
||||
.input_d({phy_mii_rxd, phy_mii_rx_dv, phy_mii_rx_er}),
|
||||
.output_clk(mac_mii_rx_clk),
|
||||
.output_q({mac_mii_rxd, mac_mii_rx_dv, mac_mii_rx_er})
|
||||
);
|
||||
|
||||
(* IOB = "TRUE" *)
|
||||
reg [3:0] phy_mii_txd_reg = 4'd0;
|
||||
(* IOB = "TRUE" *)
|
||||
reg phy_mii_tx_en_reg = 1'b0, phy_mii_tx_er_reg = 1'b0;
|
||||
|
||||
assign phy_mii_txd = phy_mii_txd_reg;
|
||||
assign phy_mii_tx_en = phy_mii_tx_en_reg;
|
||||
assign phy_mii_tx_er = phy_mii_tx_er_reg;
|
||||
|
||||
always @(posedge mac_mii_tx_clk) begin
|
||||
phy_mii_txd_reg <= mac_mii_txd;
|
||||
phy_mii_tx_en_reg <= mac_mii_tx_en;
|
||||
phy_mii_tx_er_reg <= mac_mii_tx_er;
|
||||
end
|
||||
|
||||
generate
|
||||
|
||||
if (TARGET == "XILINX") begin
|
||||
BUFG
|
||||
mii_bufg_inst (
|
||||
.I(phy_mii_tx_clk),
|
||||
.O(mac_mii_tx_clk)
|
||||
);
|
||||
end else begin
|
||||
assign mac_mii_tx_clk = phy_mii_tx_clk;
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
// reset sync
|
||||
reg [3:0] tx_rst_reg = 4'hf;
|
||||
assign mac_mii_tx_rst = tx_rst_reg[0];
|
||||
|
||||
always @(posedge mac_mii_tx_clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
tx_rst_reg <= 4'hf;
|
||||
end else begin
|
||||
tx_rst_reg <= {1'b0, tx_rst_reg[3:1]};
|
||||
end
|
||||
end
|
||||
|
||||
reg [3:0] rx_rst_reg = 4'hf;
|
||||
assign mac_mii_rx_rst = rx_rst_reg[0];
|
||||
|
||||
always @(posedge mac_mii_rx_clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
rx_rst_reg <= 4'hf;
|
||||
end else begin
|
||||
rx_rst_reg <= {1'b0, rx_rst_reg[3:1]};
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,150 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016-2018 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* Generic source synchronous DDR input
|
||||
*/
|
||||
module ssio_ddr_in #
|
||||
(
|
||||
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
|
||||
parameter TARGET = "GENERIC",
|
||||
// IODDR style ("IODDR", "IODDR2")
|
||||
// Use IODDR for Virtex-4, Virtex-5, Virtex-6, 7 Series, Ultrascale
|
||||
// Use IODDR2 for Spartan-6
|
||||
parameter IODDR_STYLE = "IODDR2",
|
||||
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
|
||||
// Use BUFR for Virtex-6, 7-series
|
||||
// Use BUFG for Virtex-5, Spartan-6, Ultrascale
|
||||
parameter CLOCK_INPUT_STYLE = "BUFG",
|
||||
// Width of register in bits
|
||||
parameter WIDTH = 1
|
||||
)
|
||||
(
|
||||
input wire input_clk,
|
||||
|
||||
input wire [WIDTH-1:0] input_d,
|
||||
|
||||
output wire output_clk,
|
||||
|
||||
output wire [WIDTH-1:0] output_q1,
|
||||
output wire [WIDTH-1:0] output_q2
|
||||
);
|
||||
|
||||
wire clk_int;
|
||||
wire clk_io;
|
||||
|
||||
generate
|
||||
|
||||
if (TARGET == "XILINX") begin
|
||||
|
||||
// use Xilinx clocking primitives
|
||||
|
||||
if (CLOCK_INPUT_STYLE == "BUFG") begin
|
||||
|
||||
// buffer RX clock
|
||||
BUFG
|
||||
clk_bufg (
|
||||
.I(input_clk),
|
||||
.O(clk_int)
|
||||
);
|
||||
|
||||
// pass through RX clock to logic and input buffers
|
||||
assign clk_io = clk_int;
|
||||
assign output_clk = clk_int;
|
||||
|
||||
end else if (CLOCK_INPUT_STYLE == "BUFR") begin
|
||||
|
||||
assign clk_int = input_clk;
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
BUFIO
|
||||
clk_bufio (
|
||||
.I(clk_int),
|
||||
.O(clk_io)
|
||||
);
|
||||
|
||||
// pass through RX clock to logic
|
||||
BUFR #(
|
||||
.BUFR_DIVIDE("BYPASS")
|
||||
)
|
||||
clk_bufr (
|
||||
.I(clk_int),
|
||||
.O(output_clk),
|
||||
.CE(1'b1),
|
||||
.CLR(1'b0)
|
||||
);
|
||||
|
||||
end else if (CLOCK_INPUT_STYLE == "BUFIO") begin
|
||||
|
||||
assign clk_int = input_clk;
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
BUFIO
|
||||
clk_bufio (
|
||||
.I(clk_int),
|
||||
.O(clk_io)
|
||||
);
|
||||
|
||||
// pass through RX clock to MAC
|
||||
BUFG
|
||||
clk_bufg (
|
||||
.I(clk_int),
|
||||
.O(output_clk)
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
assign clk_io = input_clk;
|
||||
|
||||
// pass through RX clock to logic
|
||||
assign clk_int = input_clk;
|
||||
assign output_clk = clk_int;
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
iddr #(
|
||||
.TARGET(TARGET),
|
||||
.IODDR_STYLE(IODDR_STYLE),
|
||||
.WIDTH(WIDTH)
|
||||
)
|
||||
data_iddr_inst (
|
||||
.clk(clk_io),
|
||||
.d(input_d),
|
||||
.q1(output_q1),
|
||||
.q2(output_q2)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
|
@ -1,166 +0,0 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016-2018 Alex Forencich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
// Language: Verilog 2001
|
||||
|
||||
`resetall
|
||||
`default_nettype none
|
||||
|
||||
/*
|
||||
* Generic source synchronous SDR input
|
||||
*/
|
||||
module ssio_sdr_in #
|
||||
(
|
||||
// target ("SIM", "GENERIC", "XILINX", "ALTERA")
|
||||
parameter TARGET = "GENERIC",
|
||||
// Clock input style ("BUFG", "BUFR", "BUFIO", "BUFIO2")
|
||||
// Use BUFR for Virtex-5, Virtex-6, 7-series
|
||||
// Use BUFG for Ultrascale
|
||||
// Use BUFIO2 for Spartan-6
|
||||
parameter CLOCK_INPUT_STYLE = "BUFIO2",
|
||||
// Width of register in bits
|
||||
parameter WIDTH = 1
|
||||
)
|
||||
(
|
||||
input wire input_clk,
|
||||
|
||||
input wire [WIDTH-1:0] input_d,
|
||||
|
||||
output wire output_clk,
|
||||
|
||||
output wire [WIDTH-1:0] output_q
|
||||
);
|
||||
|
||||
wire clk_int;
|
||||
wire clk_io;
|
||||
|
||||
generate
|
||||
|
||||
if (TARGET == "XILINX") begin
|
||||
|
||||
// use Xilinx clocking primitives
|
||||
|
||||
if (CLOCK_INPUT_STYLE == "BUFG") begin
|
||||
|
||||
// buffer RX clock
|
||||
BUFG
|
||||
clk_bufg (
|
||||
.I(input_clk),
|
||||
.O(clk_int)
|
||||
);
|
||||
|
||||
// pass through RX clock to logic and input buffers
|
||||
assign clk_io = clk_int;
|
||||
assign output_clk = clk_int;
|
||||
|
||||
end else if (CLOCK_INPUT_STYLE == "BUFR") begin
|
||||
|
||||
assign clk_int = input_clk;
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
BUFIO
|
||||
clk_bufio (
|
||||
.I(clk_int),
|
||||
.O(clk_io)
|
||||
);
|
||||
|
||||
// pass through RX clock to logic
|
||||
BUFR #(
|
||||
.BUFR_DIVIDE("BYPASS")
|
||||
)
|
||||
clk_bufr (
|
||||
.I(clk_int),
|
||||
.O(output_clk),
|
||||
.CE(1'b1),
|
||||
.CLR(1'b0)
|
||||
);
|
||||
|
||||
end else if (CLOCK_INPUT_STYLE == "BUFIO") begin
|
||||
|
||||
assign clk_int = input_clk;
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
BUFIO
|
||||
clk_bufio (
|
||||
.I(clk_int),
|
||||
.O(clk_io)
|
||||
);
|
||||
|
||||
// pass through RX clock to MAC
|
||||
BUFG
|
||||
clk_bufg (
|
||||
.I(clk_int),
|
||||
.O(output_clk)
|
||||
);
|
||||
|
||||
end else if (CLOCK_INPUT_STYLE == "BUFIO2") begin
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
BUFIO2 #(
|
||||
.DIVIDE(1),
|
||||
.DIVIDE_BYPASS("TRUE"),
|
||||
.I_INVERT("FALSE"),
|
||||
.USE_DOUBLER("FALSE")
|
||||
)
|
||||
clk_bufio (
|
||||
.I(input_clk),
|
||||
.DIVCLK(clk_int),
|
||||
.IOCLK(clk_io),
|
||||
.SERDESSTROBE()
|
||||
);
|
||||
|
||||
// pass through RX clock to MAC
|
||||
BUFG
|
||||
clk_bufg (
|
||||
.I(clk_int),
|
||||
.O(output_clk)
|
||||
);
|
||||
|
||||
end
|
||||
|
||||
end else begin
|
||||
|
||||
// pass through RX clock to input buffers
|
||||
assign clk_io = input_clk;
|
||||
|
||||
// pass through RX clock to logic
|
||||
assign clk_int = input_clk;
|
||||
assign output_clk = clk_int;
|
||||
|
||||
end
|
||||
|
||||
endgenerate
|
||||
|
||||
(* IOB = "TRUE" *)
|
||||
reg [WIDTH-1:0] output_q_reg = {WIDTH{1'b0}};
|
||||
|
||||
assign output_q = output_q_reg;
|
||||
|
||||
always @(posedge clk_io) begin
|
||||
output_q_reg <= input_d;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
`resetall
|
Loading…
Add table
Reference in a new issue