Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ycai
simbricks
Commits
738c1fef
Commit
738c1fef
authored
Jun 07, 2020
by
Antoine Kaufmann
Browse files
add corundum and verilator build files
parent
7f925101
Changes
157
Hide whitespace changes
Inline
Side-by-side
Showing
20 changed files
with
9031 additions
and
0 deletions
+9031
-0
corundum/lib/eth/rtl/arp.v
corundum/lib/eth/rtl/arp.v
+440
-0
corundum/lib/eth/rtl/arp_cache.v
corundum/lib/eth/rtl/arp_cache.v
+243
-0
corundum/lib/eth/rtl/arp_eth_rx.v
corundum/lib/eth/rtl/arp_eth_rx.v
+323
-0
corundum/lib/eth/rtl/arp_eth_tx.v
corundum/lib/eth/rtl/arp_eth_tx.v
+360
-0
corundum/lib/eth/rtl/axis_baser_rx_64.v
corundum/lib/eth/rtl/axis_baser_rx_64.v
+615
-0
corundum/lib/eth/rtl/axis_baser_tx_64.v
corundum/lib/eth/rtl/axis_baser_tx_64.v
+916
-0
corundum/lib/eth/rtl/axis_eth_fcs.v
corundum/lib/eth/rtl/axis_eth_fcs.v
+98
-0
corundum/lib/eth/rtl/axis_eth_fcs_64.v
corundum/lib/eth/rtl/axis_eth_fcs_64.v
+227
-0
corundum/lib/eth/rtl/axis_eth_fcs_check.v
corundum/lib/eth/rtl/axis_eth_fcs_check.v
+341
-0
corundum/lib/eth/rtl/axis_eth_fcs_check_64.v
corundum/lib/eth/rtl/axis_eth_fcs_check_64.v
+478
-0
corundum/lib/eth/rtl/axis_eth_fcs_insert.v
corundum/lib/eth/rtl/axis_eth_fcs_insert.v
+368
-0
corundum/lib/eth/rtl/axis_eth_fcs_insert_64.v
corundum/lib/eth/rtl/axis_eth_fcs_insert_64.v
+717
-0
corundum/lib/eth/rtl/axis_gmii_rx.v
corundum/lib/eth/rtl/axis_gmii_rx.v
+351
-0
corundum/lib/eth/rtl/axis_gmii_tx.v
corundum/lib/eth/rtl/axis_gmii_tx.v
+448
-0
corundum/lib/eth/rtl/axis_xgmii_rx_32.v
corundum/lib/eth/rtl/axis_xgmii_rx_32.v
+435
-0
corundum/lib/eth/rtl/axis_xgmii_rx_64.v
corundum/lib/eth/rtl/axis_xgmii_rx_64.v
+555
-0
corundum/lib/eth/rtl/axis_xgmii_tx_32.v
corundum/lib/eth/rtl/axis_xgmii_tx_32.v
+626
-0
corundum/lib/eth/rtl/axis_xgmii_tx_64.v
corundum/lib/eth/rtl/axis_xgmii_tx_64.v
+783
-0
corundum/lib/eth/rtl/eth_arb_mux.v
corundum/lib/eth/rtl/eth_arb_mux.v
+310
-0
corundum/lib/eth/rtl/eth_axis_rx.v
corundum/lib/eth/rtl/eth_axis_rx.v
+397
-0
No files found.
Too many changes to show.
To preserve performance only
157 of 157+
files are displayed.
Plain diff
Email patch
corundum/lib/eth/rtl/arp.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* ARP block for IPv4, ethernet frame interface
*/
module
arp
#
(
// 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
),
// Log2 of ARP cache size
parameter
CACHE_ADDR_WIDTH
=
9
,
// ARP request retry count
parameter
REQUEST_RETRY_COUNT
=
4
,
// ARP request retry interval (in cycles)
parameter
REQUEST_RETRY_INTERVAL
=
125000000
*
2
,
// ARP request timeout (in cycles)
parameter
REQUEST_TIMEOUT
=
125000000
*
30
)
(
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
,
/*
* Ethernet frame output
*/
output
wire
m_eth_hdr_valid
,
input
wire
m_eth_hdr_ready
,
output
wire
[
47
:
0
]
m_eth_dest_mac
,
output
wire
[
47
:
0
]
m_eth_src_mac
,
output
wire
[
15
:
0
]
m_eth_type
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep
,
output
wire
m_eth_payload_axis_tvalid
,
input
wire
m_eth_payload_axis_tready
,
output
wire
m_eth_payload_axis_tlast
,
output
wire
m_eth_payload_axis_tuser
,
/*
* ARP requests
*/
input
wire
arp_request_valid
,
output
wire
arp_request_ready
,
input
wire
[
31
:
0
]
arp_request_ip
,
output
wire
arp_response_valid
,
input
wire
arp_response_ready
,
output
wire
arp_response_error
,
output
wire
[
47
:
0
]
arp_response_mac
,
/*
* Configuration
*/
input
wire
[
47
:
0
]
local_mac
,
input
wire
[
31
:
0
]
local_ip
,
input
wire
[
31
:
0
]
gateway_ip
,
input
wire
[
31
:
0
]
subnet_mask
,
input
wire
clear_cache
);
localparam
[
15
:
0
]
ARP_OPER_ARP_REQUEST
=
16'h0001
,
ARP_OPER_ARP_REPLY
=
16'h0002
,
ARP_OPER_INARP_REQUEST
=
16'h0008
,
ARP_OPER_INARP_REPLY
=
16'h0009
;
wire
incoming_frame_valid
;
reg
incoming_frame_ready
;
wire
[
47
:
0
]
incoming_eth_dest_mac
;
wire
[
47
:
0
]
incoming_eth_src_mac
;
wire
[
15
:
0
]
incoming_eth_type
;
wire
[
15
:
0
]
incoming_arp_htype
;
wire
[
15
:
0
]
incoming_arp_ptype
;
wire
[
7
:
0
]
incoming_arp_hlen
;
wire
[
7
:
0
]
incoming_arp_plen
;
wire
[
15
:
0
]
incoming_arp_oper
;
wire
[
47
:
0
]
incoming_arp_sha
;
wire
[
31
:
0
]
incoming_arp_spa
;
wire
[
47
:
0
]
incoming_arp_tha
;
wire
[
31
:
0
]
incoming_arp_tpa
;
/*
* ARP frame processing
*/
arp_eth_rx
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
)
)
arp_eth_rx_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// Ethernet frame input
.
s_eth_hdr_valid
(
s_eth_hdr_valid
),
.
s_eth_hdr_ready
(
s_eth_hdr_ready
),
.
s_eth_dest_mac
(
s_eth_dest_mac
),
.
s_eth_src_mac
(
s_eth_src_mac
),
.
s_eth_type
(
s_eth_type
),
.
s_eth_payload_axis_tdata
(
s_eth_payload_axis_tdata
),
.
s_eth_payload_axis_tkeep
(
s_eth_payload_axis_tkeep
),
.
s_eth_payload_axis_tvalid
(
s_eth_payload_axis_tvalid
),
.
s_eth_payload_axis_tready
(
s_eth_payload_axis_tready
),
.
s_eth_payload_axis_tlast
(
s_eth_payload_axis_tlast
),
.
s_eth_payload_axis_tuser
(
s_eth_payload_axis_tuser
),
// ARP frame output
.
m_frame_valid
(
incoming_frame_valid
),
.
m_frame_ready
(
incoming_frame_ready
),
.
m_eth_dest_mac
(
incoming_eth_dest_mac
),
.
m_eth_src_mac
(
incoming_eth_src_mac
),
.
m_eth_type
(
incoming_eth_type
),
.
m_arp_htype
(
incoming_arp_htype
),
.
m_arp_ptype
(
incoming_arp_ptype
),
.
m_arp_hlen
(
incoming_arp_hlen
),
.
m_arp_plen
(
incoming_arp_plen
),
.
m_arp_oper
(
incoming_arp_oper
),
.
m_arp_sha
(
incoming_arp_sha
),
.
m_arp_spa
(
incoming_arp_spa
),
.
m_arp_tha
(
incoming_arp_tha
),
.
m_arp_tpa
(
incoming_arp_tpa
),
// Status signals
.
busy
(),
.
error_header_early_termination
(),
.
error_invalid_header
()
);
reg
outgoing_frame_valid_reg
=
1'b0
,
outgoing_frame_valid_next
;
wire
outgoing_frame_ready
;
reg
[
47
:
0
]
outgoing_eth_dest_mac_reg
=
48'd0
,
outgoing_eth_dest_mac_next
;
reg
[
15
:
0
]
outgoing_arp_oper_reg
=
16'd0
,
outgoing_arp_oper_next
;
reg
[
47
:
0
]
outgoing_arp_tha_reg
=
48'd0
,
outgoing_arp_tha_next
;
reg
[
31
:
0
]
outgoing_arp_tpa_reg
=
32'd0
,
outgoing_arp_tpa_next
;
arp_eth_tx
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
)
)
arp_eth_tx_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// ARP frame input
.
s_frame_valid
(
outgoing_frame_valid_reg
),
.
s_frame_ready
(
outgoing_frame_ready
),
.
s_eth_dest_mac
(
outgoing_eth_dest_mac_reg
),
.
s_eth_src_mac
(
local_mac
),
.
s_eth_type
(
16'h0806
),
.
s_arp_htype
(
16'h0001
),
.
s_arp_ptype
(
16'h0800
),
.
s_arp_oper
(
outgoing_arp_oper_reg
),
.
s_arp_sha
(
local_mac
),
.
s_arp_spa
(
local_ip
),
.
s_arp_tha
(
outgoing_arp_tha_reg
),
.
s_arp_tpa
(
outgoing_arp_tpa_reg
),
// Ethernet frame output
.
m_eth_hdr_valid
(
m_eth_hdr_valid
),
.
m_eth_hdr_ready
(
m_eth_hdr_ready
),
.
m_eth_dest_mac
(
m_eth_dest_mac
),
.
m_eth_src_mac
(
m_eth_src_mac
),
.
m_eth_type
(
m_eth_type
),
.
m_eth_payload_axis_tdata
(
m_eth_payload_axis_tdata
),
.
m_eth_payload_axis_tkeep
(
m_eth_payload_axis_tkeep
),
.
m_eth_payload_axis_tvalid
(
m_eth_payload_axis_tvalid
),
.
m_eth_payload_axis_tready
(
m_eth_payload_axis_tready
),
.
m_eth_payload_axis_tlast
(
m_eth_payload_axis_tlast
),
.
m_eth_payload_axis_tuser
(
m_eth_payload_axis_tuser
),
// Status signals
.
busy
()
);
reg
cache_query_request_valid_reg
=
1'b0
,
cache_query_request_valid_next
;
reg
[
31
:
0
]
cache_query_request_ip_reg
=
32'd0
,
cache_query_request_ip_next
;
wire
cache_query_response_valid
;
wire
cache_query_response_error
;
wire
[
47
:
0
]
cache_query_response_mac
;
reg
cache_write_request_valid_reg
=
1'b0
,
cache_write_request_valid_next
;
reg
[
31
:
0
]
cache_write_request_ip_reg
=
32'd0
,
cache_write_request_ip_next
;
reg
[
47
:
0
]
cache_write_request_mac_reg
=
48'd0
,
cache_write_request_mac_next
;
/*
* ARP cache
*/
arp_cache
#(
.
CACHE_ADDR_WIDTH
(
CACHE_ADDR_WIDTH
)
)
arp_cache_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// Query cache
.
query_request_valid
(
cache_query_request_valid_reg
),
.
query_request_ready
(),
.
query_request_ip
(
cache_query_request_ip_reg
),
.
query_response_valid
(
cache_query_response_valid
),
.
query_response_ready
(
1'b1
),
.
query_response_error
(
cache_query_response_error
),
.
query_response_mac
(
cache_query_response_mac
),
// Write cache
.
write_request_valid
(
cache_write_request_valid_reg
),
.
write_request_ready
(),
.
write_request_ip
(
cache_write_request_ip_reg
),
.
write_request_mac
(
cache_write_request_mac_reg
),
// Configuration
.
clear_cache
(
clear_cache
)
);
reg
arp_request_operation_reg
=
1'b0
,
arp_request_operation_next
;
reg
arp_request_ready_reg
=
1'b0
,
arp_request_ready_next
;
reg
[
31
:
0
]
arp_request_ip_reg
=
32'd0
,
arp_request_ip_next
;
reg
arp_response_valid_reg
=
1'b0
,
arp_response_valid_next
;
reg
arp_response_error_reg
=
1'b0
,
arp_response_error_next
;
reg
[
47
:
0
]
arp_response_mac_reg
=
48'd0
,
arp_response_mac_next
;
reg
[
5
:
0
]
arp_request_retry_cnt_reg
=
6'd0
,
arp_request_retry_cnt_next
;
reg
[
35
:
0
]
arp_request_timer_reg
=
36'd0
,
arp_request_timer_next
;
assign
arp_request_ready
=
arp_request_ready_reg
;
assign
arp_response_valid
=
arp_response_valid_reg
;
assign
arp_response_error
=
arp_response_error_reg
;
assign
arp_response_mac
=
arp_response_mac_reg
;
always
@*
begin
incoming_frame_ready
=
1'b0
;
outgoing_frame_valid_next
=
outgoing_frame_valid_reg
&&
!
outgoing_frame_ready
;
outgoing_eth_dest_mac_next
=
outgoing_eth_dest_mac_reg
;
outgoing_arp_oper_next
=
outgoing_arp_oper_reg
;
outgoing_arp_tha_next
=
outgoing_arp_tha_reg
;
outgoing_arp_tpa_next
=
outgoing_arp_tpa_reg
;
cache_query_request_valid_next
=
1'b0
;
cache_query_request_ip_next
=
cache_query_request_ip_reg
;
cache_write_request_valid_next
=
1'b0
;
cache_write_request_mac_next
=
cache_write_request_mac_reg
;
cache_write_request_ip_next
=
cache_write_request_ip_reg
;
arp_request_ready_next
=
1'b0
;
arp_request_ip_next
=
arp_request_ip_reg
;
arp_request_operation_next
=
arp_request_operation_reg
;
arp_request_retry_cnt_next
=
arp_request_retry_cnt_reg
;
arp_request_timer_next
=
arp_request_timer_reg
;
arp_response_valid_next
=
arp_response_valid_reg
&&
!
arp_response_ready
;
arp_response_error_next
=
1'b0
;
arp_response_mac_next
=
48'd0
;
// manage incoming frames
incoming_frame_ready
=
outgoing_frame_ready
;
if
(
incoming_frame_valid
&&
incoming_frame_ready
)
begin
if
(
incoming_eth_type
==
16'h0806
&&
incoming_arp_htype
==
16'h0001
&&
incoming_arp_ptype
==
16'h0800
)
begin
// store sender addresses in cache
cache_write_request_valid_next
=
1'b1
;
cache_write_request_ip_next
=
incoming_arp_spa
;
cache_write_request_mac_next
=
incoming_arp_sha
;
if
(
incoming_arp_oper
==
ARP_OPER_ARP_REQUEST
)
begin
// ARP request
if
(
incoming_arp_tpa
==
local_ip
)
begin
// send reply frame to valid incoming request
outgoing_frame_valid_next
=
1'b1
;
outgoing_eth_dest_mac_next
=
incoming_eth_src_mac
;
outgoing_arp_oper_next
=
ARP_OPER_ARP_REPLY
;
outgoing_arp_tha_next
=
incoming_arp_sha
;
outgoing_arp_tpa_next
=
incoming_arp_spa
;
end
end
else
if
(
incoming_arp_oper
==
ARP_OPER_INARP_REQUEST
)
begin
// INARP request
if
(
incoming_arp_tha
==
local_mac
)
begin
// send reply frame to valid incoming request
outgoing_frame_valid_next
=
1'b1
;
outgoing_eth_dest_mac_next
=
incoming_eth_src_mac
;
outgoing_arp_oper_next
=
ARP_OPER_INARP_REPLY
;
outgoing_arp_tha_next
=
incoming_arp_sha
;
outgoing_arp_tpa_next
=
incoming_arp_spa
;
end
end
end
end
// manage ARP lookup requests
if
(
arp_request_operation_reg
)
begin
arp_request_ready_next
=
1'b0
;
cache_query_request_valid_next
=
1'b1
;
arp_request_timer_next
=
arp_request_timer_reg
-
1
;
// if we got a response, it will go in the cache, so when the query succeds, we're done
if
(
cache_query_response_valid
&&
!
cache_query_response_error
)
begin
arp_request_operation_next
=
1'b0
;
cache_query_request_valid_next
=
1'b0
;
arp_response_valid_next
=
1'b1
;
arp_response_error_next
=
1'b0
;
arp_response_mac_next
=
cache_query_response_mac
;
end
// timer timeout
if
(
arp_request_timer_reg
==
0
)
begin
if
(
arp_request_retry_cnt_reg
>
0
)
begin
// have more retries
// send ARP request frame
outgoing_frame_valid_next
=
1'b1
;
outgoing_eth_dest_mac_next
=
48'hffffffffffff
;
outgoing_arp_oper_next
=
ARP_OPER_ARP_REQUEST
;
outgoing_arp_tha_next
=
48'h000000000000
;
outgoing_arp_tpa_next
=
arp_request_ip_reg
;
arp_request_retry_cnt_next
=
arp_request_retry_cnt_reg
-
1
;
if
(
arp_request_retry_cnt_reg
>
1
)
begin
arp_request_timer_next
=
REQUEST_RETRY_INTERVAL
;
end
else
begin
arp_request_timer_next
=
REQUEST_TIMEOUT
;
end
end
else
begin
// out of retries
arp_request_operation_next
=
1'b0
;
arp_response_valid_next
=
1'b1
;
arp_response_error_next
=
1'b1
;
cache_query_request_valid_next
=
1'b0
;
end
end
end
else
begin
arp_request_ready_next
=
!
arp_response_valid_next
;
if
(
cache_query_request_valid_reg
)
begin
cache_query_request_valid_next
=
1'b1
;
if
(
cache_query_response_valid
)
begin
if
(
cache_query_response_error
)
begin
arp_request_operation_next
=
1'b1
;
// send ARP request frame
outgoing_frame_valid_next
=
1'b1
;
outgoing_eth_dest_mac_next
=
48'hffffffffffff
;
outgoing_arp_oper_next
=
ARP_OPER_ARP_REQUEST
;
outgoing_arp_tha_next
=
48'h000000000000
;
outgoing_arp_tpa_next
=
arp_request_ip_reg
;
arp_request_retry_cnt_next
=
REQUEST_RETRY_COUNT
-
1
;
arp_request_timer_next
=
REQUEST_RETRY_INTERVAL
;
end
else
begin
cache_query_request_valid_next
=
1'b0
;
arp_response_valid_next
=
1'b1
;
arp_response_error_next
=
1'b0
;
arp_response_mac_next
=
cache_query_response_mac
;
end
end
end
else
if
(
arp_request_valid
&&
arp_request_ready
)
begin
if
(
~
(
arp_request_ip
|
subnet_mask
)
==
0
)
begin
// broadcast address
// (all bits in request IP set where subnet mask is clear)
arp_response_valid_next
=
1'b1
;
arp_response_error_next
=
1'b0
;
arp_response_mac_next
=
48'hffffffffffff
;
end
else
if
(((
arp_request_ip
^
gateway_ip
)
&
subnet_mask
)
==
0
)
begin
// within subnet, look up IP directly
// (no bits differ between request IP and gateway IP where subnet mask is set)
cache_query_request_valid_next
=
1'b1
;
cache_query_request_ip_next
=
arp_request_ip
;
arp_request_ip_next
=
arp_request_ip
;
end
else
begin
// outside of subnet, so look up gateway address
cache_query_request_valid_next
=
1'b1
;
cache_query_request_ip_next
=
gateway_ip
;
arp_request_ip_next
=
gateway_ip
;
end
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
outgoing_frame_valid_reg
<=
1'b0
;
cache_query_request_valid_reg
<=
1'b0
;
cache_write_request_valid_reg
<=
1'b0
;
arp_request_ready_reg
<=
1'b0
;
arp_request_operation_reg
<=
1'b0
;
arp_request_retry_cnt_reg
<=
6'd0
;
arp_request_timer_reg
<=
36'd0
;
arp_response_valid_reg
<=
1'b0
;
end
else
begin
outgoing_frame_valid_reg
<=
outgoing_frame_valid_next
;
cache_query_request_valid_reg
<=
cache_query_request_valid_next
;
cache_write_request_valid_reg
<=
cache_write_request_valid_next
;
arp_request_ready_reg
<=
arp_request_ready_next
;
arp_request_operation_reg
<=
arp_request_operation_next
;
arp_request_retry_cnt_reg
<=
arp_request_retry_cnt_next
;
arp_request_timer_reg
<=
arp_request_timer_next
;
arp_response_valid_reg
<=
arp_response_valid_next
;
end
cache_query_request_ip_reg
<=
cache_query_request_ip_next
;
outgoing_eth_dest_mac_reg
<=
outgoing_eth_dest_mac_next
;
outgoing_arp_oper_reg
<=
outgoing_arp_oper_next
;
outgoing_arp_tha_reg
<=
outgoing_arp_tha_next
;
outgoing_arp_tpa_reg
<=
outgoing_arp_tpa_next
;
cache_write_request_mac_reg
<=
cache_write_request_mac_next
;
cache_write_request_ip_reg
<=
cache_write_request_ip_next
;
arp_request_ip_reg
<=
arp_request_ip_next
;
arp_response_error_reg
<=
arp_response_error_next
;
arp_response_mac_reg
<=
arp_response_mac_next
;
end
endmodule
corundum/lib/eth/rtl/arp_cache.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2014-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
`timescale
1
ns
/
1
ps
/*
* ARP cache
*/
module
arp_cache
#(
parameter
CACHE_ADDR_WIDTH
=
9
)
(
input
wire
clk
,
input
wire
rst
,
/*
* Cache query
*/
input
wire
query_request_valid
,
output
wire
query_request_ready
,
input
wire
[
31
:
0
]
query_request_ip
,
output
wire
query_response_valid
,
input
wire
query_response_ready
,
output
wire
query_response_error
,
output
wire
[
47
:
0
]
query_response_mac
,
/*
* Cache write
*/
input
wire
write_request_valid
,
output
wire
write_request_ready
,
input
wire
[
31
:
0
]
write_request_ip
,
input
wire
[
47
:
0
]
write_request_mac
,
/*
* Configuration
*/
input
wire
clear_cache
);
reg
mem_write
=
0
;
reg
store_query
=
0
;
reg
store_write
=
0
;
reg
query_ip_valid_reg
=
0
,
query_ip_valid_next
;
reg
[
31
:
0
]
query_ip_reg
=
0
;
reg
write_ip_valid_reg
=
0
,
write_ip_valid_next
;
reg
[
31
:
0
]
write_ip_reg
=
0
;
reg
[
47
:
0
]
write_mac_reg
=
0
;
reg
clear_cache_reg
=
0
,
clear_cache_next
;
reg
[
CACHE_ADDR_WIDTH
-
1
:
0
]
wr_ptr_reg
=
{
CACHE_ADDR_WIDTH
{
1'b0
}}
,
wr_ptr_next
;
reg
[
CACHE_ADDR_WIDTH
-
1
:
0
]
rd_ptr_reg
=
{
CACHE_ADDR_WIDTH
{
1'b0
}}
,
rd_ptr_next
;
reg
valid_mem
[(
2
**
CACHE_ADDR_WIDTH
)
-
1
:
0
];
reg
[
31
:
0
]
ip_addr_mem
[(
2
**
CACHE_ADDR_WIDTH
)
-
1
:
0
];
reg
[
47
:
0
]
mac_addr_mem
[(
2
**
CACHE_ADDR_WIDTH
)
-
1
:
0
];
reg
query_request_ready_reg
=
0
,
query_request_ready_next
;
reg
query_response_valid_reg
=
0
,
query_response_valid_next
;
reg
query_response_error_reg
=
0
,
query_response_error_next
;
reg
[
47
:
0
]
query_response_mac_reg
=
0
;
reg
write_request_ready_reg
=
0
,
write_request_ready_next
;
wire
[
31
:
0
]
query_request_hash
;
wire
[
31
:
0
]
write_request_hash
;
assign
query_request_ready
=
query_request_ready_reg
;
assign
query_response_valid
=
query_response_valid_reg
;
assign
query_response_error
=
query_response_error_reg
;
assign
query_response_mac
=
query_response_mac_reg
;
assign
write_request_ready
=
write_request_ready_reg
;
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
rd_hash
(
.
data_in
(
query_request_ip
),
.
state_in
(
32'hffffffff
),
.
data_out
(),
.
state_out
(
query_request_hash
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
wr_hash
(
.
data_in
(
write_request_ip
),
.
state_in
(
32'hffffffff
),
.
data_out
(),
.
state_out
(
write_request_hash
)
);
integer
i
;
initial
begin
for
(
i
=
0
;
i
<
2
**
CACHE_ADDR_WIDTH
;
i
=
i
+
1
)
begin
valid_mem
[
i
]
=
1'b0
;
ip_addr_mem
[
i
]
=
32'd0
;
mac_addr_mem
[
i
]
=
48'd0
;
end
end
always
@*
begin
mem_write
=
1'b0
;
store_query
=
1'b0
;
store_write
=
1'b0
;
wr_ptr_next
=
wr_ptr_reg
;
rd_ptr_next
=
rd_ptr_reg
;
clear_cache_next
=
clear_cache_reg
|
clear_cache
;
query_ip_valid_next
=
query_ip_valid_reg
;
query_request_ready_next
=
(
~
query_ip_valid_reg
||
~
query_request_valid
||
query_response_ready
)
&&
!
clear_cache_next
;
query_response_valid_next
=
query_response_valid_reg
&
~
query_response_ready
;
query_response_error_next
=
query_response_error_reg
;
if
(
query_ip_valid_reg
&&
(
~
query_request_valid
||
query_response_ready
))
begin
query_response_valid_next
=
1
;
query_ip_valid_next
=
0
;
if
(
valid_mem
[
rd_ptr_reg
]
&&
ip_addr_mem
[
rd_ptr_reg
]
==
query_ip_reg
)
begin
query_response_error_next
=
0
;
end
else
begin
query_response_error_next
=
1
;
end
end
if
(
query_request_valid
&&
query_request_ready
&&
(
~
query_ip_valid_reg
||
~
query_request_valid
||
query_response_ready
))
begin
store_query
=
1
;
query_ip_valid_next
=
1
;
rd_ptr_next
=
query_request_hash
[
CACHE_ADDR_WIDTH
-
1
:
0
];
end
write_ip_valid_next
=
write_ip_valid_reg
;
write_request_ready_next
=
!
clear_cache_next
;
if
(
write_ip_valid_reg
)
begin
write_ip_valid_next
=
0
;
mem_write
=
1
;
end
if
(
write_request_valid
&&
write_request_ready
)
begin
store_write
=
1
;
write_ip_valid_next
=
1
;
wr_ptr_next
=
write_request_hash
[
CACHE_ADDR_WIDTH
-
1
:
0
];
end
if
(
clear_cache
)
begin
clear_cache_next
=
1'b1
;
wr_ptr_next
=
0
;
end
else
if
(
clear_cache_reg
)
begin
wr_ptr_next
=
wr_ptr_reg
+
1
;
clear_cache_next
=
wr_ptr_next
!=
0
;
mem_write
=
1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
query_ip_valid_reg
<=
1'b0
;
query_request_ready_reg
<=
1'b0
;
query_response_valid_reg
<=
1'b0
;
write_ip_valid_reg
<=
1'b0
;
write_request_ready_reg
<=
1'b0
;
clear_cache_reg
<=
1'b1
;
wr_ptr_reg
<=
0
;
end
else
begin
query_ip_valid_reg
<=
query_ip_valid_next
;
query_request_ready_reg
<=
query_request_ready_next
;
query_response_valid_reg
<=
query_response_valid_next
;
write_ip_valid_reg
<=
write_ip_valid_next
;
write_request_ready_reg
<=
write_request_ready_next
;
clear_cache_reg
<=
clear_cache_next
;
wr_ptr_reg
<=
wr_ptr_next
;
end
query_response_error_reg
<=
query_response_error_next
;
if
(
store_query
)
begin
query_ip_reg
<=
query_request_ip
;
end
if
(
store_write
)
begin
write_ip_reg
<=
write_request_ip
;
write_mac_reg
<=
write_request_mac
;
end
rd_ptr_reg
<=
rd_ptr_next
;
query_response_mac_reg
<=
mac_addr_mem
[
rd_ptr_reg
];
if
(
mem_write
)
begin
valid_mem
[
wr_ptr_reg
]
<=
!
clear_cache_reg
;
ip_addr_mem
[
wr_ptr_reg
]
<=
write_ip_reg
;
mac_addr_mem
[
wr_ptr_reg
]
<=
write_mac_reg
;
end
end
endmodule
corundum/lib/eth/rtl/arp_eth_rx.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* ARP ethernet frame receiver (Ethernet frame in, ARP frame out)
*/
module
arp_eth_rx
#
(
// 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
,
/*
* ARP frame output
*/
output
wire
m_frame_valid
,
input
wire
m_frame_ready
,
output
wire
[
47
:
0
]
m_eth_dest_mac
,
output
wire
[
47
:
0
]
m_eth_src_mac
,
output
wire
[
15
:
0
]
m_eth_type
,
output
wire
[
15
:
0
]
m_arp_htype
,
output
wire
[
15
:
0
]
m_arp_ptype
,
output
wire
[
7
:
0
]
m_arp_hlen
,
output
wire
[
7
:
0
]
m_arp_plen
,
output
wire
[
15
:
0
]
m_arp_oper
,
output
wire
[
47
:
0
]
m_arp_sha
,
output
wire
[
31
:
0
]
m_arp_spa
,
output
wire
[
47
:
0
]
m_arp_tha
,
output
wire
[
31
:
0
]
m_arp_tpa
,
/*
* Status signals
*/
output
wire
busy
,
output
wire
error_header_early_termination
,
output
wire
error_invalid_header
);
parameter
CYCLE_COUNT
=
(
28
+
KEEP_WIDTH
-
1
)
/
KEEP_WIDTH
;
parameter
PTR_WIDTH
=
$
clog2
(
CYCLE_COUNT
);
parameter
OFFSET
=
28
%
KEEP_WIDTH
;
// bus width assertions
initial
begin
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI stream interface requires byte (8-bit) granularity (instance %m)"
);
$
finish
;
end
end
/*
ARP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0806) 2 octets
HTYPE (1) 2 octets
PTYPE (0x0800) 2 octets
HLEN (6) 1 octets
PLEN (4) 1 octets
OPER 2 octets
SHA Sender MAC 6 octets
SPA Sender IP 4 octets
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an Ethernet frame with header fields in parallel and
payload on an AXI stream interface, decodes the ARP packet fields, and
produces the frame fields in parallel.
*/
// datapath control signals
reg
store_eth_hdr
;
reg
read_eth_header_reg
=
1'b1
,
read_eth_header_next
;
reg
read_arp_header_reg
=
1'b0
,
read_arp_header_next
;
reg
[
PTR_WIDTH
-
1
:
0
]
ptr_reg
=
0
,
ptr_next
;
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
m_frame_valid_reg
=
1'b0
,
m_frame_valid_next
;
reg
[
47
:
0
]
m_eth_dest_mac_reg
=
48'd0
;
reg
[
47
:
0
]
m_eth_src_mac_reg
=
48'd0
;
reg
[
15
:
0
]
m_eth_type_reg
=
16'd0
;
reg
[
15
:
0
]
m_arp_htype_reg
=
16'd0
,
m_arp_htype_next
;
reg
[
15
:
0
]
m_arp_ptype_reg
=
16'd0
,
m_arp_ptype_next
;
reg
[
7
:
0
]
m_arp_hlen_reg
=
8'd0
,
m_arp_hlen_next
;
reg
[
7
:
0
]
m_arp_plen_reg
=
8'd0
,
m_arp_plen_next
;
reg
[
15
:
0
]
m_arp_oper_reg
=
16'd0
,
m_arp_oper_next
;
reg
[
47
:
0
]
m_arp_sha_reg
=
48'd0
,
m_arp_sha_next
;
reg
[
31
:
0
]
m_arp_spa_reg
=
32'd0
,
m_arp_spa_next
;
reg
[
47
:
0
]
m_arp_tha_reg
=
48'd0
,
m_arp_tha_next
;
reg
[
31
:
0
]
m_arp_tpa_reg
=
32'd0
,
m_arp_tpa_next
;
reg
busy_reg
=
1'b0
;
reg
error_header_early_termination_reg
=
1'b0
,
error_header_early_termination_next
;
reg
error_invalid_header_reg
=
1'b0
,
error_invalid_header_next
;
assign
s_eth_hdr_ready
=
s_eth_hdr_ready_reg
;
assign
s_eth_payload_axis_tready
=
s_eth_payload_axis_tready_reg
;
assign
m_frame_valid
=
m_frame_valid_reg
;
assign
m_eth_dest_mac
=
m_eth_dest_mac_reg
;
assign
m_eth_src_mac
=
m_eth_src_mac_reg
;
assign
m_eth_type
=
m_eth_type_reg
;
assign
m_arp_htype
=
m_arp_htype_reg
;
assign
m_arp_ptype
=
m_arp_ptype_reg
;
assign
m_arp_hlen
=
m_arp_hlen_reg
;
assign
m_arp_plen
=
m_arp_plen_reg
;
assign
m_arp_oper
=
m_arp_oper_reg
;
assign
m_arp_sha
=
m_arp_sha_reg
;
assign
m_arp_spa
=
m_arp_spa_reg
;
assign
m_arp_tha
=
m_arp_tha_reg
;
assign
m_arp_tpa
=
m_arp_tpa_reg
;
assign
busy
=
busy_reg
;
assign
error_header_early_termination
=
error_header_early_termination_reg
;
assign
error_invalid_header
=
error_invalid_header_reg
;
always
@*
begin
read_eth_header_next
=
read_eth_header_reg
;
read_arp_header_next
=
read_arp_header_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
;
m_frame_valid_next
=
m_frame_valid_reg
&&
!
m_frame_ready
;
m_arp_htype_next
=
m_arp_htype_reg
;
m_arp_ptype_next
=
m_arp_ptype_reg
;
m_arp_hlen_next
=
m_arp_hlen_reg
;
m_arp_plen_next
=
m_arp_plen_reg
;
m_arp_oper_next
=
m_arp_oper_reg
;
m_arp_sha_next
=
m_arp_sha_reg
;
m_arp_spa_next
=
m_arp_spa_reg
;
m_arp_tha_next
=
m_arp_tha_reg
;
m_arp_tpa_next
=
m_arp_tpa_reg
;
error_header_early_termination_next
=
1'b0
;
error_invalid_header_next
=
1'b0
;
if
(
s_eth_hdr_ready
&&
s_eth_hdr_valid
)
begin
if
(
read_eth_header_reg
)
begin
store_eth_hdr
=
1'b1
;
ptr_next
=
0
;
read_eth_header_next
=
1'b0
;
read_arp_header_next
=
1'b1
;
end
end
if
(
s_eth_payload_axis_tready
&&
s_eth_payload_axis_tvalid
)
begin
if
(
read_arp_header_reg
)
begin
// word transfer in - store it
ptr_next
=
ptr_reg
+
1
;
`define
_HEADER_FIELD_
(
offset
,
field
)
\
if
(
ptr_reg
==
offset
/
KEEP_WIDTH
&&
(!
KEEP_ENABLE
||
s_eth_payload_axis_tkeep
[
offset
%
KEEP_WIDTH
]))
begin \
field
=
s_eth_payload_axis_tdata
[(
offset
%
KEEP_WIDTH
)*
8
+:
8
]
;
\
end
`_HEADER_FIELD_
(
0
,
m_arp_htype_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
1
,
m_arp_htype_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
2
,
m_arp_ptype_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
3
,
m_arp_ptype_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
4
,
m_arp_hlen_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
5
,
m_arp_plen_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
6
,
m_arp_oper_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
7
,
m_arp_oper_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
8
,
m_arp_sha_next
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
9
,
m_arp_sha_next
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
10
,
m_arp_sha_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
11
,
m_arp_sha_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
12
,
m_arp_sha_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
13
,
m_arp_sha_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
14
,
m_arp_spa_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
15
,
m_arp_spa_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
16
,
m_arp_spa_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
17
,
m_arp_spa_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
18
,
m_arp_tha_next
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
19
,
m_arp_tha_next
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
20
,
m_arp_tha_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
21
,
m_arp_tha_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
22
,
m_arp_tha_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
23
,
m_arp_tha_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
24
,
m_arp_tpa_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
25
,
m_arp_tpa_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
26
,
m_arp_tpa_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
27
,
m_arp_tpa_next
[
0
*
8
+:
8
])
if
(
ptr_reg
==
27
/
KEEP_WIDTH
&&
(
!
KEEP_ENABLE
||
s_eth_payload_axis_tkeep
[
27
%
KEEP_WIDTH
]))
begin
read_arp_header_next
=
1'b0
;
end
`undef
_
HEADER_FIELD_
end
if
(
s_eth_payload_axis_tlast
)
begin
if
(
read_arp_header_next
)
begin
// don't have the whole header
error_header_early_termination_next
=
1'b1
;
end
else
if
(
m_arp_hlen_next
!=
4'd6
||
m_arp_plen_next
!=
4'd4
)
begin
// lengths not valid
error_invalid_header_next
=
1'b1
;
end
else
begin
// otherwise, transfer tuser
m_frame_valid_next
=
!
s_eth_payload_axis_tuser
;
end
ptr_next
=
1'b0
;
read_eth_header_next
=
1'b1
;
read_arp_header_next
=
1'b0
;
end
end
if
(
read_eth_header_next
)
begin
s_eth_hdr_ready_next
=
!
m_frame_valid_next
;
end
else
begin
s_eth_payload_axis_tready_next
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
read_eth_header_reg
<=
read_eth_header_next
;
read_arp_header_reg
<=
read_arp_header_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
;
m_frame_valid_reg
<=
m_frame_valid_next
;
m_arp_htype_reg
<=
m_arp_htype_next
;
m_arp_ptype_reg
<=
m_arp_ptype_next
;
m_arp_hlen_reg
<=
m_arp_hlen_next
;
m_arp_plen_reg
<=
m_arp_plen_next
;
m_arp_oper_reg
<=
m_arp_oper_next
;
m_arp_sha_reg
<=
m_arp_sha_next
;
m_arp_spa_reg
<=
m_arp_spa_next
;
m_arp_tha_reg
<=
m_arp_tha_next
;
m_arp_tpa_reg
<=
m_arp_tpa_next
;
error_header_early_termination_reg
<=
error_header_early_termination_next
;
error_invalid_header_reg
<=
error_invalid_header_next
;
busy_reg
<=
read_arp_header_next
;
// datapath
if
(
store_eth_hdr
)
begin
m_eth_dest_mac_reg
<=
s_eth_dest_mac
;
m_eth_src_mac_reg
<=
s_eth_src_mac
;
m_eth_type_reg
<=
s_eth_type
;
end
if
(
rst
)
begin
read_eth_header_reg
<=
1'b1
;
read_arp_header_reg
<=
1'b0
;
ptr_reg
<=
0
;
s_eth_payload_axis_tready_reg
<=
1'b0
;
m_frame_valid_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
error_header_early_termination_reg
<=
1'b0
;
error_invalid_header_reg
<=
1'b0
;
end
end
endmodule
corundum/lib/eth/rtl/arp_eth_tx.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* ARP ethernet frame transmitter (ARP frame in, Ethernet frame out)
*/
module
arp_eth_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
,
/*
* ARP frame input
*/
input
wire
s_frame_valid
,
output
wire
s_frame_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
[
15
:
0
]
s_arp_htype
,
input
wire
[
15
:
0
]
s_arp_ptype
,
input
wire
[
15
:
0
]
s_arp_oper
,
input
wire
[
47
:
0
]
s_arp_sha
,
input
wire
[
31
:
0
]
s_arp_spa
,
input
wire
[
47
:
0
]
s_arp_tha
,
input
wire
[
31
:
0
]
s_arp_tpa
,
/*
* Ethernet frame output
*/
output
wire
m_eth_hdr_valid
,
input
wire
m_eth_hdr_ready
,
output
wire
[
47
:
0
]
m_eth_dest_mac
,
output
wire
[
47
:
0
]
m_eth_src_mac
,
output
wire
[
15
:
0
]
m_eth_type
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep
,
output
wire
m_eth_payload_axis_tvalid
,
input
wire
m_eth_payload_axis_tready
,
output
wire
m_eth_payload_axis_tlast
,
output
wire
m_eth_payload_axis_tuser
,
/*
* Status signals
*/
output
wire
busy
);
parameter
CYCLE_COUNT
=
(
28
+
KEEP_WIDTH
-
1
)
/
KEEP_WIDTH
;
parameter
PTR_WIDTH
=
$
clog2
(
CYCLE_COUNT
);
parameter
OFFSET
=
28
%
KEEP_WIDTH
;
// bus width assertions
initial
begin
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: AXI stream interface requires byte (8-bit) granularity (instance %m)"
);
$
finish
;
end
end
/*
ARP Frame
Field Length
Destination MAC address 6 octets
Source MAC address 6 octets
Ethertype (0x0806) 2 octets
HTYPE (1) 2 octets
PTYPE (0x0800) 2 octets
HLEN (6) 1 octets
PLEN (4) 1 octets
OPER 2 octets
SHA Sender MAC 6 octets
SPA Sender IP 4 octets
THA Target MAC 6 octets
TPA Target IP 4 octets
This module receives an ARP frame with header fields in parallel and
transmits the complete Ethernet payload on an AXI interface.
*/
// datapath control signals
reg
store_frame
;
reg
send_arp_header_reg
=
1'b0
,
send_arp_header_next
;
reg
[
PTR_WIDTH
-
1
:
0
]
ptr_reg
=
0
,
ptr_next
;
reg
[
15
:
0
]
arp_htype_reg
=
16'd0
;
reg
[
15
:
0
]
arp_ptype_reg
=
16'd0
;
reg
[
15
:
0
]
arp_oper_reg
=
16'd0
;
reg
[
47
:
0
]
arp_sha_reg
=
48'd0
;
reg
[
31
:
0
]
arp_spa_reg
=
32'd0
;
reg
[
47
:
0
]
arp_tha_reg
=
48'd0
;
reg
[
31
:
0
]
arp_tpa_reg
=
32'd0
;
reg
s_frame_ready_reg
=
1'b0
,
s_frame_ready_next
;
reg
m_eth_hdr_valid_reg
=
1'b0
,
m_eth_hdr_valid_next
;
reg
[
47
:
0
]
m_eth_dest_mac_reg
=
48'd0
;
reg
[
47
:
0
]
m_eth_src_mac_reg
=
48'd0
;
reg
[
15
:
0
]
m_eth_type_reg
=
16'd0
;
reg
busy_reg
=
1'b0
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_int
;
reg
m_eth_payload_axis_tvalid_int
;
reg
m_eth_payload_axis_tready_int_reg
=
1'b0
;
reg
m_eth_payload_axis_tlast_int
;
reg
m_eth_payload_axis_tuser_int
;
wire
m_eth_payload_axis_tready_int_early
;
assign
s_frame_ready
=
s_frame_ready_reg
;
assign
m_eth_hdr_valid
=
m_eth_hdr_valid_reg
;
assign
m_eth_dest_mac
=
m_eth_dest_mac_reg
;
assign
m_eth_src_mac
=
m_eth_src_mac_reg
;
assign
m_eth_type
=
m_eth_type_reg
;
assign
busy
=
busy_reg
;
always
@*
begin
send_arp_header_next
=
send_arp_header_reg
;
ptr_next
=
ptr_reg
;
s_frame_ready_next
=
1'b0
;
store_frame
=
1'b0
;
m_eth_hdr_valid_next
=
m_eth_hdr_valid_reg
&&
!
m_eth_hdr_ready
;
m_eth_payload_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_eth_payload_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b0
}}
;
m_eth_payload_axis_tvalid_int
=
1'b0
;
m_eth_payload_axis_tlast_int
=
1'b0
;
m_eth_payload_axis_tuser_int
=
1'b0
;
if
(
s_frame_ready
&&
s_frame_valid
)
begin
store_frame
=
1'b1
;
m_eth_hdr_valid_next
=
1'b1
;
ptr_next
=
0
;
send_arp_header_next
=
1'b1
;
end
if
(
m_eth_payload_axis_tready_int_reg
)
begin
if
(
send_arp_header_reg
)
begin
ptr_next
=
ptr_reg
+
1
;
m_eth_payload_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_eth_payload_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b0
}}
;
m_eth_payload_axis_tvalid_int
=
1'b1
;
m_eth_payload_axis_tlast_int
=
1'b0
;
m_eth_payload_axis_tuser_int
=
1'b0
;
`define
_HEADER_FIELD_
(
offset
,
field
)
\
if
(
ptr_reg
==
offset
/
KEEP_WIDTH
)
begin \
m_eth_payload_axis_tdata_int
[(
offset
%
KEEP_WIDTH
)*
8
+:
8
]
=
field
;
\
m_eth_payload_axis_tkeep_int
[
offset
%
KEEP_WIDTH
]
=
1
'
b1
;
\
end
`_HEADER_FIELD_
(
0
,
arp_htype_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
1
,
arp_htype_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
2
,
arp_ptype_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
3
,
arp_ptype_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
4
,
8'd6
)
`_HEADER_FIELD_
(
5
,
8'd4
)
`_HEADER_FIELD_
(
6
,
arp_oper_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
7
,
arp_oper_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
8
,
arp_sha_reg
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
9
,
arp_sha_reg
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
10
,
arp_sha_reg
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
11
,
arp_sha_reg
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
12
,
arp_sha_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
13
,
arp_sha_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
14
,
arp_spa_reg
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
15
,
arp_spa_reg
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
16
,
arp_spa_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
17
,
arp_spa_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
18
,
arp_tha_reg
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
19
,
arp_tha_reg
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
20
,
arp_tha_reg
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
21
,
arp_tha_reg
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
22
,
arp_tha_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
23
,
arp_tha_reg
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
24
,
arp_tpa_reg
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
25
,
arp_tpa_reg
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
26
,
arp_tpa_reg
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
27
,
arp_tpa_reg
[
0
*
8
+:
8
])
if
(
ptr_reg
==
27
/
KEEP_WIDTH
)
begin
m_eth_payload_axis_tlast_int
=
1'b1
;
send_arp_header_next
=
1'b0
;
end
`undef
_
HEADER_FIELD_
end
end
s_frame_ready_next
=
!
m_eth_hdr_valid_next
&&
!
send_arp_header_next
;
end
always
@
(
posedge
clk
)
begin
send_arp_header_reg
<=
send_arp_header_next
;
ptr_reg
<=
ptr_next
;
s_frame_ready_reg
<=
s_frame_ready_next
;
m_eth_hdr_valid_reg
<=
m_eth_hdr_valid_next
;
busy_reg
<=
send_arp_header_next
;
if
(
store_frame
)
begin
m_eth_dest_mac_reg
<=
s_eth_dest_mac
;
m_eth_src_mac_reg
<=
s_eth_src_mac
;
m_eth_type_reg
<=
s_eth_type
;
arp_htype_reg
<=
s_arp_htype
;
arp_ptype_reg
<=
s_arp_ptype
;
arp_oper_reg
<=
s_arp_oper
;
arp_sha_reg
<=
s_arp_sha
;
arp_spa_reg
<=
s_arp_spa
;
arp_tha_reg
<=
s_arp_tha
;
arp_tpa_reg
<=
s_arp_tpa
;
end
if
(
rst
)
begin
send_arp_header_reg
<=
1'b0
;
ptr_reg
<=
0
;
s_frame_ready_reg
<=
1'b0
;
m_eth_hdr_valid_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_eth_payload_axis_tvalid_reg
=
1'b0
,
m_eth_payload_axis_tvalid_next
;
reg
m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
m_eth_payload_axis_tuser_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_eth_payload_axis_tvalid_reg
=
1'b0
,
temp_m_eth_payload_axis_tvalid_next
;
reg
temp_m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
temp_m_eth_payload_axis_tuser_reg
=
1'b0
;
// datapath control
reg
store_eth_payload_int_to_output
;
reg
store_eth_payload_int_to_temp
;
reg
store_eth_payload_axis_temp_to_output
;
assign
m_eth_payload_axis_tdata
=
m_eth_payload_axis_tdata_reg
;
assign
m_eth_payload_axis_tkeep
=
KEEP_ENABLE
?
m_eth_payload_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_eth_payload_axis_tvalid
=
m_eth_payload_axis_tvalid_reg
;
assign
m_eth_payload_axis_tlast
=
m_eth_payload_axis_tlast_reg
;
assign
m_eth_payload_axis_tuser
=
m_eth_payload_axis_tuser_reg
;
// 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_eth_payload_axis_tready_int_early
=
m_eth_payload_axis_tready
||
(
!
temp_m_eth_payload_axis_tvalid_reg
&&
(
!
m_eth_payload_axis_tvalid_reg
||
!
m_eth_payload_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
store_eth_payload_int_to_output
=
1'b0
;
store_eth_payload_int_to_temp
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b0
;
if
(
m_eth_payload_axis_tready_int_reg
)
begin
// input is ready
if
(
m_eth_payload_axis_tready
||
!
m_eth_payload_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_eth_payload_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_eth_payload_int_to_temp
=
1'b1
;
end
end
else
if
(
m_eth_payload_axis_tready
)
begin
// input is not ready, but output is ready
m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_eth_payload_axis_tvalid_reg
<=
1'b0
;
m_eth_payload_axis_tready_int_reg
<=
1'b0
;
temp_m_eth_payload_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_eth_payload_axis_tvalid_reg
<=
m_eth_payload_axis_tvalid_next
;
m_eth_payload_axis_tready_int_reg
<=
m_eth_payload_axis_tready_int_early
;
temp_m_eth_payload_axis_tvalid_reg
<=
temp_m_eth_payload_axis_tvalid_next
;
end
// datapath
if
(
store_eth_payload_int_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
else
if
(
store_eth_payload_axis_temp_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
temp_m_eth_payload_axis_tdata_reg
;
m_eth_payload_axis_tkeep_reg
<=
temp_m_eth_payload_axis_tkeep_reg
;
m_eth_payload_axis_tlast_reg
<=
temp_m_eth_payload_axis_tlast_reg
;
m_eth_payload_axis_tuser_reg
<=
temp_m_eth_payload_axis_tuser_reg
;
end
if
(
store_eth_payload_int_to_temp
)
begin
temp_m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
temp_m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
temp_m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
temp_m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/rtl/axis_baser_rx_64.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream 10GBASE-R frame receiver (10GBASE-R in, AXI out)
*/
module
axis_baser_rx_64
#
(
parameter
DATA_WIDTH
=
64
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
HDR_WIDTH
=
2
,
parameter
PTP_PERIOD_NS
=
4'h6
,
parameter
PTP_PERIOD_FNS
=
16'h6666
,
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
,
/*
* 10GBASE-R encoded input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
encoded_rx_data
,
input
wire
[
HDR_WIDTH
-
1
:
0
]
encoded_rx_hdr
,
/*
* 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
,
output
wire
m_axis_tlast
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* PTP
*/
input
wire
[
PTP_TS_WIDTH
-
1
:
0
]
ptp_ts
,
/*
* Status
*/
output
wire
[
1
:
0
]
start_packet
,
output
wire
error_bad_frame
,
output
wire
error_bad_fcs
,
output
wire
rx_bad_block
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
64
)
begin
$
error
(
"Error: Interface width must be 64"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
if
(
HDR_WIDTH
!=
2
)
begin
$
error
(
"Error: HDR_WIDTH must be 2"
);
$
finish
;
end
end
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
7
:
0
]
XGMII_IDLE
=
8'h07
,
XGMII_START
=
8'hfb
,
XGMII_TERM
=
8'hfd
,
XGMII_ERROR
=
8'hfe
;
localparam
[
6
:
0
]
CTRL_IDLE
=
7'h00
,
CTRL_LPI
=
7'h06
,
CTRL_ERROR
=
7'h1e
,
CTRL_RES_0
=
7'h2d
,
CTRL_RES_1
=
7'h33
,
CTRL_RES_2
=
7'h4b
,
CTRL_RES_3
=
7'h55
,
CTRL_RES_4
=
7'h66
,
CTRL_RES_5
=
7'h78
;
localparam
[
3
:
0
]
O_SEQ_OS
=
4'h0
,
O_SIG_OS
=
4'hf
;
localparam
[
1
:
0
]
SYNC_DATA
=
2'b10
,
SYNC_CTRL
=
2'b01
;
localparam
[
7
:
0
]
BLOCK_TYPE_CTRL
=
8'h1e
,
// C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4
=
8'h2d
,
// D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4
=
8'h33
,
// D7 D6 D5 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_START
=
8'h66
,
// D7 D6 D5 O0 D3 D2 D1 BT
BLOCK_TYPE_OS_04
=
8'h55
,
// D7 D6 D5 O4 O0 D3 D2 D1 BT
BLOCK_TYPE_START_0
=
8'h78
,
// D7 D6 D5 D4 D3 D2 D1 BT
BLOCK_TYPE_OS_0
=
8'h4b
,
// C7 C6 C5 C4 O0 D3 D2 D1 BT
BLOCK_TYPE_TERM_0
=
8'h87
,
// C7 C6 C5 C4 C3 C2 C1 BT
BLOCK_TYPE_TERM_1
=
8'h99
,
// C7 C6 C5 C4 C3 C2 D0 BT
BLOCK_TYPE_TERM_2
=
8'haa
,
// C7 C6 C5 C4 C3 D1 D0 BT
BLOCK_TYPE_TERM_3
=
8'hb4
,
// C7 C6 C5 C4 D2 D1 D0 BT
BLOCK_TYPE_TERM_4
=
8'hcc
,
// C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5
=
8'hd2
,
// C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6
=
8'he1
,
// C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7
=
8'hff
;
// D6 D5 D4 D3 D2 D1 D0 BT
localparam
[
3
:
0
]
INPUT_TYPE_IDLE
=
4'd0
,
INPUT_TYPE_ERROR
=
4'd1
,
INPUT_TYPE_START_0
=
4'd2
,
INPUT_TYPE_START_4
=
4'd3
,
INPUT_TYPE_DATA
=
4'd4
,
INPUT_TYPE_TERM_0
=
4'd8
,
INPUT_TYPE_TERM_1
=
4'd9
,
INPUT_TYPE_TERM_2
=
4'd10
,
INPUT_TYPE_TERM_3
=
4'd11
,
INPUT_TYPE_TERM_4
=
4'd12
,
INPUT_TYPE_TERM_5
=
4'd13
,
INPUT_TYPE_TERM_6
=
4'd14
,
INPUT_TYPE_TERM_7
=
4'd15
;
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
,
STATE_LAST
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc_last
;
reg
lanes_swapped
=
1'b0
;
reg
[
31
:
0
]
swap_data
=
32'd0
;
reg
delay_type_valid
=
1'b0
;
reg
[
3
:
0
]
delay_type
=
INPUT_TYPE_IDLE
;
reg
[
DATA_WIDTH
-
1
:
0
]
input_data_d0
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
input_data_d1
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
input_data_crc
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
3
:
0
]
input_type_d0
=
INPUT_TYPE_IDLE
;
reg
[
3
:
0
]
input_type_d1
=
INPUT_TYPE_IDLE
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
m_axis_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
m_axis_tkeep_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
[
1
:
0
]
start_packet_reg
=
2'b00
;
reg
error_bad_frame_reg
=
1'b0
,
error_bad_frame_next
;
reg
error_bad_fcs_reg
=
1'b0
,
error_bad_fcs_next
;
reg
rx_bad_block_reg
=
1'b0
;
reg
[
PTP_TS_WIDTH
-
1
:
0
]
ptp_ts_reg
=
0
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
reg
[
31
:
0
]
crc_state3
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next7
;
wire
crc_valid0
=
crc_next0
==
~
32'h2144df1c
;
wire
crc_valid1
=
crc_next1
==
~
32'h2144df1c
;
wire
crc_valid2
=
crc_next2
==
~
32'h2144df1c
;
wire
crc_valid3
=
crc_next3
==
~
32'h2144df1c
;
wire
crc_valid7
=
crc_next7
==
~
32'h2144df1c
;
reg
crc_valid7_save
=
1'b0
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
m_axis_tkeep_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
;
assign
rx_bad_block
=
rx_bad_block_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
(
input_data_crc
[
7
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
input_data_crc
[
15
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
input_data_crc
[
23
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
input_data_crc
[
31
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
input_data_d0
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc_last
=
1'b0
;
m_axis_tdata_next
=
input_data_d1
;
m_axis_tkeep_next
=
8'd0
;
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
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for packet
reset_crc
=
1'b1
;
if
(
input_type_d1
==
INPUT_TYPE_START_0
)
begin
// start condition
reset_crc
=
1'b0
;
state_next
=
STATE_PAYLOAD
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// read payload
m_axis_tdata_next
=
input_data_d1
;
m_axis_tkeep_next
=
8'hff
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b0
;
m_axis_tuser_next
=
1'b0
;
if
(
input_type_d0
==
INPUT_TYPE_DATA
)
begin
state_next
=
STATE_PAYLOAD
;
end
else
if
(
input_type_d0
[
3
])
begin
// INPUT_TYPE_TERM_*
if
(
input_type_d0
<=
INPUT_TYPE_TERM_4
)
begin
// end this cycle
reset_crc
=
1'b1
;
case
(
input_type_d0
)
INPUT_TYPE_TERM_0:
m_axis_tkeep_next
=
8'b00001111
;
INPUT_TYPE_TERM_1:
m_axis_tkeep_next
=
8'b00011111
;
INPUT_TYPE_TERM_2:
m_axis_tkeep_next
=
8'b00111111
;
INPUT_TYPE_TERM_3:
m_axis_tkeep_next
=
8'b01111111
;
INPUT_TYPE_TERM_4:
m_axis_tkeep_next
=
8'b11111111
;
endcase
m_axis_tlast_next
=
1'b1
;
if
((
input_type_d0
==
INPUT_TYPE_TERM_0
&&
crc_valid7_save
)
||
(
input_type_d0
==
INPUT_TYPE_TERM_1
&&
crc_valid0
)
||
(
input_type_d0
==
INPUT_TYPE_TERM_2
&&
crc_valid1
)
||
(
input_type_d0
==
INPUT_TYPE_TERM_3
&&
crc_valid2
)
||
(
input_type_d0
==
INPUT_TYPE_TERM_4
&&
crc_valid3
))
begin
// CRC valid
end
else
begin
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
// need extra cycle
update_crc_last
=
1'b1
;
state_next
=
STATE_LAST
;
end
end
else
begin
// control or error characters in packet
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
reset_crc
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
STATE_LAST:
begin
// last cycle of packet
m_axis_tdata_next
=
input_data_d1
;
m_axis_tkeep_next
=
8'hff
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b0
;
reset_crc
=
1'b1
;
case
(
input_type_d1
)
INPUT_TYPE_TERM_5:
m_axis_tkeep_next
=
8'b00000001
;
INPUT_TYPE_TERM_6:
m_axis_tkeep_next
=
8'b00000011
;
INPUT_TYPE_TERM_7:
m_axis_tkeep_next
=
8'b00000111
;
endcase
if
((
input_type_d1
==
INPUT_TYPE_TERM_5
&&
crc_valid0
)
||
(
input_type_d1
==
INPUT_TYPE_TERM_6
&&
crc_valid1
)
||
(
input_type_d1
==
INPUT_TYPE_TERM_7
&&
crc_valid2
))
begin
// CRC valid
end
else
begin
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
state_next
=
STATE_IDLE
;
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
m_axis_tvalid_reg
<=
1'b0
;
start_packet_reg
<=
2'b00
;
error_bad_frame_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
rx_bad_block_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
crc_state3
<=
32'hFFFFFFFF
;
input_type_d0
<=
INPUT_TYPE_IDLE
;
input_type_d1
<=
INPUT_TYPE_IDLE
;
lanes_swapped
<=
1'b0
;
delay_type_valid
<=
1'b0
;
delay_type
<=
INPUT_TYPE_IDLE
;
end
else
begin
state_reg
<=
state_next
;
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
start_packet_reg
<=
2'b00
;
error_bad_frame_reg
<=
error_bad_frame_next
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
rx_bad_block_reg
<=
1'b0
;
delay_type_valid
<=
1'b0
;
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_0
)
begin
lanes_swapped
<=
1'b0
;
start_packet_reg
<=
2'b01
;
input_type_d0
<=
INPUT_TYPE_START_0
;
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
(
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_4
||
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_OS_START
))
begin
lanes_swapped
<=
1'b1
;
start_packet_reg
<=
2'b10
;
delay_type_valid
<=
1'b1
;
if
(
delay_type_valid
)
begin
input_type_d0
<=
delay_type
;
end
else
begin
input_type_d0
<=
INPUT_TYPE_IDLE
;
end
end
else
if
(
lanes_swapped
)
begin
if
(
delay_type_valid
)
begin
input_type_d0
<=
delay_type
;
end
else
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
input_type_d0
<=
INPUT_TYPE_DATA
;
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
)
begin
case
(
encoded_rx_data
[
7
:
0
])
BLOCK_TYPE_TERM_0:
input_type_d0
<=
INPUT_TYPE_TERM_4
;
BLOCK_TYPE_TERM_1:
input_type_d0
<=
INPUT_TYPE_TERM_5
;
BLOCK_TYPE_TERM_2:
input_type_d0
<=
INPUT_TYPE_TERM_6
;
BLOCK_TYPE_TERM_3:
input_type_d0
<=
INPUT_TYPE_TERM_7
;
BLOCK_TYPE_TERM_4:
begin
delay_type_valid
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_DATA
;
end
BLOCK_TYPE_TERM_5:
begin
delay_type_valid
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_DATA
;
end
BLOCK_TYPE_TERM_6:
begin
delay_type_valid
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_DATA
;
end
BLOCK_TYPE_TERM_7:
begin
delay_type_valid
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_DATA
;
end
default:
begin
rx_bad_block_reg
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_ERROR
;
end
endcase
end
else
begin
rx_bad_block_reg
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_ERROR
;
end
end
else
begin
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
input_type_d0
<=
INPUT_TYPE_DATA
;
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
)
begin
case
(
encoded_rx_data
[
7
:
0
])
BLOCK_TYPE_TERM_0:
input_type_d0
<=
INPUT_TYPE_TERM_0
;
BLOCK_TYPE_TERM_1:
input_type_d0
<=
INPUT_TYPE_TERM_1
;
BLOCK_TYPE_TERM_2:
input_type_d0
<=
INPUT_TYPE_TERM_2
;
BLOCK_TYPE_TERM_3:
input_type_d0
<=
INPUT_TYPE_TERM_3
;
BLOCK_TYPE_TERM_4:
input_type_d0
<=
INPUT_TYPE_TERM_4
;
BLOCK_TYPE_TERM_5:
input_type_d0
<=
INPUT_TYPE_TERM_5
;
BLOCK_TYPE_TERM_6:
input_type_d0
<=
INPUT_TYPE_TERM_6
;
BLOCK_TYPE_TERM_7:
input_type_d0
<=
INPUT_TYPE_TERM_7
;
default:
begin
rx_bad_block_reg
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_ERROR
;
end
endcase
end
else
begin
rx_bad_block_reg
<=
1'b1
;
input_type_d0
<=
INPUT_TYPE_ERROR
;
end
end
input_type_d1
<=
input_type_d0
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
crc_state
<=
crc_next7
;
end
if
(
update_crc_last
)
begin
crc_state3
<=
crc_next3
;
end
else
begin
crc_state3
<=
crc_next7
;
end
end
if
(
PTP_TS_WIDTH
==
96
&&
$
signed
(
{
1'b0
,
ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
)
>
0
)
begin
// ns field rollover
ptp_ts_reg
[
45
:
16
]
<=
$
signed
(
{
1'b0
,
ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts_reg
[
95
:
48
]
+
1
;
end
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_0
)
begin
if
(
PTP_TS_WIDTH
==
96
)
begin
ptp_ts_reg
[
45
:
0
]
<=
ptp_ts
[
45
:
0
]
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts
[
95
:
48
];
end
else
begin
ptp_ts_reg
<=
ptp_ts
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
end
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
(
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_4
||
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_OS_START
))
begin
if
(
PTP_TS_WIDTH
==
96
)
begin
ptp_ts_reg
[
45
:
0
]
<=
ptp_ts
[
45
:
0
]
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts
[
95
:
48
];
end
else
begin
ptp_ts_reg
<=
ptp_ts
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
end
end
m_axis_tdata_reg
<=
m_axis_tdata_next
;
m_axis_tkeep_reg
<=
m_axis_tkeep_next
;
m_axis_tlast_reg
<=
m_axis_tlast_next
;
m_axis_tuser_reg
<=
m_axis_tuser_next
;
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
swap_data
<=
encoded_rx_data
[
63
:
32
];
end
else
begin
swap_data
<=
{
8'd0
,
encoded_rx_data
[
63
:
40
]
}
;
end
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_0
)
begin
input_data_d0
<=
encoded_rx_data
;
input_data_crc
<=
encoded_rx_data
;
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
&&
(
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_START_4
||
encoded_rx_data
[
7
:
0
]
==
BLOCK_TYPE_OS_START
))
begin
input_data_d0
<=
{
encoded_rx_data
[
31
:
0
],
swap_data
}
;
input_data_crc
<=
{
encoded_rx_data
[
31
:
0
],
swap_data
}
;
end
else
if
(
lanes_swapped
)
begin
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
input_data_d0
<=
{
encoded_rx_data
[
31
:
0
],
swap_data
}
;
input_data_crc
<=
{
encoded_rx_data
[
31
:
0
],
swap_data
}
;
end
else
begin
input_data_d0
<=
{
encoded_rx_data
[
39
:
8
],
swap_data
}
;
input_data_crc
<=
{
encoded_rx_data
[
39
:
8
],
swap_data
}
;
end
end
else
begin
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
input_data_d0
<=
encoded_rx_data
;
input_data_crc
<=
encoded_rx_data
;
end
else
begin
input_data_d0
<=
{
8'd0
,
encoded_rx_data
[
63
:
8
]
}
;
input_data_crc
<=
{
8'd0
,
encoded_rx_data
[
63
:
8
]
}
;
end
end
crc_valid7_save
<=
crc_valid7
;
if
(
state_next
==
STATE_LAST
)
begin
input_data_crc
[
31
:
0
]
<=
input_data_crc
[
63
:
32
];
end
input_data_d1
<=
input_data_d0
;
if
(
encoded_rx_hdr
==
SYNC_DATA
)
begin
delay_type
<=
INPUT_TYPE_DATA
;
end
else
if
(
encoded_rx_hdr
==
SYNC_CTRL
)
begin
case
(
encoded_rx_data
[
7
:
0
])
BLOCK_TYPE_START_4:
delay_type
<=
INPUT_TYPE_START_0
;
BLOCK_TYPE_TERM_0:
delay_type
<=
INPUT_TYPE_TERM_4
;
BLOCK_TYPE_TERM_1:
delay_type
<=
INPUT_TYPE_TERM_5
;
BLOCK_TYPE_TERM_2:
delay_type
<=
INPUT_TYPE_TERM_6
;
BLOCK_TYPE_TERM_3:
delay_type
<=
INPUT_TYPE_TERM_7
;
BLOCK_TYPE_TERM_4:
delay_type
<=
INPUT_TYPE_TERM_0
;
BLOCK_TYPE_TERM_5:
delay_type
<=
INPUT_TYPE_TERM_1
;
BLOCK_TYPE_TERM_6:
delay_type
<=
INPUT_TYPE_TERM_2
;
BLOCK_TYPE_TERM_7:
delay_type
<=
INPUT_TYPE_TERM_3
;
default:
delay_type
<=
INPUT_TYPE_ERROR
;
endcase
end
else
begin
delay_type
<=
INPUT_TYPE_ERROR
;
end
end
endmodule
corundum/lib/eth/rtl/axis_baser_tx_64.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream 10GBASE-R frame transmitter (AXI in, 10GBASE-R out)
*/
module
axis_baser_tx_64
#
(
parameter
DATA_WIDTH
=
64
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
HDR_WIDTH
=
2
,
parameter
ENABLE_PADDING
=
1
,
parameter
ENABLE_DIC
=
1
,
parameter
MIN_FRAME_LENGTH
=
64
,
parameter
PTP_PERIOD_NS
=
4'h6
,
parameter
PTP_PERIOD_FNS
=
16'h6666
,
parameter
PTP_TS_ENABLE
=
0
,
parameter
PTP_TS_WIDTH
=
96
,
parameter
PTP_TAG_ENABLE
=
PTP_TS_ENABLE
,
parameter
PTP_TAG_WIDTH
=
16
,
parameter
USER_WIDTH
=
(
PTP_TAG_ENABLE
?
PTP_TAG_WIDTH
:
0
)
+
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI 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
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* 10GBASE-R encoded interface
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
encoded_tx_data
,
output
wire
[
HDR_WIDTH
-
1
:
0
]
encoded_tx_hdr
,
/*
* 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
,
/*
* Configuration
*/
input
wire
[
7
:
0
]
ifg_delay
,
/*
* Status
*/
output
wire
[
1
:
0
]
start_packet
,
output
wire
error_underflow
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
64
)
begin
$
error
(
"Error: Interface width must be 64"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
if
(
HDR_WIDTH
!=
2
)
begin
$
error
(
"Error: HDR_WIDTH must be 2"
);
$
finish
;
end
end
localparam
MIN_FL_NOCRC
=
MIN_FRAME_LENGTH
-
4
;
localparam
MIN_FL_NOCRC_MS
=
MIN_FL_NOCRC
&
16'hfff8
;
localparam
MIN_FL_NOCRC_LS
=
MIN_FL_NOCRC
&
16'h0007
;
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
6
:
0
]
CTRL_IDLE
=
7'h00
,
CTRL_LPI
=
7'h06
,
CTRL_ERROR
=
7'h1e
,
CTRL_RES_0
=
7'h2d
,
CTRL_RES_1
=
7'h33
,
CTRL_RES_2
=
7'h4b
,
CTRL_RES_3
=
7'h55
,
CTRL_RES_4
=
7'h66
,
CTRL_RES_5
=
7'h78
;
localparam
[
3
:
0
]
O_SEQ_OS
=
4'h0
,
O_SIG_OS
=
4'hf
;
localparam
[
1
:
0
]
SYNC_DATA
=
2'b10
,
SYNC_CTRL
=
2'b01
;
localparam
[
7
:
0
]
BLOCK_TYPE_CTRL
=
8'h1e
,
// C7 C6 C5 C4 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_4
=
8'h2d
,
// D7 D6 D5 O4 C3 C2 C1 C0 BT
BLOCK_TYPE_START_4
=
8'h33
,
// D7 D6 D5 C3 C2 C1 C0 BT
BLOCK_TYPE_OS_START
=
8'h66
,
// D7 D6 D5 O0 D3 D2 D1 BT
BLOCK_TYPE_OS_04
=
8'h55
,
// D7 D6 D5 O4 O0 D3 D2 D1 BT
BLOCK_TYPE_START_0
=
8'h78
,
// D7 D6 D5 D4 D3 D2 D1 BT
BLOCK_TYPE_OS_0
=
8'h4b
,
// C7 C6 C5 C4 O0 D3 D2 D1 BT
BLOCK_TYPE_TERM_0
=
8'h87
,
// C7 C6 C5 C4 C3 C2 C1 BT
BLOCK_TYPE_TERM_1
=
8'h99
,
// C7 C6 C5 C4 C3 C2 D0 BT
BLOCK_TYPE_TERM_2
=
8'haa
,
// C7 C6 C5 C4 C3 D1 D0 BT
BLOCK_TYPE_TERM_3
=
8'hb4
,
// C7 C6 C5 C4 D2 D1 D0 BT
BLOCK_TYPE_TERM_4
=
8'hcc
,
// C7 C6 C5 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_5
=
8'hd2
,
// C7 C6 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_6
=
8'he1
,
// C7 D5 D4 D3 D2 D1 D0 BT
BLOCK_TYPE_TERM_7
=
8'hff
;
// D6 D5 D4 D3 D2 D1 D0 BT
localparam
[
3
:
0
]
OUTPUT_TYPE_IDLE
=
4'd0
,
OUTPUT_TYPE_ERROR
=
4'd1
,
OUTPUT_TYPE_START_0
=
4'd2
,
OUTPUT_TYPE_START_4
=
4'd3
,
OUTPUT_TYPE_DATA
=
4'd4
,
OUTPUT_TYPE_TERM_0
=
4'd8
,
OUTPUT_TYPE_TERM_1
=
4'd9
,
OUTPUT_TYPE_TERM_2
=
4'd10
,
OUTPUT_TYPE_TERM_3
=
4'd11
,
OUTPUT_TYPE_TERM_4
=
4'd12
,
OUTPUT_TYPE_TERM_5
=
4'd13
,
OUTPUT_TYPE_TERM_6
=
4'd14
,
OUTPUT_TYPE_TERM_7
=
4'd15
;
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_PAYLOAD
=
3'd1
,
STATE_PAD
=
3'd2
,
STATE_FCS_1
=
3'd3
,
STATE_FCS_2
=
3'd4
,
STATE_IFG
=
3'd5
,
STATE_WAIT_END
=
3'd6
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
swap_lanes
;
reg
unswap_lanes
;
reg
lanes_swapped
=
1'b0
;
reg
[
31
:
0
]
swap_data
=
32'd0
;
reg
delay_type_valid
=
1'b0
;
reg
[
3
:
0
]
delay_type
=
OUTPUT_TYPE_IDLE
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_masked
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
s_tdata_next
;
reg
[
7
:
0
]
s_tkeep_reg
=
8'd0
,
s_tkeep_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_data_0
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_data_1
;
reg
[
3
:
0
]
fcs_output_type_0
;
reg
[
3
:
0
]
fcs_output_type_1
;
reg
[
7
:
0
]
ifg_offset
;
reg
extra_cycle
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
[
7
:
0
]
ifg_count_reg
=
8'd0
,
ifg_count_next
;
reg
[
1
:
0
]
deficit_idle_count_reg
=
2'd0
,
deficit_idle_count_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
m_axis_ptp_ts_valid_int_reg
=
1'b0
,
m_axis_ptp_ts_valid_int_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next4
;
wire
[
31
:
0
]
crc_next5
;
wire
[
31
:
0
]
crc_next6
;
wire
[
31
:
0
]
crc_next7
;
reg
[
DATA_WIDTH
-
1
:
0
]
encoded_tx_data_reg
=
{{
8
{
CTRL_IDLE
}}
,
BLOCK_TYPE_CTRL
}
;
reg
[
HDR_WIDTH
-
1
:
0
]
encoded_tx_hdr_reg
=
SYNC_CTRL
;
reg
[
DATA_WIDTH
-
1
:
0
]
output_data_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
output_data_next
;
reg
[
3
:
0
]
output_type_reg
=
OUTPUT_TYPE_IDLE
,
output_type_next
;
reg
[
1
:
0
]
start_packet_reg
=
2'b00
,
start_packet_next
;
reg
error_underflow_reg
=
1'b0
,
error_underflow_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
encoded_tx_data
=
encoded_tx_data_reg
;
assign
encoded_tx_hdr
=
encoded_tx_hdr_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
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
s_tdata_reg
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
s_tdata_reg
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
s_tdata_reg
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
40
),
.
STYLE
(
"AUTO"
)
)
eth_crc_40
(
.
data_in
(
s_tdata_reg
[
39
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next4
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
48
),
.
STYLE
(
"AUTO"
)
)
eth_crc_48
(
.
data_in
(
s_tdata_reg
[
47
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next5
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
56
),
.
STYLE
(
"AUTO"
)
)
eth_crc_56
(
.
data_in
(
s_tdata_reg
[
55
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next6
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
s_tdata_reg
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
function
[
3
:
0
]
keep2count
;
input
[
7
:
0
]
k
;
casez
(
k
)
8'bzzzzzzz0
:
keep2count
=
4'd0
;
8'bzzzzzz01
:
keep2count
=
4'd1
;
8'bzzzzz011
:
keep2count
=
4'd2
;
8'bzzzz0111
:
keep2count
=
4'd3
;
8'bzzz01111
:
keep2count
=
4'd4
;
8'bzz011111
:
keep2count
=
4'd5
;
8'bz0111111
:
keep2count
=
4'd6
;
8'b01111111
:
keep2count
=
4'd7
;
8'b11111111
:
keep2count
=
4'd8
;
endcase
endfunction
// Mask input data
integer
j
;
always
@*
begin
for
(
j
=
0
;
j
<
8
;
j
=
j
+
1
)
begin
s_axis_tdata_masked
[
j
*
8
+:
8
]
=
s_axis_tkeep
[
j
]
?
s_axis_tdata
[
j
*
8
+:
8
]
:
8'd0
;
end
end
// FCS cycle calculation
always
@*
begin
casez
(
s_tkeep_reg
)
8'bzzzzzz01
:
begin
fcs_output_data_0
=
{
24'd0
,
~
crc_next0
[
31
:
0
],
s_tdata_reg
[
7
:
0
]
}
;
fcs_output_data_1
=
64'd0
;
fcs_output_type_0
=
OUTPUT_TYPE_TERM_5
;
fcs_output_type_1
=
OUTPUT_TYPE_IDLE
;
ifg_offset
=
8'd3
;
extra_cycle
=
1'b0
;
end
8'bzzzzz011
:
begin
fcs_output_data_0
=
{
16'd0
,
~
crc_next1
[
31
:
0
],
s_tdata_reg
[
15
:
0
]
}
;
fcs_output_data_1
=
64'd0
;
fcs_output_type_0
=
OUTPUT_TYPE_TERM_6
;
fcs_output_type_1
=
OUTPUT_TYPE_IDLE
;
ifg_offset
=
8'd2
;
extra_cycle
=
1'b0
;
end
8'bzzzz0111
:
begin
fcs_output_data_0
=
{
8'd0
,
~
crc_next2
[
31
:
0
],
s_tdata_reg
[
23
:
0
]
}
;
fcs_output_data_1
=
64'd0
;
fcs_output_type_0
=
OUTPUT_TYPE_TERM_7
;
fcs_output_type_1
=
OUTPUT_TYPE_IDLE
;
ifg_offset
=
8'd1
;
extra_cycle
=
1'b0
;
end
8'bzzz01111
:
begin
fcs_output_data_0
=
{~
crc_next3
[
31
:
0
],
s_tdata_reg
[
31
:
0
]
}
;
fcs_output_data_1
=
64'd0
;
fcs_output_type_0
=
OUTPUT_TYPE_DATA
;
fcs_output_type_1
=
OUTPUT_TYPE_TERM_0
;
ifg_offset
=
8'd8
;
extra_cycle
=
1'b1
;
end
8'bzz011111
:
begin
fcs_output_data_0
=
{~
crc_next4
[
23
:
0
],
s_tdata_reg
[
39
:
0
]
}
;
fcs_output_data_1
=
{
56'd0
,
~
crc_next4
[
31
:
24
]
}
;
fcs_output_type_0
=
OUTPUT_TYPE_DATA
;
fcs_output_type_1
=
OUTPUT_TYPE_TERM_1
;
ifg_offset
=
8'd7
;
extra_cycle
=
1'b1
;
end
8'bz0111111
:
begin
fcs_output_data_0
=
{~
crc_next5
[
15
:
0
],
s_tdata_reg
[
47
:
0
]
}
;
fcs_output_data_1
=
{
48'd0
,
~
crc_next5
[
31
:
16
]
}
;
fcs_output_type_0
=
OUTPUT_TYPE_DATA
;
fcs_output_type_1
=
OUTPUT_TYPE_TERM_2
;
ifg_offset
=
8'd6
;
extra_cycle
=
1'b1
;
end
8'b01111111
:
begin
fcs_output_data_0
=
{~
crc_next6
[
7
:
0
],
s_tdata_reg
[
55
:
0
]
}
;
fcs_output_data_1
=
{
40'd0
,
~
crc_next6
[
31
:
8
]
}
;
fcs_output_type_0
=
OUTPUT_TYPE_DATA
;
fcs_output_type_1
=
OUTPUT_TYPE_TERM_3
;
ifg_offset
=
8'd5
;
extra_cycle
=
1'b1
;
end
8'b11111111
:
begin
fcs_output_data_0
=
s_tdata_reg
;
fcs_output_data_1
=
{
32'd0
,
~
crc_next7
[
31
:
0
]
}
;
fcs_output_type_0
=
OUTPUT_TYPE_DATA
;
fcs_output_type_1
=
OUTPUT_TYPE_TERM_4
;
ifg_offset
=
8'd4
;
extra_cycle
=
1'b1
;
end
default:
begin
fcs_output_data_0
=
64'd0
;
fcs_output_data_1
=
64'd0
;
fcs_output_type_0
=
OUTPUT_TYPE_ERROR
;
fcs_output_type_1
=
OUTPUT_TYPE_ERROR
;
ifg_offset
=
8'd0
;
extra_cycle
=
1'b1
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
swap_lanes
=
1'b0
;
unswap_lanes
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
ifg_count_next
=
ifg_count_reg
;
deficit_idle_count_next
=
deficit_idle_count_reg
;
s_axis_tready_next
=
1'b0
;
s_tdata_next
=
s_tdata_reg
;
s_tkeep_next
=
s_tkeep_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
;
m_axis_ptp_ts_valid_int_next
=
1'b0
;
output_data_next
=
s_tdata_reg
;
output_type_next
=
OUTPUT_TYPE_IDLE
;
start_packet_next
=
2'b00
;
error_underflow_next
=
1'b0
;
if
(
m_axis_ptp_ts_valid_int_reg
)
begin
m_axis_ptp_ts_valid_next
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
&&
$
signed
(
{
1'b0
,
m_axis_ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
)
>
0
)
begin
// ns field rollover
m_axis_ptp_ts_next
[
45
:
16
]
=
$
signed
(
{
1'b0
,
m_axis_ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
);
m_axis_ptp_ts_next
[
95
:
48
]
=
m_axis_ptp_ts_reg
[
95
:
48
]
+
1
;
end
end
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
frame_ptr_next
=
16'd8
;
reset_crc
=
1'b1
;
s_axis_tready_next
=
1'b1
;
output_data_next
=
s_tdata_reg
;
output_type_next
=
OUTPUT_TYPE_IDLE
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
// XGMII start and preamble
if
(
ifg_count_reg
>
8'd0
)
begin
// need to send more idles - swap lanes
swap_lanes
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
)
begin
m_axis_ptp_ts_next
[
45
:
0
]
=
ptp_ts
[
45
:
0
]
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
m_axis_ptp_ts_next
[
95
:
48
]
=
ptp_ts
[
95
:
48
];
end
else
begin
m_axis_ptp_ts_next
=
ptp_ts
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
end
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_int_next
=
1'b1
;
start_packet_next
=
2'b10
;
end
else
begin
// no more idles - unswap
unswap_lanes
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
)
begin
m_axis_ptp_ts_next
[
45
:
0
]
=
ptp_ts
[
45
:
0
]
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
m_axis_ptp_ts_next
[
95
:
48
]
=
ptp_ts
[
95
:
48
];
end
else
begin
m_axis_ptp_ts_next
=
ptp_ts
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
end
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_int_next
=
1'b1
;
start_packet_next
=
2'b01
;
end
output_data_next
=
{
ETH_SFD
,
{
7
{
ETH_PRE
}}}
;
output_type_next
=
OUTPUT_TYPE_START_0
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_PAYLOAD
;
end
else
begin
ifg_count_next
=
8'd0
;
deficit_idle_count_next
=
2'd0
;
unswap_lanes
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
update_crc
=
1'b1
;
s_axis_tready_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
output_data_next
=
s_tdata_reg
;
output_type_next
=
OUTPUT_TYPE_DATA
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
frame_ptr_next
=
frame_ptr_reg
+
keep2count
(
s_axis_tkeep
);
s_axis_tready_next
=
1'b0
;
if
(
s_axis_tuser
[
0
])
begin
output_type_next
=
OUTPUT_TYPE_ERROR
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd8
;
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_PADDING
&&
(
frame_ptr_reg
<
MIN_FL_NOCRC_MS
||
(
frame_ptr_reg
==
MIN_FL_NOCRC_MS
&&
keep2count
(
s_axis_tkeep
)
<
MIN_FL_NOCRC_LS
)))
begin
s_tkeep_next
=
8'hff
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
8
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
8'hff
>>
((
8
-
MIN_FL_NOCRC_LS
)
%
8
);
state_next
=
STATE_FCS_1
;
end
end
else
begin
state_next
=
STATE_FCS_1
;
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
// tvalid deassert, fail frame
output_type_next
=
OUTPUT_TYPE_ERROR
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd8
;
error_underflow_next
=
1'b1
;
state_next
=
STATE_WAIT_END
;
end
end
STATE_PAD:
begin
// pad frame to MIN_FRAME_LENGTH
s_axis_tready_next
=
1'b0
;
output_data_next
=
s_tdata_reg
;
output_type_next
=
OUTPUT_TYPE_DATA
;
s_tdata_next
=
64'd0
;
s_tkeep_next
=
8'hff
;
update_crc
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
8
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
8'hff
>>
((
8
-
MIN_FL_NOCRC_LS
)
%
8
);
state_next
=
STATE_FCS_1
;
end
end
STATE_FCS_1:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
output_data_next
=
fcs_output_data_0
;
output_type_next
=
fcs_output_type_0
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
(
ifg_delay
>
8'd12
?
ifg_delay
:
8'd12
)
-
ifg_offset
+
(
lanes_swapped
?
8'd4
:
8'd0
)
+
deficit_idle_count_reg
;
if
(
extra_cycle
)
begin
state_next
=
STATE_FCS_2
;
end
else
begin
state_next
=
STATE_IFG
;
end
end
STATE_FCS_2:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
output_data_next
=
fcs_output_data_1
;
output_type_next
=
fcs_output_type_1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
STATE_IFG:
begin
// send IFG
if
(
ifg_count_reg
>
8'd8
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd8
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
STATE_WAIT_END:
begin
// wait for end of frame
s_axis_tready_next
=
1'b1
;
if
(
ifg_count_reg
>
8'd4
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd4
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
16'd0
;
ifg_count_reg
<=
8'd0
;
deficit_idle_count_reg
<=
2'd0
;
s_axis_tready_reg
<=
1'b0
;
m_axis_ptp_ts_valid_reg
<=
1'b0
;
m_axis_ptp_ts_valid_int_reg
<=
1'b0
;
encoded_tx_data_reg
<=
{{
8
{
CTRL_IDLE
}}
,
BLOCK_TYPE_CTRL
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
output_data_reg
<=
{
DATA_WIDTH
{
1'b0
}}
;
output_type_reg
<=
OUTPUT_TYPE_IDLE
;
start_packet_reg
<=
2'b00
;
error_underflow_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
lanes_swapped
<=
1'b0
;
delay_type_valid
<=
1'b0
;
delay_type
<=
OUTPUT_TYPE_IDLE
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
ifg_count_reg
<=
ifg_count_next
;
deficit_idle_count_reg
<=
deficit_idle_count_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
m_axis_ptp_ts_valid_reg
<=
m_axis_ptp_ts_valid_next
;
m_axis_ptp_ts_valid_int_reg
<=
m_axis_ptp_ts_valid_int_next
;
start_packet_reg
<=
start_packet_next
;
error_underflow_reg
<=
error_underflow_next
;
delay_type_valid
<=
1'b0
;
if
(
swap_lanes
||
(
lanes_swapped
&&
!
unswap_lanes
))
begin
lanes_swapped
<=
1'b1
;
output_data_reg
<=
{
output_data_next
[
31
:
0
],
swap_data
}
;
if
(
delay_type_valid
)
begin
output_type_reg
<=
delay_type
;
end
else
if
(
output_type_next
==
OUTPUT_TYPE_START_0
)
begin
output_type_reg
<=
OUTPUT_TYPE_START_4
;
end
else
if
(
output_type_next
[
3
])
begin
// OUTPUT_TYPE_TERM_*
if
(
output_type_next
[
2
])
begin
delay_type_valid
<=
1'b1
;
output_type_reg
<=
OUTPUT_TYPE_DATA
;
end
else
begin
output_type_reg
<=
output_type_next
^
4'd4
;
end
end
else
begin
output_type_reg
<=
output_type_next
;
end
end
else
begin
lanes_swapped
<=
1'b0
;
output_data_reg
<=
output_data_next
;
output_type_reg
<=
output_type_next
;
end
case
(
output_type_reg
)
OUTPUT_TYPE_IDLE:
begin
encoded_tx_data_reg
<=
{{
8
{
CTRL_IDLE
}}
,
BLOCK_TYPE_CTRL
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_ERROR:
begin
encoded_tx_data_reg
<=
{{
8
{
CTRL_ERROR
}}
,
BLOCK_TYPE_CTRL
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_START_0:
begin
encoded_tx_data_reg
<=
{
output_data_reg
[
63
:
8
],
BLOCK_TYPE_START_0
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_START_4:
begin
encoded_tx_data_reg
<=
{
output_data_reg
[
63
:
40
],
4'd0
,
{
4
{
CTRL_IDLE
}}
,
BLOCK_TYPE_START_4
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_DATA:
begin
encoded_tx_data_reg
<=
output_data_reg
;
encoded_tx_hdr_reg
<=
SYNC_DATA
;
end
OUTPUT_TYPE_TERM_0:
begin
encoded_tx_data_reg
<=
{{
7
{
CTRL_IDLE
}}
,
7'd0
,
BLOCK_TYPE_TERM_0
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_1:
begin
encoded_tx_data_reg
<=
{{
6
{
CTRL_IDLE
}}
,
6'd0
,
output_data_reg
[
7
:
0
],
BLOCK_TYPE_TERM_1
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_2:
begin
encoded_tx_data_reg
<=
{{
5
{
CTRL_IDLE
}}
,
5'd0
,
output_data_reg
[
15
:
0
],
BLOCK_TYPE_TERM_2
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_3:
begin
encoded_tx_data_reg
<=
{{
4
{
CTRL_IDLE
}}
,
4'd0
,
output_data_reg
[
23
:
0
],
BLOCK_TYPE_TERM_3
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_4:
begin
encoded_tx_data_reg
<=
{{
3
{
CTRL_IDLE
}}
,
3'd0
,
output_data_reg
[
31
:
0
],
BLOCK_TYPE_TERM_4
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_5:
begin
encoded_tx_data_reg
<=
{{
2
{
CTRL_IDLE
}}
,
2'd0
,
output_data_reg
[
39
:
0
],
BLOCK_TYPE_TERM_5
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_6:
begin
encoded_tx_data_reg
<=
{{
1
{
CTRL_IDLE
}}
,
1'd0
,
output_data_reg
[
47
:
0
],
BLOCK_TYPE_TERM_6
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
OUTPUT_TYPE_TERM_7:
begin
encoded_tx_data_reg
<=
{
output_data_reg
[
55
:
0
],
BLOCK_TYPE_TERM_7
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
default:
begin
encoded_tx_data_reg
<=
{{
8
{
CTRL_ERROR
}}
,
BLOCK_TYPE_CTRL
}
;
encoded_tx_hdr_reg
<=
SYNC_CTRL
;
end
endcase
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next7
;
end
end
s_tdata_reg
<=
s_tdata_next
;
s_tkeep_reg
<=
s_tkeep_next
;
m_axis_ptp_ts_reg
<=
m_axis_ptp_ts_next
;
m_axis_ptp_ts_tag_reg
<=
m_axis_ptp_ts_tag_next
;
swap_data
<=
output_data_next
[
63
:
32
];
delay_type
<=
output_type_next
^
4'd4
;
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS Generator
*/
module
axis_eth_fcs
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
7
:
0
]
s_axis_tdata
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* FCS output
*/
output
wire
[
31
:
0
]
output_fcs
,
output
wire
output_fcs_valid
);
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
reg
[
31
:
0
]
fcs_reg
=
32'h00000000
;
reg
fcs_valid_reg
=
1'b0
;
wire
[
31
:
0
]
crc_next
;
assign
s_axis_tready
=
1
;
assign
output_fcs
=
fcs_reg
;
assign
output_fcs_valid
=
fcs_valid_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_axis_tdata
),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next
)
);
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
crc_state
<=
32'hFFFFFFFF
;
fcs_reg
<=
32'h00000000
;
fcs_valid_reg
<=
1'b0
;
end
else
begin
fcs_valid_reg
<=
1'b0
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
crc_state
<=
32'hFFFFFFFF
;
fcs_reg
<=
~
crc_next
;
fcs_valid_reg
<=
1'b1
;
end
else
begin
crc_state
<=
crc_next
;
end
end
end
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs_64.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS Generator (64 bit datapath)
*/
module
axis_eth_fcs_64
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
63
:
0
]
s_axis_tdata
,
input
wire
[
7
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* FCS output
*/
output
wire
[
31
:
0
]
output_fcs
,
output
wire
output_fcs_valid
);
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
reg
[
31
:
0
]
fcs_reg
=
32'h00000000
;
reg
fcs_valid_reg
=
1'b0
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next4
;
wire
[
31
:
0
]
crc_next5
;
wire
[
31
:
0
]
crc_next6
;
wire
[
31
:
0
]
crc_next7
;
assign
s_axis_tready
=
1'b1
;
assign
output_fcs
=
fcs_reg
;
assign
output_fcs_valid
=
fcs_valid_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_axis_tdata
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
s_axis_tdata
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
s_axis_tdata
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
s_axis_tdata
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
40
),
.
STYLE
(
"AUTO"
)
)
eth_crc_40
(
.
data_in
(
s_axis_tdata
[
39
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next4
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
48
),
.
STYLE
(
"AUTO"
)
)
eth_crc_48
(
.
data_in
(
s_axis_tdata
[
47
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next5
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
56
),
.
STYLE
(
"AUTO"
)
)
eth_crc_56
(
.
data_in
(
s_axis_tdata
[
55
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next6
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
s_axis_tdata
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
crc_state
<=
32'hFFFFFFFF
;
fcs_reg
<=
1'b0
;
fcs_valid_reg
<=
1'b0
;
end
else
begin
fcs_valid_reg
<=
1'b0
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
crc_state
<=
32'hFFFFFFFF
;
case
(
s_axis_tkeep
)
8'b00000001
:
fcs_reg
<=
~
crc_next0
;
8'b00000011
:
fcs_reg
<=
~
crc_next1
;
8'b00000111
:
fcs_reg
<=
~
crc_next2
;
8'b00001111
:
fcs_reg
<=
~
crc_next3
;
8'b00011111
:
fcs_reg
<=
~
crc_next4
;
8'b00111111
:
fcs_reg
<=
~
crc_next5
;
8'b01111111
:
fcs_reg
<=
~
crc_next6
;
8'b11111111
:
fcs_reg
<=
~
crc_next7
;
endcase
fcs_valid_reg
<=
1'b1
;
end
else
begin
crc_state
<=
crc_next7
;
end
end
end
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs_check.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS checker
*/
module
axis_eth_fcs_check
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
7
:
0
]
s_axis_tdata
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
7
:
0
]
m_axis_tdata
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
m_axis_tuser
,
/*
* Status
*/
output
wire
busy
,
output
wire
error_bad_fcs
);
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
shift_in
;
reg
shift_reset
;
reg
[
7
:
0
]
s_axis_tdata_d0
=
8'd0
;
reg
[
7
:
0
]
s_axis_tdata_d1
=
8'd0
;
reg
[
7
:
0
]
s_axis_tdata_d2
=
8'd0
;
reg
[
7
:
0
]
s_axis_tdata_d3
=
8'd0
;
reg
s_axis_tvalid_d0
=
1'b0
;
reg
s_axis_tvalid_d1
=
1'b0
;
reg
s_axis_tvalid_d2
=
1'b0
;
reg
s_axis_tvalid_d3
=
1'b0
;
reg
busy_reg
=
1'b0
;
reg
error_bad_fcs_reg
=
1'b0
,
error_bad_fcs_next
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next
;
// internal datapath
reg
[
7
:
0
]
m_axis_tdata_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_axis_tready
=
s_axis_tready_reg
;
assign
busy
=
busy_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
(
s_axis_tdata_d3
),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next
)
);
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
shift_in
=
1'b0
;
shift_reset
=
1'b0
;
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
error_bad_fcs_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
s_axis_tready_next
=
m_axis_tready_int_early
;
reset_crc
=
1'b1
;
m_axis_tdata_int
=
s_axis_tdata_d3
;
m_axis_tvalid_int
=
s_axis_tvalid_d3
&&
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
shift_in
=
1'b1
;
if
(
s_axis_tvalid_d3
)
begin
reset_crc
=
1'b0
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
shift_reset
=
1'b1
;
reset_crc
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
s_axis_tuser
;
if
(
{
s_axis_tdata
,
s_axis_tdata_d0
,
s_axis_tdata_d1
,
s_axis_tdata_d2
}
!=
~
crc_next
)
begin
m_axis_tuser_int
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
s_axis_tdata_d3
;
m_axis_tvalid_int
=
s_axis_tvalid_d3
&&
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
shift_in
=
1'b1
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
shift_reset
=
1'b1
;
reset_crc
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
s_axis_tuser
;
if
(
{
s_axis_tdata
,
s_axis_tdata_d0
,
s_axis_tdata_d1
,
s_axis_tdata_d2
}
!=
~
crc_next
)
begin
m_axis_tuser_int
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axis_tready_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
s_axis_tvalid_d0
<=
1'b0
;
s_axis_tvalid_d1
<=
1'b0
;
s_axis_tvalid_d2
<=
1'b0
;
s_axis_tvalid_d3
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next
;
end
if
(
shift_reset
)
begin
s_axis_tvalid_d0
<=
1'b0
;
s_axis_tvalid_d1
<=
1'b0
;
s_axis_tvalid_d2
<=
1'b0
;
s_axis_tvalid_d3
<=
1'b0
;
end
else
if
(
shift_in
)
begin
s_axis_tvalid_d0
<=
s_axis_tvalid
;
s_axis_tvalid_d1
<=
s_axis_tvalid_d0
;
s_axis_tvalid_d2
<=
s_axis_tvalid_d1
;
s_axis_tvalid_d3
<=
s_axis_tvalid_d2
;
end
end
if
(
shift_in
)
begin
s_axis_tdata_d0
<=
s_axis_tdata
;
s_axis_tdata_d1
<=
s_axis_tdata_d0
;
s_axis_tdata_d2
<=
s_axis_tdata_d1
;
s_axis_tdata_d3
<=
s_axis_tdata_d2
;
end
end
// output datapath logic
reg
[
7
:
0
]
m_axis_tdata_reg
=
8'd0
;
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
[
7
:
0
]
temp_m_axis_tdata_reg
=
8'd0
;
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_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 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
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
1'b0
;
end
else
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
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_axis_tdata_reg
<=
m_axis_tdata_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_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_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs_check_64.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS checker (64 bit datapath)
*/
module
axis_eth_fcs_check_64
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
63
:
0
]
s_axis_tdata
,
input
wire
[
7
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
63
:
0
]
m_axis_tdata
,
output
wire
[
7
:
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
*/
output
wire
busy
,
output
wire
error_bad_fcs
);
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
,
STATE_LAST
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
shift_in
;
reg
shift_reset
;
reg
[
7
:
0
]
last_cycle_tkeep_reg
=
8'd0
,
last_cycle_tkeep_next
;
reg
last_cycle_tuser_reg
=
1'b0
,
last_cycle_tuser_next
;
reg
[
63
:
0
]
s_axis_tdata_d0
=
64'd0
;
reg
[
7
:
0
]
s_axis_tkeep_d0
=
8'd0
;
reg
s_axis_tvalid_d0
=
1'b0
;
reg
s_axis_tuser_d0
=
1'b0
;
reg
busy_reg
=
1'b0
;
reg
error_bad_fcs_reg
=
1'b0
,
error_bad_fcs_next
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
reg
[
31
:
0
]
crc_state3
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next7
;
wire
crc_valid0
=
crc_next0
==
~
32'h2144df1c
;
wire
crc_valid1
=
crc_next1
==
~
32'h2144df1c
;
wire
crc_valid2
=
crc_next2
==
~
32'h2144df1c
;
wire
crc_valid3
=
crc_next3
==
~
32'h2144df1c
;
// internal datapath
reg
[
63
:
0
]
m_axis_tdata_int
;
reg
[
7
:
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_axis_tready
=
s_axis_tready_reg
;
assign
busy
=
busy_reg
;
assign
error_bad_fcs
=
error_bad_fcs_reg
;
wire
last_cycle
=
state_reg
==
STATE_LAST
;
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
(
last_cycle
?
s_axis_tdata_d0
[
39
:
32
]
:
s_axis_tdata
[
7
:
0
]),
.
state_in
(
last_cycle
?
crc_state3
:
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
last_cycle
?
s_axis_tdata_d0
[
47
:
32
]
:
s_axis_tdata
[
15
:
0
]),
.
state_in
(
last_cycle
?
crc_state3
:
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
last_cycle
?
s_axis_tdata_d0
[
55
:
32
]
:
s_axis_tdata
[
23
:
0
]),
.
state_in
(
last_cycle
?
crc_state3
:
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
last_cycle
?
s_axis_tdata_d0
[
63
:
32
]
:
s_axis_tdata
[
31
:
0
]),
.
state_in
(
last_cycle
?
crc_state3
:
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
s_axis_tdata
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
shift_in
=
1'b0
;
shift_reset
=
1'b0
;
last_cycle_tkeep_next
=
last_cycle_tkeep_reg
;
last_cycle_tuser_next
=
last_cycle_tuser_reg
;
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
64'd0
;
m_axis_tkeep_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
error_bad_fcs_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
s_axis_tready_next
=
m_axis_tready_int_early
;
reset_crc
=
1'b1
;
m_axis_tdata_int
=
s_axis_tdata_d0
;
m_axis_tkeep_int
=
s_axis_tkeep_d0
;
m_axis_tvalid_int
=
s_axis_tvalid_d0
&&
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
shift_in
=
1'b1
;
reset_crc
=
1'b0
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
if
(
s_axis_tkeep
[
7
:
4
]
==
0
)
begin
shift_reset
=
1'b1
;
reset_crc
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
s_axis_tuser
;
m_axis_tkeep_int
=
{
s_axis_tkeep
[
3
:
0
],
4'b1111
}
;
if
((
s_axis_tkeep
[
3
:
0
]
==
4'b0001
&&
crc_valid0
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b0011
&&
crc_valid1
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b0111
&&
crc_valid2
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b1111
&&
crc_valid3
))
begin
// CRC valid
end
else
begin
m_axis_tuser_int
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
else
begin
last_cycle_tkeep_next
=
{
4'b0000
,
s_axis_tkeep
[
7
:
4
]
}
;
last_cycle_tuser_next
=
s_axis_tuser
;
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_LAST
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
s_axis_tdata_d0
;
m_axis_tkeep_int
=
s_axis_tkeep_d0
;
m_axis_tvalid_int
=
s_axis_tvalid_d0
&&
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
shift_in
=
1'b1
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
if
(
s_axis_tkeep
[
7
:
4
]
==
0
)
begin
shift_reset
=
1'b1
;
reset_crc
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
s_axis_tuser
;
m_axis_tkeep_int
=
{
s_axis_tkeep
[
3
:
0
],
4'b1111
}
;
if
((
s_axis_tkeep
[
3
:
0
]
==
4'b0001
&&
crc_valid0
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b0011
&&
crc_valid1
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b0111
&&
crc_valid2
)
||
(
s_axis_tkeep
[
3
:
0
]
==
4'b1111
&&
crc_valid3
))
begin
// CRC valid
end
else
begin
m_axis_tuser_int
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
else
begin
last_cycle_tkeep_next
=
{
4'b0000
,
s_axis_tkeep
[
7
:
4
]
}
;
last_cycle_tuser_next
=
s_axis_tuser
;
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_LAST
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
STATE_LAST:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
s_axis_tdata_d0
;
m_axis_tkeep_int
=
last_cycle_tkeep_reg
;
m_axis_tvalid_int
=
s_axis_tvalid_d0
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
last_cycle_tuser_reg
;
if
((
s_axis_tkeep_d0
[
7
:
4
]
==
4'b0001
&&
crc_valid0
)
||
(
s_axis_tkeep_d0
[
7
:
4
]
==
4'b0011
&&
crc_valid1
)
||
(
s_axis_tkeep_d0
[
7
:
4
]
==
4'b0111
&&
crc_valid2
)
||
(
s_axis_tkeep_d0
[
7
:
4
]
==
4'b1111
&&
crc_valid3
))
begin
// CRC valid
end
else
begin
m_axis_tuser_int
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
if
(
m_axis_tready_int_reg
)
begin
shift_reset
=
1'b1
;
reset_crc
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_LAST
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axis_tready_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
s_axis_tvalid_d0
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
crc_state3
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
crc_state3
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next7
;
crc_state3
<=
crc_next3
;
end
if
(
shift_reset
)
begin
s_axis_tvalid_d0
<=
1'b0
;
end
else
if
(
shift_in
)
begin
s_axis_tvalid_d0
<=
s_axis_tvalid
;
end
end
last_cycle_tkeep_reg
<=
last_cycle_tkeep_next
;
last_cycle_tuser_reg
<=
last_cycle_tuser_next
;
if
(
shift_in
)
begin
s_axis_tdata_d0
<=
s_axis_tdata
;
s_axis_tkeep_d0
<=
s_axis_tkeep
;
s_axis_tuser_d0
<=
s_axis_tuser
;
end
end
// output datapath logic
reg
[
63
:
0
]
m_axis_tdata_reg
=
64'd0
;
reg
[
7
:
0
]
m_axis_tkeep_reg
=
8'd0
;
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
[
63
:
0
]
temp_m_axis_tdata_reg
=
64'd0
;
reg
[
7
:
0
]
temp_m_axis_tkeep_reg
=
8'd0
;
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
=
m_axis_tkeep_reg
;
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 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
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
1'b0
;
end
else
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
;
end
// 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
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs_insert.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS inserter
*/
module
axis_eth_fcs_insert
#
(
parameter
ENABLE_PADDING
=
0
,
parameter
MIN_FRAME_LENGTH
=
64
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
7
:
0
]
s_axis_tdata
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
7
:
0
]
m_axis_tdata
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
m_axis_tuser
,
/*
* Status
*/
output
wire
busy
);
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
,
STATE_PAD
=
2'd2
,
STATE_FCS
=
2'd3
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
busy_reg
=
1'b0
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next
;
// internal datapath
reg
[
7
:
0
]
m_axis_tdata_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_axis_tready
=
s_axis_tready_reg
;
assign
busy
=
busy_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
(
m_axis_tdata_int
),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next
)
);
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
reset_crc
=
1'b1
;
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
frame_ptr_next
=
16'd1
;
reset_crc
=
1'b0
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
if
(
s_axis_tuser
)
begin
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_PADDING
&&
frame_ptr_reg
<
MIN_FRAME_LENGTH
-
5
)
begin
state_next
=
STATE_PAD
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_FCS
;
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
update_crc
=
1'b1
;
if
(
s_axis_tlast
)
begin
if
(
s_axis_tuser
)
begin
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_PADDING
&&
frame_ptr_reg
<
MIN_FRAME_LENGTH
-
5
)
begin
state_next
=
STATE_PAD
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_FCS
;
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
STATE_PAD:
begin
// insert padding
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
8'd0
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
update_crc
=
1'b1
;
if
(
frame_ptr_reg
<
MIN_FRAME_LENGTH
-
5
)
begin
state_next
=
STATE_PAD
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_FCS
;
end
end
else
begin
state_next
=
STATE_PAD
;
end
end
STATE_FCS:
begin
// send FCS
s_axis_tready_next
=
1'b0
;
case
(
frame_ptr_reg
)
2'd0
:
m_axis_tdata_int
=
~
crc_state
[
7
:
0
];
2'd1
:
m_axis_tdata_int
=
~
crc_state
[
15
:
8
];
2'd2
:
m_axis_tdata_int
=
~
crc_state
[
23
:
16
];
2'd3
:
m_axis_tdata_int
=
~
crc_state
[
31
:
24
];
endcase
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
if
(
frame_ptr_reg
<
16'd3
)
begin
state_next
=
STATE_FCS
;
end
else
begin
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_FCS
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
1'b0
;
s_axis_tready_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next
;
end
end
end
// output datapath logic
reg
[
7
:
0
]
m_axis_tdata_reg
=
8'd0
;
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
[
7
:
0
]
temp_m_axis_tdata_reg
=
8'd0
;
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_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 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
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
1'b0
;
end
else
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
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_axis_tdata_reg
<=
m_axis_tdata_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_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_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/rtl/axis_eth_fcs_insert_64.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream Ethernet FCS inserter (64 bit datapath)
*/
module
axis_eth_fcs_insert_64
#
(
parameter
ENABLE_PADDING
=
0
,
parameter
MIN_FRAME_LENGTH
=
64
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
63
:
0
]
s_axis_tdata
,
input
wire
[
7
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
63
:
0
]
m_axis_tdata
,
output
wire
[
7
:
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
*/
output
wire
busy
);
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
,
STATE_PAD
=
2'd2
,
STATE_FCS
=
2'd3
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
[
63
:
0
]
s_axis_tdata_masked
;
reg
[
63
:
0
]
fcs_s_tdata
;
reg
[
7
:
0
]
fcs_s_tkeep
;
reg
[
63
:
0
]
fcs_m_tdata_0
;
reg
[
63
:
0
]
fcs_m_tdata_1
;
reg
[
7
:
0
]
fcs_m_tkeep_0
;
reg
[
7
:
0
]
fcs_m_tkeep_1
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
[
63
:
0
]
last_cycle_tdata_reg
=
64'd0
,
last_cycle_tdata_next
;
reg
[
7
:
0
]
last_cycle_tkeep_reg
=
8'd0
,
last_cycle_tkeep_next
;
reg
busy_reg
=
1'b0
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next4
;
wire
[
31
:
0
]
crc_next5
;
wire
[
31
:
0
]
crc_next6
;
wire
[
31
:
0
]
crc_next7
;
// internal datapath
reg
[
63
:
0
]
m_axis_tdata_int
;
reg
[
7
:
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_axis_tready
=
s_axis_tready_reg
;
assign
busy
=
busy_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
(
fcs_s_tdata
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
fcs_s_tdata
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
fcs_s_tdata
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
fcs_s_tdata
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
40
),
.
STYLE
(
"AUTO"
)
)
eth_crc_40
(
.
data_in
(
fcs_s_tdata
[
39
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next4
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
48
),
.
STYLE
(
"AUTO"
)
)
eth_crc_48
(
.
data_in
(
fcs_s_tdata
[
47
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next5
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
56
),
.
STYLE
(
"AUTO"
)
)
eth_crc_56
(
.
data_in
(
fcs_s_tdata
[
55
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next6
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
fcs_s_tdata
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
function
[
3
:
0
]
keep2count
;
input
[
7
:
0
]
k
;
casez
(
k
)
8'bzzzzzzz0
:
keep2count
=
4'd0
;
8'bzzzzzz01
:
keep2count
=
4'd1
;
8'bzzzzz011
:
keep2count
=
4'd2
;
8'bzzzz0111
:
keep2count
=
4'd3
;
8'bzzz01111
:
keep2count
=
4'd4
;
8'bzz011111
:
keep2count
=
4'd5
;
8'bz0111111
:
keep2count
=
4'd6
;
8'b01111111
:
keep2count
=
4'd7
;
8'b11111111
:
keep2count
=
4'd8
;
endcase
endfunction
function
[
7
:
0
]
count2keep
;
input
[
3
:
0
]
k
;
case
(
k
)
4'd0
:
count2keep
=
8'b00000000
;
4'd1
:
count2keep
=
8'b00000001
;
4'd2
:
count2keep
=
8'b00000011
;
4'd3
:
count2keep
=
8'b00000111
;
4'd4
:
count2keep
=
8'b00001111
;
4'd5
:
count2keep
=
8'b00011111
;
4'd6
:
count2keep
=
8'b00111111
;
4'd7
:
count2keep
=
8'b01111111
;
4'd8
:
count2keep
=
8'b11111111
;
endcase
endfunction
// Mask input data
integer
j
;
always
@*
begin
for
(
j
=
0
;
j
<
8
;
j
=
j
+
1
)
begin
s_axis_tdata_masked
[
j
*
8
+:
8
]
=
s_axis_tkeep
[
j
]
?
s_axis_tdata
[
j
*
8
+:
8
]
:
8'd0
;
end
end
// FCS cycle calculation
always
@*
begin
casez
(
fcs_s_tkeep
)
8'bzzzzzz01
:
begin
fcs_m_tdata_0
=
{
24'd0
,
~
crc_next0
[
31
:
0
],
fcs_s_tdata
[
7
:
0
]
}
;
fcs_m_tdata_1
=
64'd0
;
fcs_m_tkeep_0
=
8'b00011111
;
fcs_m_tkeep_1
=
8'b00000000
;
end
8'bzzzzz011
:
begin
fcs_m_tdata_0
=
{
16'd0
,
~
crc_next1
[
31
:
0
],
fcs_s_tdata
[
15
:
0
]
}
;
fcs_m_tdata_1
=
64'd0
;
fcs_m_tkeep_0
=
8'b00111111
;
fcs_m_tkeep_1
=
8'b00000000
;
end
8'bzzzz0111
:
begin
fcs_m_tdata_0
=
{
8'd0
,
~
crc_next2
[
31
:
0
],
fcs_s_tdata
[
23
:
0
]
}
;
fcs_m_tdata_1
=
64'd0
;
fcs_m_tkeep_0
=
8'b01111111
;
fcs_m_tkeep_1
=
8'b00000000
;
end
8'bzzz01111
:
begin
fcs_m_tdata_0
=
{~
crc_next3
[
31
:
0
],
fcs_s_tdata
[
31
:
0
]
}
;
fcs_m_tdata_1
=
64'd0
;
fcs_m_tkeep_0
=
8'b11111111
;
fcs_m_tkeep_1
=
8'b00000000
;
end
8'bzz011111
:
begin
fcs_m_tdata_0
=
{~
crc_next4
[
23
:
0
],
fcs_s_tdata
[
39
:
0
]
}
;
fcs_m_tdata_1
=
{
56'd0
,
~
crc_next4
[
31
:
24
]
}
;
fcs_m_tkeep_0
=
8'b11111111
;
fcs_m_tkeep_1
=
8'b00000001
;
end
8'bz0111111
:
begin
fcs_m_tdata_0
=
{~
crc_next5
[
15
:
0
],
fcs_s_tdata
[
47
:
0
]
}
;
fcs_m_tdata_1
=
{
48'd0
,
~
crc_next5
[
31
:
16
]
}
;
fcs_m_tkeep_0
=
8'b11111111
;
fcs_m_tkeep_1
=
8'b00000011
;
end
8'b01111111
:
begin
fcs_m_tdata_0
=
{~
crc_next6
[
7
:
0
],
fcs_s_tdata
[
55
:
0
]
}
;
fcs_m_tdata_1
=
{
40'd0
,
~
crc_next6
[
31
:
8
]
}
;
fcs_m_tkeep_0
=
8'b11111111
;
fcs_m_tkeep_1
=
8'b00000111
;
end
8'b11111111
:
begin
fcs_m_tdata_0
=
fcs_s_tdata
;
fcs_m_tdata_1
=
{
32'd0
,
~
crc_next7
[
31
:
0
]
}
;
fcs_m_tkeep_0
=
8'b11111111
;
fcs_m_tkeep_1
=
8'b00001111
;
end
default:
begin
fcs_m_tdata_0
=
64'd0
;
fcs_m_tdata_1
=
64'd0
;
fcs_m_tkeep_0
=
8'd0
;
fcs_m_tkeep_1
=
8'd0
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
last_cycle_tdata_next
=
last_cycle_tdata_reg
;
last_cycle_tkeep_next
=
last_cycle_tkeep_reg
;
s_axis_tready_next
=
1'b0
;
fcs_s_tdata
=
64'd0
;
fcs_s_tkeep
=
8'd0
;
m_axis_tdata_int
=
64'd0
;
m_axis_tkeep_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
reset_crc
=
1'b1
;
m_axis_tdata_int
=
s_axis_tdata_masked
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
fcs_s_tdata
=
s_axis_tdata_masked
;
fcs_s_tkeep
=
s_axis_tkeep
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
reset_crc
=
1'b0
;
update_crc
=
1'b1
;
frame_ptr_next
=
keep2count
(
s_axis_tkeep
);
if
(
s_axis_tlast
)
begin
if
(
s_axis_tuser
)
begin
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
if
(
ENABLE_PADDING
&&
frame_ptr_next
<
MIN_FRAME_LENGTH
-
4
)
begin
m_axis_tkeep_int
=
8'hff
;
fcs_s_tkeep
=
8'hff
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_next
<
MIN_FRAME_LENGTH
-
4
)
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_PAD
;
end
else
begin
m_axis_tkeep_int
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
fcs_s_tkeep
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
m_axis_tdata_int
=
fcs_m_tdata_0
;
last_cycle_tdata_next
=
fcs_m_tdata_1
;
m_axis_tkeep_int
=
fcs_m_tkeep_0
;
last_cycle_tkeep_next
=
fcs_m_tkeep_1
;
reset_crc
=
1'b1
;
if
(
fcs_m_tkeep_1
==
8'd0
)
begin
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
1'b0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_FCS
;
end
end
end
else
begin
m_axis_tdata_int
=
fcs_m_tdata_0
;
last_cycle_tdata_next
=
fcs_m_tdata_1
;
m_axis_tkeep_int
=
fcs_m_tkeep_0
;
last_cycle_tkeep_next
=
fcs_m_tkeep_1
;
reset_crc
=
1'b1
;
if
(
fcs_m_tkeep_1
==
8'd0
)
begin
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_FCS
;
end
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
s_axis_tdata_masked
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
fcs_s_tdata
=
s_axis_tdata_masked
;
fcs_s_tkeep
=
s_axis_tkeep
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
update_crc
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
keep2count
(
s_axis_tkeep
);
if
(
s_axis_tlast
)
begin
if
(
s_axis_tuser
)
begin
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
if
(
ENABLE_PADDING
&&
frame_ptr_next
<
MIN_FRAME_LENGTH
-
4
)
begin
m_axis_tkeep_int
=
8'hff
;
fcs_s_tkeep
=
8'hff
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_next
<
MIN_FRAME_LENGTH
-
4
)
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_PAD
;
end
else
begin
m_axis_tkeep_int
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
fcs_s_tkeep
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
m_axis_tdata_int
=
fcs_m_tdata_0
;
last_cycle_tdata_next
=
fcs_m_tdata_1
;
m_axis_tkeep_int
=
fcs_m_tkeep_0
;
last_cycle_tkeep_next
=
fcs_m_tkeep_1
;
reset_crc
=
1'b1
;
if
(
fcs_m_tkeep_1
==
8'd0
)
begin
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_FCS
;
end
end
end
else
begin
m_axis_tdata_int
=
fcs_m_tdata_0
;
last_cycle_tdata_next
=
fcs_m_tdata_1
;
m_axis_tkeep_int
=
fcs_m_tkeep_0
;
last_cycle_tkeep_next
=
fcs_m_tkeep_1
;
reset_crc
=
1'b1
;
if
(
fcs_m_tkeep_1
==
8'd0
)
begin
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_FCS
;
end
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
STATE_PAD:
begin
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
64'd0
;
m_axis_tkeep_int
=
8'hff
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
fcs_s_tdata
=
64'd0
;
fcs_s_tkeep
=
8'hff
;
if
(
m_axis_tready_int_reg
)
begin
update_crc
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_next
<
MIN_FRAME_LENGTH
-
4
)
begin
state_next
=
STATE_PAD
;
end
else
begin
m_axis_tkeep_int
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
fcs_s_tkeep
=
8'hff
>>
(
8
-
((
MIN_FRAME_LENGTH
-
4
)
&
7
));
m_axis_tdata_int
=
fcs_m_tdata_0
;
last_cycle_tdata_next
=
fcs_m_tdata_1
;
m_axis_tkeep_int
=
fcs_m_tkeep_0
;
last_cycle_tkeep_next
=
fcs_m_tkeep_1
;
reset_crc
=
1'b1
;
if
(
fcs_m_tkeep_1
==
8'd0
)
begin
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IDLE
;
end
else
begin
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_FCS
;
end
end
end
else
begin
state_next
=
STATE_PAD
;
end
end
STATE_FCS:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
last_cycle_tdata_reg
;
m_axis_tkeep_int
=
last_cycle_tkeep_reg
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
reset_crc
=
1'b1
;
s_axis_tready_next
=
m_axis_tready_int_early
;
frame_ptr_next
=
1'b0
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_FCS
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
1'b0
;
s_axis_tready_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next7
;
end
end
last_cycle_tdata_reg
<=
last_cycle_tdata_next
;
last_cycle_tkeep_reg
<=
last_cycle_tkeep_next
;
end
// output datapath logic
reg
[
63
:
0
]
m_axis_tdata_reg
=
64'd0
;
reg
[
7
:
0
]
m_axis_tkeep_reg
=
8'd0
;
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
[
63
:
0
]
temp_m_axis_tdata_reg
=
64'd0
;
reg
[
7
:
0
]
temp_m_axis_tkeep_reg
=
8'd0
;
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
=
m_axis_tkeep_reg
;
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 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
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
1'b0
;
end
else
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
;
end
// 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
end
endmodule
corundum/lib/eth/rtl/axis_gmii_rx.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* 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
,
/*
* 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
mii_locked
=
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_reg
=
1'b0
,
start_packet_next
;
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
,
ptp_ts_next
;
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
;
start_packet_next
=
1'b0
;
error_bad_frame_next
=
1'b0
;
error_bad_fcs_next
=
1'b0
;
ptp_ts_next
=
ptp_ts_reg
;
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
)
begin
ptp_ts_next
=
ptp_ts
;
start_packet_next
=
1'b1
;
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
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
m_axis_tvalid_reg
<=
1'b0
;
start_packet_reg
<=
1'b0
;
error_bad_frame_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
mii_locked
<=
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
else
begin
state_reg
<=
state_next
;
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
start_packet_reg
<=
start_packet_next
;
error_bad_frame_reg
<=
error_bad_frame_next
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next
;
end
if
(
clk_enable
)
begin
if
(
mii_select
)
begin
mii_odd
<=
!
mii_odd
;
if
(
mii_locked
)
begin
mii_locked
<=
gmii_rx_dv
;
end
else
if
(
gmii_rx_dv
&&
{
gmii_rxd
[
3
:
0
],
gmii_rxd_d0
[
7
:
4
]
}
==
ETH_SFD
)
begin
mii_locked
<=
1'b1
;
mii_odd
<=
1'b1
;
end
if
(
mii_odd
)
begin
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
;
end
else
begin
gmii_rx_dv_d0
<=
gmii_rx_dv
;
end
end
else
begin
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
;
end
end
end
ptp_ts_reg
<=
ptp_ts_next
;
m_axis_tdata_reg
<=
m_axis_tdata_next
;
m_axis_tlast_reg
<=
m_axis_tlast_next
;
m_axis_tuser_reg
<=
m_axis_tuser_next
;
// delay input
if
(
clk_enable
)
begin
if
(
mii_select
)
begin
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_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_er_d0
<=
gmii_rx_er
;
end
end
else
begin
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_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
end
endmodule
corundum/lib/eth/rtl/axis_gmii_tx.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* 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_TAG_ENABLE
=
PTP_TS_ENABLE
,
parameter
PTP_TAG_WIDTH
=
16
,
parameter
USER_WIDTH
=
(
PTP_TAG_ENABLE
?
PTP_TAG_WIDTH
:
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
]
ifg_delay
,
/*
* Status
*/
output
wire
start_packet
,
output
wire
error_underflow
);
// 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_WAIT_END
=
3'd6
,
STATE_IFG
=
3'd7
;
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
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_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_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_ptr_next
=
frame_ptr_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
;
gmii_txd_next
=
{
DATA_WIDTH
{
1'b0
}}
;
gmii_tx_en_next
=
1'b0
;
gmii_tx_er_next
=
1'b0
;
start_packet_next
=
1'b0
;
error_underflow_next
=
1'b0
;
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
;
end
else
begin
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for packet
reset_crc
=
1'b1
;
mii_odd_next
=
1'b0
;
if
(
s_axis_tvalid
)
begin
mii_odd_next
=
1'b1
;
frame_ptr_next
=
16'd1
;
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
+
16'd1
;
gmii_txd_next
=
ETH_PRE
;
gmii_tx_en_next
=
1'b1
;
if
(
frame_ptr_reg
==
16'd6
)
begin
s_axis_tready_next
=
1'b1
;
s_tdata_next
=
s_axis_tdata
;
state_next
=
STATE_PREAMBLE
;
end
else
if
(
frame_ptr_reg
==
16'd7
)
begin
// end of preamble; start payload
frame_ptr_next
=
16'd0
;
if
(
s_axis_tready_reg
)
begin
s_axis_tready_next
=
1'b1
;
s_tdata_next
=
s_axis_tdata
;
end
gmii_txd_next
=
ETH_SFD
;
m_axis_ptp_ts_next
=
ptp_ts
;
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_next
=
1'b1
;
start_packet_next
=
1'b1
;
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
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
gmii_txd_next
=
s_tdata_reg
;
gmii_tx_en_next
=
1'b1
;
s_tdata_next
=
s_axis_tdata
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
s_axis_tready_next
=
!
s_axis_tready_reg
;
if
(
s_axis_tuser
[
0
])
begin
gmii_tx_er_next
=
1'b1
;
frame_ptr_next
=
1'b0
;
state_next
=
STATE_IFG
;
end
else
begin
state_next
=
STATE_LAST
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
// tvalid deassert, fail frame
gmii_tx_er_next
=
1'b1
;
frame_ptr_next
=
16'd0
;
error_underflow_next
=
1'b1
;
state_next
=
STATE_WAIT_END
;
end
end
STATE_LAST:
begin
// last payload word
update_crc
=
1'b1
;
mii_odd_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
gmii_txd_next
=
s_tdata_reg
;
gmii_tx_en_next
=
1'b1
;
if
(
ENABLE_PADDING
&&
frame_ptr_reg
<
MIN_FRAME_LENGTH
-
5
)
begin
s_tdata_next
=
8'd0
;
state_next
=
STATE_PAD
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_FCS
;
end
end
STATE_PAD:
begin
// send padding
update_crc
=
1'b1
;
mii_odd_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
gmii_txd_next
=
8'd0
;
gmii_tx_en_next
=
1'b1
;
s_tdata_next
=
8'd0
;
if
(
frame_ptr_reg
<
MIN_FRAME_LENGTH
-
5
)
begin
state_next
=
STATE_PAD
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_FCS
;
end
end
STATE_FCS:
begin
// send FCS
mii_odd_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
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
;
if
(
frame_ptr_reg
<
3
)
begin
state_next
=
STATE_FCS
;
end
else
begin
frame_ptr_next
=
16'd0
;
state_next
=
STATE_IFG
;
end
end
STATE_WAIT_END:
begin
// wait for end of frame
reset_crc
=
1'b1
;
mii_odd_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
s_axis_tready_next
=
1'b1
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
s_axis_tready_next
=
1'b0
;
if
(
frame_ptr_reg
<
ifg_delay
-
1
)
begin
state_next
=
STATE_IFG
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
STATE_IFG:
begin
// send IFG
reset_crc
=
1'b1
;
mii_odd_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd1
;
if
(
frame_ptr_reg
<
ifg_delay
-
1
)
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
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
16'd0
;
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_reg
<=
1'b0
;
error_underflow_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
m_axis_ptp_ts_valid_reg
<=
m_axis_ptp_ts_valid_next
;
gmii_tx_en_reg
<=
gmii_tx_en_next
;
gmii_tx_er_reg
<=
gmii_tx_er_next
;
start_packet_reg
<=
start_packet_next
;
error_underflow_reg
<=
error_underflow_next
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next
;
end
end
m_axis_ptp_ts_reg
<=
m_axis_ptp_ts_next
;
m_axis_ptp_ts_tag_reg
<=
m_axis_ptp_ts_tag_next
;
mii_odd_reg
<=
mii_odd_next
;
mii_msn_reg
<=
mii_msn_next
;
s_tdata_reg
<=
s_tdata_next
;
gmii_txd_reg
<=
gmii_txd_next
;
end
endmodule
corundum/lib/eth/rtl/axis_xgmii_rx_32.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2017 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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream XGMII frame receiver (XGMII in, AXI out)
*/
module
axis_xgmii_rx_32
#
(
parameter
DATA_WIDTH
=
32
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
CTRL_WIDTH
=
(
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
,
/*
* XGMII input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd
,
input
wire
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc
,
/*
* 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
,
output
wire
m_axis_tlast
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* PTP
*/
input
wire
[
PTP_TS_WIDTH
-
1
:
0
]
ptp_ts
,
/*
* Status
*/
output
wire
start_packet
,
output
wire
error_bad_frame
,
output
wire
error_bad_fcs
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
32
)
begin
$
error
(
"Error: Interface width must be 32"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
||
CTRL_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
end
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
7
:
0
]
XGMII_IDLE
=
8'h07
,
XGMII_START
=
8'hfb
,
XGMII_TERM
=
8'hfd
,
XGMII_ERROR
=
8'hfe
;
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PREAMBLE
=
2'd1
,
STATE_PAYLOAD
=
2'd2
,
STATE_LAST
=
2'd3
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
[
3
:
0
]
last_cycle_tkeep_reg
=
4'd0
,
last_cycle_tkeep_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_d0
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_d1
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_d2
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc_d0
=
{
CTRL_WIDTH
{
1'b0
}}
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc_d1
=
{
CTRL_WIDTH
{
1'b0
}}
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc_d2
=
{
CTRL_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
m_axis_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
m_axis_tkeep_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_reg
=
1'b0
,
start_packet_next
;
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
,
ptp_ts_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
crc_valid0
=
crc_next0
==
~
32'h2144df1c
;
wire
crc_valid1
=
crc_next1
==
~
32'h2144df1c
;
wire
crc_valid2
=
crc_next2
==
~
32'h2144df1c
;
wire
crc_valid3
=
crc_next3
==
~
32'h2144df1c
;
reg
crc_valid0_save
=
1'b0
;
reg
crc_valid1_save
=
1'b0
;
reg
crc_valid2_save
=
1'b0
;
reg
crc_valid3_save
=
1'b0
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
m_axis_tkeep_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
;
wire
last_cycle
=
state_reg
==
STATE_LAST
;
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
(
xgmii_rxd_d0
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
xgmii_rxd_d0
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
xgmii_rxd_d0
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
xgmii_rxd_d0
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
// detect control characters
reg
[
3
:
0
]
detect_term
=
4'd0
;
reg
[
3
:
0
]
detect_term_save
;
integer
i
;
// mask errors to within packet
reg
[
3
:
0
]
control_masked
;
reg
[
3
:
0
]
tkeep_mask
;
always
@*
begin
casez
(
detect_term
)
4'b0000
:
begin
control_masked
=
xgmii_rxc_d0
;
tkeep_mask
=
4'b1111
;
end
4'bzzz1
:
begin
control_masked
=
0
;
tkeep_mask
=
4'b0000
;
end
4'bzz10
:
begin
control_masked
=
xgmii_rxc_d0
[
0
];
tkeep_mask
=
4'b0001
;
end
4'bz100
:
begin
control_masked
=
xgmii_rxc_d0
[
1
:
0
];
tkeep_mask
=
4'b0011
;
end
4'b1000
:
begin
control_masked
=
xgmii_rxc_d0
[
2
:
0
];
tkeep_mask
=
4'b0111
;
end
default:
begin
control_masked
=
xgmii_rxc_d0
;
tkeep_mask
=
4'b1111
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
last_cycle_tkeep_next
=
last_cycle_tkeep_reg
;
m_axis_tdata_next
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_next
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tvalid_next
=
1'b0
;
m_axis_tlast_next
=
1'b0
;
m_axis_tuser_next
=
1'b0
;
start_packet_next
=
1'b0
;
error_bad_frame_next
=
1'b0
;
error_bad_fcs_next
=
1'b0
;
ptp_ts_next
=
ptp_ts_reg
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for packet
reset_crc
=
1'b1
;
if
(
xgmii_rxc_d2
[
0
]
&&
xgmii_rxd_d2
[
7
:
0
]
==
XGMII_START
)
begin
// start condition
if
(
control_masked
)
begin
// control or error characters in first data word
m_axis_tdata_next
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_next
=
4'h1
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
reset_crc
=
1'b0
;
state_next
=
STATE_PREAMBLE
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PREAMBLE:
begin
// drop preamble
ptp_ts_next
=
ptp_ts
;
start_packet_next
=
1'b1
;
state_next
=
STATE_PAYLOAD
;
end
STATE_PAYLOAD:
begin
// read payload
m_axis_tdata_next
=
xgmii_rxd_d2
;
m_axis_tkeep_next
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b0
;
m_axis_tuser_next
=
1'b0
;
last_cycle_tkeep_next
=
tkeep_mask
;
if
(
control_masked
)
begin
// control or error characters in packet
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
reset_crc
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
if
(
detect_term
)
begin
if
(
detect_term
[
0
])
begin
// end this cycle
reset_crc
=
1'b1
;
m_axis_tkeep_next
=
4'b1111
;
m_axis_tlast_next
=
1'b1
;
if
(
detect_term
[
0
]
&&
crc_valid3_save
)
begin
// CRC valid
end
else
begin
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
// need extra cycle
state_next
=
STATE_LAST
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
STATE_LAST:
begin
// last cycle of packet
m_axis_tdata_next
=
xgmii_rxd_d2
;
m_axis_tkeep_next
=
last_cycle_tkeep_reg
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b0
;
reset_crc
=
1'b1
;
if
((
detect_term_save
[
1
]
&&
crc_valid0_save
)
||
(
detect_term_save
[
2
]
&&
crc_valid1_save
)
||
(
detect_term_save
[
3
]
&&
crc_valid2_save
))
begin
// CRC valid
end
else
begin
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
state_next
=
STATE_IDLE
;
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
m_axis_tvalid_reg
<=
1'b0
;
start_packet_reg
<=
1'b0
;
error_bad_frame_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
xgmii_rxc_d0
<=
{
CTRL_WIDTH
{
1'b0
}}
;
xgmii_rxc_d1
<=
{
CTRL_WIDTH
{
1'b0
}}
;
end
else
begin
state_reg
<=
state_next
;
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
start_packet_reg
<=
start_packet_next
;
error_bad_frame_reg
<=
error_bad_frame_next
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
xgmii_rxc_d0
<=
xgmii_rxc
;
xgmii_rxc_d1
<=
xgmii_rxc_d0
;
xgmii_rxc_d2
<=
xgmii_rxc_d1
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
crc_state
<=
crc_next3
;
end
end
m_axis_tdata_reg
<=
m_axis_tdata_next
;
m_axis_tkeep_reg
<=
m_axis_tkeep_next
;
m_axis_tlast_reg
<=
m_axis_tlast_next
;
m_axis_tuser_reg
<=
m_axis_tuser_next
;
ptp_ts_reg
<=
ptp_ts_next
;
last_cycle_tkeep_reg
<=
last_cycle_tkeep_next
;
for
(
i
=
0
;
i
<
4
;
i
=
i
+
1
)
begin
detect_term
[
i
]
<=
xgmii_rxc
[
i
]
&&
(
xgmii_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
end
detect_term_save
<=
detect_term
;
crc_valid0_save
<=
crc_valid0
;
crc_valid1_save
<=
crc_valid1
;
crc_valid2_save
<=
crc_valid2
;
crc_valid3_save
<=
crc_valid3
;
xgmii_rxd_d0
<=
xgmii_rxd
;
xgmii_rxd_d1
<=
xgmii_rxd_d0
;
xgmii_rxd_d2
<=
xgmii_rxd_d1
;
end
endmodule
corundum/lib/eth/rtl/axis_xgmii_rx_64.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2017 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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream XGMII frame receiver (XGMII in, AXI out)
*/
module
axis_xgmii_rx_64
#
(
parameter
DATA_WIDTH
=
64
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
CTRL_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
PTP_PERIOD_NS
=
4'h6
,
parameter
PTP_PERIOD_FNS
=
16'h6666
,
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
,
/*
* XGMII input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd
,
input
wire
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc
,
/*
* 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
,
output
wire
m_axis_tlast
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* PTP
*/
input
wire
[
PTP_TS_WIDTH
-
1
:
0
]
ptp_ts
,
/*
* Status
*/
output
wire
[
1
:
0
]
start_packet
,
output
wire
error_bad_frame
,
output
wire
error_bad_fcs
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
64
)
begin
$
error
(
"Error: Interface width must be 64"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
||
CTRL_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
end
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
7
:
0
]
XGMII_IDLE
=
8'h07
,
XGMII_START
=
8'hfb
,
XGMII_TERM
=
8'hfd
,
XGMII_ERROR
=
8'hfe
;
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_PAYLOAD
=
2'd1
,
STATE_LAST
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc_last
;
reg
[
7
:
0
]
last_cycle_tkeep_reg
=
8'd0
,
last_cycle_tkeep_next
;
reg
lanes_swapped
=
1'b0
;
reg
[
31
:
0
]
swap_rxd
=
32'd0
;
reg
[
3
:
0
]
swap_rxc
=
4'd0
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_d0
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_d1
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_rxd_crc
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc_d0
=
{
CTRL_WIDTH
{
1'b0
}}
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_rxc_d1
=
{
CTRL_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
m_axis_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
m_axis_tkeep_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
[
1
:
0
]
start_packet_reg
=
2'b00
;
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
;
reg
[
31
:
0
]
crc_state3
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next7
;
wire
crc_valid0
=
crc_next0
==
~
32'h2144df1c
;
wire
crc_valid1
=
crc_next1
==
~
32'h2144df1c
;
wire
crc_valid2
=
crc_next2
==
~
32'h2144df1c
;
wire
crc_valid3
=
crc_next3
==
~
32'h2144df1c
;
wire
crc_valid7
=
crc_next7
==
~
32'h2144df1c
;
reg
crc_valid7_save
=
1'b0
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
m_axis_tkeep_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
(
xgmii_rxd_crc
[
7
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
xgmii_rxd_crc
[
15
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
xgmii_rxd_crc
[
23
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
xgmii_rxd_crc
[
31
:
0
]),
.
state_in
(
crc_state3
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
xgmii_rxd_crc
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
// detect control characters
reg
[
7
:
0
]
detect_term
=
8'd0
;
reg
[
7
:
0
]
detect_term_save
=
8'd0
;
integer
i
;
// mask errors to within packet
reg
[
7
:
0
]
control_masked
;
reg
[
7
:
0
]
tkeep_mask
;
always
@*
begin
casez
(
detect_term
)
8'b00000000
:
begin
control_masked
=
xgmii_rxc_d0
;
tkeep_mask
=
8'b11111111
;
end
8'bzzzzzzz1
:
begin
control_masked
=
0
;
tkeep_mask
=
8'b00000000
;
end
8'bzzzzzz10
:
begin
control_masked
=
xgmii_rxc_d0
[
0
];
tkeep_mask
=
8'b00000001
;
end
8'bzzzzz100
:
begin
control_masked
=
xgmii_rxc_d0
[
1
:
0
];
tkeep_mask
=
8'b00000011
;
end
8'bzzzz1000
:
begin
control_masked
=
xgmii_rxc_d0
[
2
:
0
];
tkeep_mask
=
8'b00000111
;
end
8'bzzz10000
:
begin
control_masked
=
xgmii_rxc_d0
[
3
:
0
];
tkeep_mask
=
8'b00001111
;
end
8'bzz100000
:
begin
control_masked
=
xgmii_rxc_d0
[
4
:
0
];
tkeep_mask
=
8'b00011111
;
end
8'bz1000000
:
begin
control_masked
=
xgmii_rxc_d0
[
5
:
0
];
tkeep_mask
=
8'b00111111
;
end
8'b10000000
:
begin
control_masked
=
xgmii_rxc_d0
[
6
:
0
];
tkeep_mask
=
8'b01111111
;
end
default:
begin
control_masked
=
xgmii_rxc_d0
;
tkeep_mask
=
8'b11111111
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc_last
=
1'b0
;
last_cycle_tkeep_next
=
last_cycle_tkeep_reg
;
m_axis_tdata_next
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_next
=
{
KEEP_WIDTH
{
1'b1
}}
;
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
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for packet
reset_crc
=
1'b1
;
if
(
xgmii_rxc_d1
[
0
]
&&
xgmii_rxd_d1
[
7
:
0
]
==
XGMII_START
)
begin
// start condition
if
(
control_masked
)
begin
// control or error characters in first data word
m_axis_tdata_next
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_next
=
8'h01
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
reset_crc
=
1'b0
;
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// read payload
m_axis_tdata_next
=
xgmii_rxd_d1
;
m_axis_tkeep_next
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b0
;
m_axis_tuser_next
=
1'b0
;
last_cycle_tkeep_next
=
{
4'b0000
,
tkeep_mask
[
7
:
4
]
}
;
if
(
control_masked
)
begin
// control or error characters in packet
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
reset_crc
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
if
(
detect_term
)
begin
if
(
detect_term
[
4
:
0
])
begin
// end this cycle
reset_crc
=
1'b1
;
m_axis_tkeep_next
=
{
tkeep_mask
[
3
:
0
],
4'b1111
}
;
m_axis_tlast_next
=
1'b1
;
if
((
detect_term
[
0
]
&&
crc_valid7_save
)
||
(
detect_term
[
1
]
&&
crc_valid0
)
||
(
detect_term
[
2
]
&&
crc_valid1
)
||
(
detect_term
[
3
]
&&
crc_valid2
)
||
(
detect_term
[
4
]
&&
crc_valid3
))
begin
// CRC valid
end
else
begin
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
// need extra cycle
update_crc_last
=
1'b1
;
state_next
=
STATE_LAST
;
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
STATE_LAST:
begin
// last cycle of packet
m_axis_tdata_next
=
xgmii_rxd_d1
;
m_axis_tkeep_next
=
last_cycle_tkeep_reg
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b0
;
reset_crc
=
1'b1
;
if
((
detect_term_save
[
5
]
&&
crc_valid0
)
||
(
detect_term_save
[
6
]
&&
crc_valid1
)
||
(
detect_term_save
[
7
]
&&
crc_valid2
))
begin
// CRC valid
end
else
begin
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
error_bad_fcs_next
=
1'b1
;
end
if
(
xgmii_rxc_d1
[
0
]
&&
xgmii_rxd_d1
[
7
:
0
]
==
XGMII_START
)
begin
// start condition
if
(
control_masked
)
begin
// control or error characters in first data word
m_axis_tdata_next
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_next
=
8'h01
;
m_axis_tvalid_next
=
1'b1
;
m_axis_tlast_next
=
1'b1
;
m_axis_tuser_next
=
1'b1
;
error_bad_frame_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
reset_crc
=
1'b0
;
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
m_axis_tvalid_reg
<=
1'b0
;
start_packet_reg
<=
2'b00
;
error_bad_frame_reg
<=
1'b0
;
error_bad_fcs_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
crc_state3
<=
32'hFFFFFFFF
;
xgmii_rxc_d0
<=
{
CTRL_WIDTH
{
1'b0
}}
;
xgmii_rxc_d1
<=
{
CTRL_WIDTH
{
1'b0
}}
;
lanes_swapped
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
start_packet_reg
<=
2'b00
;
error_bad_frame_reg
<=
error_bad_frame_next
;
error_bad_fcs_reg
<=
error_bad_fcs_next
;
if
(
xgmii_rxc
[
0
]
&&
xgmii_rxd
[
7
:
0
]
==
XGMII_START
)
begin
lanes_swapped
<=
1'b0
;
start_packet_reg
<=
2'b01
;
xgmii_rxc_d0
<=
xgmii_rxc
;
end
else
if
(
xgmii_rxc
[
4
]
&&
xgmii_rxd
[
39
:
32
]
==
XGMII_START
)
begin
lanes_swapped
<=
1'b1
;
start_packet_reg
<=
2'b10
;
xgmii_rxc_d0
<=
{
xgmii_rxc
[
3
:
0
],
swap_rxc
}
;
end
else
if
(
lanes_swapped
)
begin
xgmii_rxc_d0
<=
{
xgmii_rxc
[
3
:
0
],
swap_rxc
}
;
end
else
begin
xgmii_rxc_d0
<=
xgmii_rxc
;
end
xgmii_rxc_d1
<=
xgmii_rxc_d0
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
crc_state
<=
crc_next7
;
end
if
(
update_crc_last
)
begin
crc_state3
<=
crc_next3
;
end
else
begin
crc_state3
<=
crc_next7
;
end
end
if
(
PTP_TS_WIDTH
==
96
&&
$
signed
(
{
1'b0
,
ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
)
>
0
)
begin
// ns field rollover
ptp_ts_reg
[
45
:
16
]
<=
$
signed
(
{
1'b0
,
ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts_reg
[
95
:
48
]
+
1
;
end
if
(
xgmii_rxc
[
0
]
&&
xgmii_rxd
[
7
:
0
]
==
XGMII_START
)
begin
if
(
PTP_TS_WIDTH
==
96
)
begin
ptp_ts_reg
[
45
:
0
]
<=
ptp_ts
[
45
:
0
]
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts
[
95
:
48
];
end
else
begin
ptp_ts_reg
<=
ptp_ts
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
end
end
else
if
(
xgmii_rxc
[
4
]
&&
xgmii_rxd
[
39
:
32
]
==
XGMII_START
)
begin
if
(
PTP_TS_WIDTH
==
96
)
begin
ptp_ts_reg
[
45
:
0
]
<=
ptp_ts
[
45
:
0
]
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
ptp_ts_reg
[
95
:
48
]
<=
ptp_ts
[
95
:
48
];
end
else
begin
ptp_ts_reg
<=
ptp_ts
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
end
end
m_axis_tdata_reg
<=
m_axis_tdata_next
;
m_axis_tkeep_reg
<=
m_axis_tkeep_next
;
m_axis_tlast_reg
<=
m_axis_tlast_next
;
m_axis_tuser_reg
<=
m_axis_tuser_next
;
last_cycle_tkeep_reg
<=
last_cycle_tkeep_next
;
detect_term_save
<=
detect_term
;
swap_rxd
<=
xgmii_rxd
[
63
:
32
];
swap_rxc
<=
xgmii_rxc
[
7
:
4
];
if
(
xgmii_rxc
[
0
]
&&
xgmii_rxd
[
7
:
0
]
==
XGMII_START
)
begin
xgmii_rxd_d0
<=
xgmii_rxd
;
xgmii_rxd_crc
<=
xgmii_rxd
;
for
(
i
=
0
;
i
<
8
;
i
=
i
+
1
)
begin
detect_term
[
i
]
<=
xgmii_rxc
[
i
]
&&
(
xgmii_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
end
end
else
if
(
xgmii_rxc
[
4
]
&&
xgmii_rxd
[
39
:
32
]
==
XGMII_START
)
begin
xgmii_rxd_d0
<=
{
xgmii_rxd
[
31
:
0
],
swap_rxd
}
;
xgmii_rxd_crc
<=
{
xgmii_rxd
[
31
:
0
],
swap_rxd
}
;
for
(
i
=
0
;
i
<
4
;
i
=
i
+
1
)
begin
detect_term
[
i
]
<=
swap_rxc
[
i
]
&&
(
swap_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
detect_term
[
i
+
4
]
<=
xgmii_rxc
[
i
]
&&
(
xgmii_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
end
end
else
if
(
lanes_swapped
)
begin
xgmii_rxd_d0
<=
{
xgmii_rxd
[
31
:
0
],
swap_rxd
}
;
xgmii_rxd_crc
<=
{
xgmii_rxd
[
31
:
0
],
swap_rxd
}
;
for
(
i
=
0
;
i
<
4
;
i
=
i
+
1
)
begin
detect_term
[
i
]
<=
swap_rxc
[
i
]
&&
(
swap_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
detect_term
[
i
+
4
]
<=
xgmii_rxc
[
i
]
&&
(
xgmii_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
end
end
else
begin
xgmii_rxd_d0
<=
xgmii_rxd
;
xgmii_rxd_crc
<=
xgmii_rxd
;
for
(
i
=
0
;
i
<
8
;
i
=
i
+
1
)
begin
detect_term
[
i
]
<=
xgmii_rxc
[
i
]
&&
(
xgmii_rxd
[
i
*
8
+:
8
]
==
XGMII_TERM
);
end
end
crc_valid7_save
<=
crc_valid7
;
if
(
state_next
==
STATE_LAST
)
begin
xgmii_rxd_crc
[
31
:
0
]
<=
xgmii_rxd_crc
[
63
:
32
];
end
xgmii_rxd_d1
<=
xgmii_rxd_d0
;
end
endmodule
corundum/lib/eth/rtl/axis_xgmii_tx_32.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2017 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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream XGMII frame transmitter (AXI in, XGMII out)
*/
module
axis_xgmii_tx_32
#
(
parameter
DATA_WIDTH
=
32
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
CTRL_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
ENABLE_PADDING
=
1
,
parameter
ENABLE_DIC
=
1
,
parameter
MIN_FRAME_LENGTH
=
64
,
parameter
PTP_TS_ENABLE
=
0
,
parameter
PTP_TS_WIDTH
=
96
,
parameter
PTP_TAG_ENABLE
=
PTP_TS_ENABLE
,
parameter
PTP_TAG_WIDTH
=
16
,
parameter
USER_WIDTH
=
(
PTP_TAG_ENABLE
?
PTP_TAG_WIDTH
:
0
)
+
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI 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
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* XGMII output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
xgmii_txd
,
output
wire
[
CTRL_WIDTH
-
1
:
0
]
xgmii_txc
,
/*
* 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
,
/*
* Configuration
*/
input
wire
[
7
:
0
]
ifg_delay
,
/*
* Status
*/
output
wire
start_packet
,
output
wire
error_underflow
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
32
)
begin
$
error
(
"Error: Interface width must be 32"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
||
CTRL_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
end
localparam
MIN_FL_NOCRC
=
MIN_FRAME_LENGTH
-
4
;
localparam
MIN_FL_NOCRC_MS
=
MIN_FL_NOCRC
&
16'hfffc
;
localparam
MIN_FL_NOCRC_LS
=
MIN_FL_NOCRC
&
16'h0003
;
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
7
:
0
]
XGMII_IDLE
=
8'h07
,
XGMII_START
=
8'hfb
,
XGMII_TERM
=
8'hfd
,
XGMII_ERROR
=
8'hfe
;
localparam
[
3
:
0
]
STATE_IDLE
=
4'd0
,
STATE_PREAMBLE
=
4'd1
,
STATE_PAYLOAD
=
4'd2
,
STATE_PAD
=
4'd3
,
STATE_FCS_1
=
4'd4
,
STATE_FCS_2
=
4'd5
,
STATE_FCS_3
=
4'd6
,
STATE_IFG
=
4'd7
,
STATE_WAIT_END
=
4'd8
;
reg
[
3
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_masked
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_tdata_reg
={
DATA_WIDTH
{
1'b0
}}
,
s_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
s_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
s_tkeep_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_txd_0
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_txd_1
;
reg
[
CTRL_WIDTH
-
1
:
0
]
fcs_output_txc_0
;
reg
[
CTRL_WIDTH
-
1
:
0
]
fcs_output_txc_1
;
reg
[
7
:
0
]
ifg_offset
;
reg
extra_cycle
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
[
7
:
0
]
ifg_count_reg
=
8'd0
,
ifg_count_next
;
reg
[
1
:
0
]
deficit_idle_count_reg
=
2'd0
,
deficit_idle_count_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
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_txd_reg
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
,
xgmii_txd_next
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_txc_reg
=
{
CTRL_WIDTH
{
1'b1
}}
,
xgmii_txc_next
;
reg
start_packet_reg
=
1'b0
,
start_packet_next
;
reg
error_underflow_reg
=
1'b0
,
error_underflow_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
xgmii_txd
=
xgmii_txd_reg
;
assign
xgmii_txc
=
xgmii_txc_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
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
s_tdata_reg
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
s_tdata_reg
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
s_tdata_reg
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
function
[
2
:
0
]
keep2count
;
input
[
3
:
0
]
k
;
casez
(
k
)
4'bzzz0
:
keep2count
=
3'd0
;
4'bzz01
:
keep2count
=
3'd1
;
4'bz011
:
keep2count
=
3'd2
;
4'b0111
:
keep2count
=
3'd3
;
4'b1111
:
keep2count
=
3'd4
;
endcase
endfunction
// Mask input data
integer
j
;
always
@*
begin
for
(
j
=
0
;
j
<
4
;
j
=
j
+
1
)
begin
s_axis_tdata_masked
[
j
*
8
+:
8
]
=
s_axis_tkeep
[
j
]
?
s_axis_tdata
[
j
*
8
+:
8
]
:
8'd0
;
end
end
// FCS cycle calculation
always
@*
begin
casez
(
s_tkeep_reg
)
4'bzz01
:
begin
fcs_output_txd_0
=
{~
crc_next0
[
23
:
0
],
s_tdata_reg
[
7
:
0
]
}
;
fcs_output_txd_1
=
{{
2
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next0
[
31
:
24
]
}
;
fcs_output_txc_0
=
4'b0000
;
fcs_output_txc_1
=
4'b1110
;
ifg_offset
=
8'd3
;
extra_cycle
=
1'b0
;
end
4'bz011
:
begin
fcs_output_txd_0
=
{~
crc_next1
[
15
:
0
],
s_tdata_reg
[
15
:
0
]
}
;
fcs_output_txd_1
=
{
XGMII_IDLE
,
XGMII_TERM
,
~
crc_next1
[
31
:
16
]
}
;
fcs_output_txc_0
=
4'b0000
;
fcs_output_txc_1
=
4'b1100
;
ifg_offset
=
8'd2
;
extra_cycle
=
1'b0
;
end
4'b0111
:
begin
fcs_output_txd_0
=
{~
crc_next2
[
7
:
0
],
s_tdata_reg
[
23
:
0
]
}
;
fcs_output_txd_1
=
{
XGMII_TERM
,
~
crc_next2
[
31
:
8
]
}
;
fcs_output_txc_0
=
4'b0000
;
fcs_output_txc_1
=
4'b1000
;
ifg_offset
=
8'd1
;
extra_cycle
=
1'b0
;
end
4'b1111
:
begin
fcs_output_txd_0
=
s_tdata_reg
;
fcs_output_txd_1
=
~
crc_next3
;
fcs_output_txc_0
=
4'b0000
;
fcs_output_txc_1
=
4'b0000
;
ifg_offset
=
8'd4
;
extra_cycle
=
1'b1
;
end
default:
begin
fcs_output_txd_0
=
{
CTRL_WIDTH
{
XGMII_ERROR
}}
;
fcs_output_txd_1
=
{
CTRL_WIDTH
{
XGMII_ERROR
}}
;
fcs_output_txc_0
=
{
CTRL_WIDTH
{
1'b1
}}
;
fcs_output_txc_1
=
{
CTRL_WIDTH
{
1'b1
}}
;
ifg_offset
=
8'd0
;
extra_cycle
=
1'b0
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
ifg_count_next
=
ifg_count_reg
;
deficit_idle_count_next
=
deficit_idle_count_reg
;
s_axis_tready_next
=
1'b0
;
s_tdata_next
=
s_tdata_reg
;
s_tkeep_next
=
s_tkeep_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
;
// XGMII idle
xgmii_txd_next
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b1
}}
;
start_packet_next
=
1'b0
;
error_underflow_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
frame_ptr_next
=
16'd4
;
reset_crc
=
1'b1
;
// XGMII idle
xgmii_txd_next
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b1
}}
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
// XGMII start and preamble
xgmii_txd_next
=
{{
3
{
ETH_PRE
}}
,
XGMII_START
}
;
xgmii_txc_next
=
4'b0001
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_PREAMBLE
;
end
else
begin
ifg_count_next
=
8'd0
;
deficit_idle_count_next
=
2'd0
;
state_next
=
STATE_IDLE
;
end
end
STATE_PREAMBLE:
begin
// send preamble
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
xgmii_txd_next
=
{
ETH_SFD
,
{
3
{
ETH_PRE
}}}
;
xgmii_txc_next
=
4'b0000
;
s_axis_tready_next
=
1'b1
;
m_axis_ptp_ts_next
=
ptp_ts
;
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_next
=
1'b1
;
start_packet_next
=
1'b1
;
state_next
=
STATE_PAYLOAD
;
end
STATE_PAYLOAD:
begin
// transfer payload
update_crc
=
1'b1
;
s_axis_tready_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd4
;
xgmii_txd_next
=
s_tdata_reg
;
xgmii_txc_next
=
4'b0000
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
frame_ptr_next
=
frame_ptr_reg
+
keep2count
(
s_axis_tkeep
);
s_axis_tready_next
=
1'b0
;
if
(
s_axis_tuser
[
0
])
begin
xgmii_txd_next
=
{
XGMII_TERM
,
{
3
{
XGMII_ERROR
}}}
;
xgmii_txc_next
=
4'b1111
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd10
;
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_PADDING
&&
(
frame_ptr_reg
<
MIN_FL_NOCRC_MS
||
(
frame_ptr_reg
==
MIN_FL_NOCRC_MS
&&
keep2count
(
s_axis_tkeep
)
<
MIN_FL_NOCRC_LS
)))
begin
s_tkeep_next
=
4'hf
;
frame_ptr_next
=
frame_ptr_reg
+
16'd4
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
4
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
4'hf
>>
((
4
-
MIN_FL_NOCRC_LS
)
%
4
);
state_next
=
STATE_FCS_1
;
end
end
else
begin
state_next
=
STATE_FCS_1
;
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
// tvalid deassert, fail frame
xgmii_txd_next
=
{
XGMII_TERM
,
{
3
{
XGMII_ERROR
}}}
;
xgmii_txc_next
=
4'b1111
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd10
;
error_underflow_next
=
1'b1
;
state_next
=
STATE_WAIT_END
;
end
end
STATE_PAD:
begin
// pad frame to MIN_FRAME_LENGTH
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
s_tdata_reg
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b0
}}
;
s_tdata_next
=
32'd0
;
s_tkeep_next
=
4'hf
;
update_crc
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd4
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
4
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
4'hf
>>
((
4
-
MIN_FL_NOCRC_LS
)
%
4
);
state_next
=
STATE_FCS_1
;
end
end
STATE_FCS_1:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
fcs_output_txd_0
;
xgmii_txc_next
=
fcs_output_txc_0
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
(
ifg_delay
>
8'd12
?
ifg_delay
:
8'd12
)
-
ifg_offset
+
deficit_idle_count_reg
;
state_next
=
STATE_FCS_2
;
end
STATE_FCS_2:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
fcs_output_txd_1
;
xgmii_txc_next
=
fcs_output_txc_1
;
frame_ptr_next
=
16'd0
;
if
(
extra_cycle
)
begin
state_next
=
STATE_FCS_3
;
end
else
begin
state_next
=
STATE_IFG
;
end
end
STATE_FCS_3:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
{{
3
{
XGMII_IDLE
}}
,
XGMII_TERM
}
;
xgmii_txc_next
=
4'b1111
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd3
)
begin
state_next
=
STATE_IFG
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd0
)
begin
state_next
=
STATE_IFG
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
end
STATE_IFG:
begin
// send IFG
if
(
ifg_count_reg
>
8'd4
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd4
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd3
)
begin
state_next
=
STATE_IFG
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd0
)
begin
state_next
=
STATE_IFG
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
end
STATE_WAIT_END:
begin
// wait for end of frame
s_axis_tready_next
=
1'b1
;
if
(
ifg_count_reg
>
8'd4
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd4
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd3
)
begin
state_next
=
STATE_IFG
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd0
)
begin
state_next
=
STATE_IFG
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
16'd0
;
ifg_count_reg
<=
8'd0
;
deficit_idle_count_reg
<=
2'd0
;
s_axis_tready_reg
<=
1'b0
;
m_axis_ptp_ts_valid_reg
<=
1'b0
;
xgmii_txd_reg
<=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_reg
<=
{
CTRL_WIDTH
{
1'b1
}}
;
start_packet_reg
<=
1'b0
;
error_underflow_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
ifg_count_reg
<=
ifg_count_next
;
deficit_idle_count_reg
<=
deficit_idle_count_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
m_axis_ptp_ts_valid_reg
<=
m_axis_ptp_ts_valid_next
;
xgmii_txd_reg
<=
xgmii_txd_next
;
xgmii_txc_reg
<=
xgmii_txc_next
;
start_packet_reg
<=
start_packet_next
;
error_underflow_reg
<=
error_underflow_next
;
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next3
;
end
end
s_tdata_reg
<=
s_tdata_next
;
s_tkeep_reg
<=
s_tkeep_next
;
m_axis_ptp_ts_reg
<=
m_axis_ptp_ts_next
;
m_axis_ptp_ts_tag_reg
<=
m_axis_ptp_ts_tag_next
;
end
endmodule
corundum/lib/eth/rtl/axis_xgmii_tx_64.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2017 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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream XGMII frame transmitter (AXI in, XGMII out)
*/
module
axis_xgmii_tx_64
#
(
parameter
DATA_WIDTH
=
64
,
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
CTRL_WIDTH
=
(
DATA_WIDTH
/
8
),
parameter
ENABLE_PADDING
=
1
,
parameter
ENABLE_DIC
=
1
,
parameter
MIN_FRAME_LENGTH
=
64
,
parameter
PTP_PERIOD_NS
=
4'h6
,
parameter
PTP_PERIOD_FNS
=
16'h6666
,
parameter
PTP_TS_ENABLE
=
0
,
parameter
PTP_TS_WIDTH
=
96
,
parameter
PTP_TAG_ENABLE
=
PTP_TS_ENABLE
,
parameter
PTP_TAG_WIDTH
=
16
,
parameter
USER_WIDTH
=
(
PTP_TAG_ENABLE
?
PTP_TAG_WIDTH
:
0
)
+
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI 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
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* XGMII output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
xgmii_txd
,
output
wire
[
CTRL_WIDTH
-
1
:
0
]
xgmii_txc
,
/*
* 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
,
/*
* Configuration
*/
input
wire
[
7
:
0
]
ifg_delay
,
/*
* Status
*/
output
wire
[
1
:
0
]
start_packet
,
output
wire
error_underflow
);
// bus width assertions
initial
begin
if
(
DATA_WIDTH
!=
64
)
begin
$
error
(
"Error: Interface width must be 64"
);
$
finish
;
end
if
(
KEEP_WIDTH
*
8
!=
DATA_WIDTH
||
CTRL_WIDTH
*
8
!=
DATA_WIDTH
)
begin
$
error
(
"Error: Interface requires byte (8-bit) granularity"
);
$
finish
;
end
end
localparam
MIN_FL_NOCRC
=
MIN_FRAME_LENGTH
-
4
;
localparam
MIN_FL_NOCRC_MS
=
MIN_FL_NOCRC
&
16'hfff8
;
localparam
MIN_FL_NOCRC_LS
=
MIN_FL_NOCRC
&
16'h0007
;
localparam
[
7
:
0
]
ETH_PRE
=
8'h55
,
ETH_SFD
=
8'hD5
;
localparam
[
7
:
0
]
XGMII_IDLE
=
8'h07
,
XGMII_START
=
8'hfb
,
XGMII_TERM
=
8'hfd
,
XGMII_ERROR
=
8'hfe
;
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_PAYLOAD
=
3'd1
,
STATE_PAD
=
3'd2
,
STATE_FCS_1
=
3'd3
,
STATE_FCS_2
=
3'd4
,
STATE_IFG
=
3'd5
,
STATE_WAIT_END
=
3'd6
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
reset_crc
;
reg
update_crc
;
reg
swap_lanes
;
reg
unswap_lanes
;
reg
lanes_swapped
=
1'b0
;
reg
[
31
:
0
]
swap_txd
=
32'd0
;
reg
[
3
:
0
]
swap_txc
=
4'd0
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_masked
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
s_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
s_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
s_tkeep_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_txd_0
;
reg
[
DATA_WIDTH
-
1
:
0
]
fcs_output_txd_1
;
reg
[
CTRL_WIDTH
-
1
:
0
]
fcs_output_txc_0
;
reg
[
CTRL_WIDTH
-
1
:
0
]
fcs_output_txc_1
;
reg
[
7
:
0
]
ifg_offset
;
reg
extra_cycle
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
[
7
:
0
]
ifg_count_reg
=
8'd0
,
ifg_count_next
;
reg
[
1
:
0
]
deficit_idle_count_reg
=
2'd0
,
deficit_idle_count_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
m_axis_ptp_ts_valid_int_reg
=
1'b0
,
m_axis_ptp_ts_valid_int_next
;
reg
[
31
:
0
]
crc_state
=
32'hFFFFFFFF
;
wire
[
31
:
0
]
crc_next0
;
wire
[
31
:
0
]
crc_next1
;
wire
[
31
:
0
]
crc_next2
;
wire
[
31
:
0
]
crc_next3
;
wire
[
31
:
0
]
crc_next4
;
wire
[
31
:
0
]
crc_next5
;
wire
[
31
:
0
]
crc_next6
;
wire
[
31
:
0
]
crc_next7
;
reg
[
DATA_WIDTH
-
1
:
0
]
xgmii_txd_reg
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
,
xgmii_txd_next
;
reg
[
CTRL_WIDTH
-
1
:
0
]
xgmii_txc_reg
=
{
CTRL_WIDTH
{
1'b1
}}
,
xgmii_txc_next
;
reg
start_packet_reg
=
2'b00
,
start_packet_next
;
reg
error_underflow_reg
=
1'b0
,
error_underflow_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
xgmii_txd
=
xgmii_txd_reg
;
assign
xgmii_txc
=
xgmii_txc_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
[
7
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next0
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
16
),
.
STYLE
(
"AUTO"
)
)
eth_crc_16
(
.
data_in
(
s_tdata_reg
[
15
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next1
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
24
),
.
STYLE
(
"AUTO"
)
)
eth_crc_24
(
.
data_in
(
s_tdata_reg
[
23
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next2
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
32
),
.
STYLE
(
"AUTO"
)
)
eth_crc_32
(
.
data_in
(
s_tdata_reg
[
31
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next3
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
40
),
.
STYLE
(
"AUTO"
)
)
eth_crc_40
(
.
data_in
(
s_tdata_reg
[
39
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next4
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
48
),
.
STYLE
(
"AUTO"
)
)
eth_crc_48
(
.
data_in
(
s_tdata_reg
[
47
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next5
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
56
),
.
STYLE
(
"AUTO"
)
)
eth_crc_56
(
.
data_in
(
s_tdata_reg
[
55
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next6
)
);
lfsr
#(
.
LFSR_WIDTH
(
32
),
.
LFSR_POLY
(
32'h4c11db7
),
.
LFSR_CONFIG
(
"GALOIS"
),
.
LFSR_FEED_FORWARD
(
0
),
.
REVERSE
(
1
),
.
DATA_WIDTH
(
64
),
.
STYLE
(
"AUTO"
)
)
eth_crc_64
(
.
data_in
(
s_tdata_reg
[
63
:
0
]),
.
state_in
(
crc_state
),
.
data_out
(),
.
state_out
(
crc_next7
)
);
function
[
3
:
0
]
keep2count
;
input
[
7
:
0
]
k
;
casez
(
k
)
8'bzzzzzzz0
:
keep2count
=
4'd0
;
8'bzzzzzz01
:
keep2count
=
4'd1
;
8'bzzzzz011
:
keep2count
=
4'd2
;
8'bzzzz0111
:
keep2count
=
4'd3
;
8'bzzz01111
:
keep2count
=
4'd4
;
8'bzz011111
:
keep2count
=
4'd5
;
8'bz0111111
:
keep2count
=
4'd6
;
8'b01111111
:
keep2count
=
4'd7
;
8'b11111111
:
keep2count
=
4'd8
;
endcase
endfunction
// Mask input data
integer
j
;
always
@*
begin
for
(
j
=
0
;
j
<
8
;
j
=
j
+
1
)
begin
s_axis_tdata_masked
[
j
*
8
+:
8
]
=
s_axis_tkeep
[
j
]
?
s_axis_tdata
[
j
*
8
+:
8
]
:
8'd0
;
end
end
// FCS cycle calculation
always
@*
begin
casez
(
s_tkeep_reg
)
8'bzzzzzz01
:
begin
fcs_output_txd_0
=
{{
2
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next0
[
31
:
0
],
s_tdata_reg
[
7
:
0
]
}
;
fcs_output_txd_1
=
{
8
{
XGMII_IDLE
}}
;
fcs_output_txc_0
=
8'b11100000
;
fcs_output_txc_1
=
8'b11111111
;
ifg_offset
=
8'd3
;
extra_cycle
=
1'b0
;
end
8'bzzzzz011
:
begin
fcs_output_txd_0
=
{
XGMII_IDLE
,
XGMII_TERM
,
~
crc_next1
[
31
:
0
],
s_tdata_reg
[
15
:
0
]
}
;
fcs_output_txd_1
=
{
8
{
XGMII_IDLE
}}
;
fcs_output_txc_0
=
8'b11000000
;
fcs_output_txc_1
=
8'b11111111
;
ifg_offset
=
8'd2
;
extra_cycle
=
1'b0
;
end
8'bzzzz0111
:
begin
fcs_output_txd_0
=
{
XGMII_TERM
,
~
crc_next2
[
31
:
0
],
s_tdata_reg
[
23
:
0
]
}
;
fcs_output_txd_1
=
{
8
{
XGMII_IDLE
}}
;
fcs_output_txc_0
=
8'b10000000
;
fcs_output_txc_1
=
8'b11111111
;
ifg_offset
=
8'd1
;
extra_cycle
=
1'b0
;
end
8'bzzz01111
:
begin
fcs_output_txd_0
=
{~
crc_next3
[
31
:
0
],
s_tdata_reg
[
31
:
0
]
}
;
fcs_output_txd_1
=
{{
7
{
XGMII_IDLE
}}
,
XGMII_TERM
}
;
fcs_output_txc_0
=
8'b00000000
;
fcs_output_txc_1
=
8'b11111111
;
ifg_offset
=
8'd8
;
extra_cycle
=
1'b1
;
end
8'bzz011111
:
begin
fcs_output_txd_0
=
{~
crc_next4
[
23
:
0
],
s_tdata_reg
[
39
:
0
]
}
;
fcs_output_txd_1
=
{{
6
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next4
[
31
:
24
]
}
;
fcs_output_txc_0
=
8'b00000000
;
fcs_output_txc_1
=
8'b11111110
;
ifg_offset
=
8'd7
;
extra_cycle
=
1'b1
;
end
8'bz0111111
:
begin
fcs_output_txd_0
=
{~
crc_next5
[
15
:
0
],
s_tdata_reg
[
47
:
0
]
}
;
fcs_output_txd_1
=
{{
5
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next5
[
31
:
16
]
}
;
fcs_output_txc_0
=
8'b00000000
;
fcs_output_txc_1
=
8'b11111100
;
ifg_offset
=
8'd6
;
extra_cycle
=
1'b1
;
end
8'b01111111
:
begin
fcs_output_txd_0
=
{~
crc_next6
[
7
:
0
],
s_tdata_reg
[
55
:
0
]
}
;
fcs_output_txd_1
=
{{
4
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next6
[
31
:
8
]
}
;
fcs_output_txc_0
=
8'b00000000
;
fcs_output_txc_1
=
8'b11111000
;
ifg_offset
=
8'd5
;
extra_cycle
=
1'b1
;
end
8'b11111111
:
begin
fcs_output_txd_0
=
s_tdata_reg
;
fcs_output_txd_1
=
{{
3
{
XGMII_IDLE
}}
,
XGMII_TERM
,
~
crc_next7
[
31
:
0
]
}
;
fcs_output_txc_0
=
8'b00000000
;
fcs_output_txc_1
=
8'b11110000
;
ifg_offset
=
8'd4
;
extra_cycle
=
1'b1
;
end
default:
begin
fcs_output_txd_0
=
{
CTRL_WIDTH
{
XGMII_ERROR
}}
;
fcs_output_txd_1
=
{
CTRL_WIDTH
{
XGMII_ERROR
}}
;
fcs_output_txc_0
=
{
CTRL_WIDTH
{
1'b1
}}
;
fcs_output_txc_1
=
{
CTRL_WIDTH
{
1'b1
}}
;
ifg_offset
=
8'd0
;
extra_cycle
=
1'b1
;
end
endcase
end
always
@*
begin
state_next
=
STATE_IDLE
;
reset_crc
=
1'b0
;
update_crc
=
1'b0
;
swap_lanes
=
1'b0
;
unswap_lanes
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
ifg_count_next
=
ifg_count_reg
;
deficit_idle_count_next
=
deficit_idle_count_reg
;
s_axis_tready_next
=
1'b0
;
s_tdata_next
=
s_tdata_reg
;
s_tkeep_next
=
s_tkeep_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
;
m_axis_ptp_ts_valid_int_next
=
1'b0
;
// XGMII idle
xgmii_txd_next
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b1
}}
;
start_packet_next
=
2'b00
;
error_underflow_next
=
1'b0
;
if
(
m_axis_ptp_ts_valid_int_reg
)
begin
m_axis_ptp_ts_valid_next
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
&&
$
signed
(
{
1'b0
,
m_axis_ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
)
>
0
)
begin
// ns field rollover
m_axis_ptp_ts_next
[
45
:
16
]
=
$
signed
(
{
1'b0
,
m_axis_ptp_ts_reg
[
45
:
16
]
}
)
-
$
signed
(
31'd1000000000
);
m_axis_ptp_ts_next
[
95
:
48
]
=
m_axis_ptp_ts_reg
[
95
:
48
]
+
1
;
end
end
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
frame_ptr_next
=
16'd8
;
reset_crc
=
1'b1
;
s_axis_tready_next
=
1'b1
;
// XGMII idle
xgmii_txd_next
=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b1
}}
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
// XGMII start and preamble
if
(
ifg_count_reg
>
8'd0
)
begin
// need to send more idles - swap lanes
swap_lanes
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
)
begin
m_axis_ptp_ts_next
[
45
:
0
]
=
ptp_ts
[
45
:
0
]
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
m_axis_ptp_ts_next
[
95
:
48
]
=
ptp_ts
[
95
:
48
];
end
else
begin
m_axis_ptp_ts_next
=
ptp_ts
+
(((
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
)
*
3
)
>>
1
);
end
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_int_next
=
1'b1
;
start_packet_next
=
2'b10
;
end
else
begin
// no more idles - unswap
unswap_lanes
=
1'b1
;
if
(
PTP_TS_WIDTH
==
96
)
begin
m_axis_ptp_ts_next
[
45
:
0
]
=
ptp_ts
[
45
:
0
]
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
m_axis_ptp_ts_next
[
95
:
48
]
=
ptp_ts
[
95
:
48
];
end
else
begin
m_axis_ptp_ts_next
=
ptp_ts
+
(
PTP_PERIOD_NS
*
2
**
16
+
PTP_PERIOD_FNS
);
end
m_axis_ptp_ts_tag_next
=
s_axis_tuser
>>
1
;
m_axis_ptp_ts_valid_int_next
=
1'b1
;
start_packet_next
=
2'b01
;
end
xgmii_txd_next
=
{
ETH_SFD
,
{
6
{
ETH_PRE
}}
,
XGMII_START
}
;
xgmii_txc_next
=
8'b00000001
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_PAYLOAD
;
end
else
begin
ifg_count_next
=
8'd0
;
deficit_idle_count_next
=
2'd0
;
unswap_lanes
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
STATE_PAYLOAD:
begin
// transfer payload
update_crc
=
1'b1
;
s_axis_tready_next
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
xgmii_txd_next
=
s_tdata_reg
;
xgmii_txc_next
=
8'b00000000
;
s_tdata_next
=
s_axis_tdata_masked
;
s_tkeep_next
=
s_axis_tkeep
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
frame_ptr_next
=
frame_ptr_reg
+
keep2count
(
s_axis_tkeep
);
s_axis_tready_next
=
1'b0
;
if
(
s_axis_tuser
[
0
])
begin
xgmii_txd_next
=
{{
3
{
XGMII_IDLE
}}
,
XGMII_TERM
,
{
4
{
XGMII_ERROR
}}}
;
xgmii_txc_next
=
8'b11111111
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd8
;
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_PADDING
&&
(
frame_ptr_reg
<
MIN_FL_NOCRC_MS
||
(
frame_ptr_reg
==
MIN_FL_NOCRC_MS
&&
keep2count
(
s_axis_tkeep
)
<
MIN_FL_NOCRC_LS
)))
begin
s_tkeep_next
=
8'hff
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
8
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
8'hff
>>
((
8
-
MIN_FL_NOCRC_LS
)
%
8
);
state_next
=
STATE_FCS_1
;
end
end
else
begin
state_next
=
STATE_FCS_1
;
end
end
end
else
begin
state_next
=
STATE_PAYLOAD
;
end
end
else
begin
// tvalid deassert, fail frame
xgmii_txd_next
=
{{
3
{
XGMII_IDLE
}}
,
XGMII_TERM
,
{
4
{
XGMII_ERROR
}}}
;
xgmii_txc_next
=
8'b11111111
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
8'd8
;
error_underflow_next
=
1'b1
;
state_next
=
STATE_WAIT_END
;
end
end
STATE_PAD:
begin
// pad frame to MIN_FRAME_LENGTH
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
s_tdata_reg
;
xgmii_txc_next
=
{
CTRL_WIDTH
{
1'b0
}}
;
s_tdata_next
=
64'd0
;
s_tkeep_next
=
8'hff
;
update_crc
=
1'b1
;
frame_ptr_next
=
frame_ptr_reg
+
16'd8
;
if
(
frame_ptr_reg
<
(
MIN_FL_NOCRC_LS
>
0
?
MIN_FL_NOCRC_MS
:
MIN_FL_NOCRC_MS
-
8
))
begin
state_next
=
STATE_PAD
;
end
else
begin
s_tkeep_next
=
8'hff
>>
((
8
-
MIN_FL_NOCRC_LS
)
%
8
);
state_next
=
STATE_FCS_1
;
end
end
STATE_FCS_1:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
fcs_output_txd_0
;
xgmii_txc_next
=
fcs_output_txc_0
;
frame_ptr_next
=
16'd0
;
ifg_count_next
=
(
ifg_delay
>
8'd12
?
ifg_delay
:
8'd12
)
-
ifg_offset
+
(
lanes_swapped
?
8'd4
:
8'd0
)
+
deficit_idle_count_reg
;
if
(
extra_cycle
)
begin
state_next
=
STATE_FCS_2
;
end
else
begin
state_next
=
STATE_IFG
;
end
end
STATE_FCS_2:
begin
// last cycle
s_axis_tready_next
=
1'b0
;
xgmii_txd_next
=
fcs_output_txd_1
;
xgmii_txc_next
=
fcs_output_txc_1
;
reset_crc
=
1'b1
;
frame_ptr_next
=
16'd0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
STATE_IFG:
begin
// send IFG
if
(
ifg_count_reg
>
8'd8
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd8
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
STATE_WAIT_END:
begin
// wait for end of frame
s_axis_tready_next
=
1'b1
;
if
(
ifg_count_reg
>
8'd8
)
begin
ifg_count_next
=
ifg_count_reg
-
8'd8
;
end
else
begin
ifg_count_next
=
8'd0
;
end
reset_crc
=
1'b1
;
if
(
s_axis_tvalid
)
begin
if
(
s_axis_tlast
)
begin
s_axis_tready_next
=
1'b0
;
if
(
ENABLE_DIC
)
begin
if
(
ifg_count_next
>
8'd7
)
begin
state_next
=
STATE_IFG
;
end
else
begin
if
(
ifg_count_next
>=
8'd4
)
begin
deficit_idle_count_next
=
ifg_count_next
-
8'd4
;
end
else
begin
deficit_idle_count_next
=
ifg_count_next
;
ifg_count_next
=
8'd0
;
end
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
if
(
ifg_count_next
>
8'd4
)
begin
state_next
=
STATE_IFG
;
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
else
begin
state_next
=
STATE_WAIT_END
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
16'd0
;
ifg_count_reg
<=
8'd0
;
deficit_idle_count_reg
<=
2'd0
;
s_axis_tready_reg
<=
1'b0
;
m_axis_ptp_ts_valid_reg
<=
1'b0
;
m_axis_ptp_ts_valid_int_reg
<=
1'b0
;
xgmii_txd_reg
<=
{
CTRL_WIDTH
{
XGMII_IDLE
}}
;
xgmii_txc_reg
<=
{
CTRL_WIDTH
{
1'b1
}}
;
start_packet_reg
<=
2'b00
;
error_underflow_reg
<=
1'b0
;
crc_state
<=
32'hFFFFFFFF
;
lanes_swapped
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
ifg_count_reg
<=
ifg_count_next
;
deficit_idle_count_reg
<=
deficit_idle_count_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
m_axis_ptp_ts_valid_reg
<=
m_axis_ptp_ts_valid_next
;
m_axis_ptp_ts_valid_int_reg
<=
m_axis_ptp_ts_valid_int_next
;
start_packet_reg
<=
start_packet_next
;
error_underflow_reg
<=
error_underflow_next
;
if
(
swap_lanes
||
(
lanes_swapped
&&
!
unswap_lanes
))
begin
lanes_swapped
<=
1'b1
;
xgmii_txd_reg
<=
{
xgmii_txd_next
[
31
:
0
],
swap_txd
}
;
xgmii_txc_reg
<=
{
xgmii_txc_next
[
3
:
0
],
swap_txc
}
;
end
else
begin
lanes_swapped
<=
1'b0
;
xgmii_txd_reg
<=
xgmii_txd_next
;
xgmii_txc_reg
<=
xgmii_txc_next
;
end
// datapath
if
(
reset_crc
)
begin
crc_state
<=
32'hFFFFFFFF
;
end
else
if
(
update_crc
)
begin
crc_state
<=
crc_next7
;
end
end
s_tdata_reg
<=
s_tdata_next
;
s_tkeep_reg
<=
s_tkeep_next
;
m_axis_ptp_ts_reg
<=
m_axis_ptp_ts_next
;
m_axis_ptp_ts_tag_reg
<=
m_axis_ptp_ts_tag_next
;
swap_txd
<=
xgmii_txd_next
[
63
:
32
];
swap_txc
<=
xgmii_txc_next
[
7
:
4
];
end
endmodule
corundum/lib/eth/rtl/eth_arb_mux.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2014-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
`timescale
1
ns
/
1
ps
/*
* Ethernet arbitrated multiplexer
*/
module
eth_arb_mux
#
(
parameter
S_COUNT
=
4
,
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
,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
ARB_TYPE
=
"PRIORITY"
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"HIGH"
)
(
input
wire
clk
,
input
wire
rst
,
/*
* Ethernet frame inputs
*/
input
wire
[
S_COUNT
-
1
:
0
]
s_eth_hdr_valid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_eth_hdr_ready
,
input
wire
[
S_COUNT
*
48
-
1
:
0
]
s_eth_dest_mac
,
input
wire
[
S_COUNT
*
48
-
1
:
0
]
s_eth_src_mac
,
input
wire
[
S_COUNT
*
16
-
1
:
0
]
s_eth_type
,
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_eth_payload_axis_tdata
,
input
wire
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
s_eth_payload_axis_tkeep
,
input
wire
[
S_COUNT
-
1
:
0
]
s_eth_payload_axis_tvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_eth_payload_axis_tready
,
input
wire
[
S_COUNT
-
1
:
0
]
s_eth_payload_axis_tlast
,
input
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_eth_payload_axis_tid
,
input
wire
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
s_eth_payload_axis_tdest
,
input
wire
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
s_eth_payload_axis_tuser
,
/*
* Ethernet frame output
*/
output
wire
m_eth_hdr_valid
,
input
wire
m_eth_hdr_ready
,
output
wire
[
47
:
0
]
m_eth_dest_mac
,
output
wire
[
47
:
0
]
m_eth_src_mac
,
output
wire
[
15
:
0
]
m_eth_type
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep
,
output
wire
m_eth_payload_axis_tvalid
,
input
wire
m_eth_payload_axis_tready
,
output
wire
m_eth_payload_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_eth_payload_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_eth_payload_axis_tuser
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
reg
frame_reg
=
1'b0
,
frame_next
;
reg
s_eth_hdr_ready_mask_reg
=
1'b0
,
s_eth_hdr_ready_mask_next
;
reg
m_eth_hdr_valid_reg
=
1'b0
,
m_eth_hdr_valid_next
;
reg
[
47
:
0
]
m_eth_dest_mac_reg
=
48'd0
,
m_eth_dest_mac_next
;
reg
[
47
:
0
]
m_eth_src_mac_reg
=
48'd0
,
m_eth_src_mac_next
;
reg
[
15
:
0
]
m_eth_type_reg
=
16'd0
,
m_eth_type_next
;
wire
[
S_COUNT
-
1
:
0
]
request
;
wire
[
S_COUNT
-
1
:
0
]
acknowledge
;
wire
[
S_COUNT
-
1
:
0
]
grant
;
wire
grant_valid
;
wire
[
CL_S_COUNT
-
1
:
0
]
grant_encoded
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_int
;
reg
m_eth_payload_axis_tvalid_int
;
reg
m_eth_payload_axis_tready_int_reg
=
1'b0
;
reg
m_eth_payload_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_eth_payload_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_eth_payload_axis_tuser_int
;
wire
m_eth_payload_axis_tready_int_early
;
assign
s_eth_hdr_ready
=
(
!
s_eth_hdr_ready_mask_reg
&&
grant_valid
)
<<
grant_encoded
;
assign
s_eth_payload_axis_tready
=
(
m_eth_payload_axis_tready_int_reg
&&
grant_valid
)
<<
grant_encoded
;
assign
m_eth_hdr_valid
=
m_eth_hdr_valid_reg
;
assign
m_eth_dest_mac
=
m_eth_dest_mac_reg
;
assign
m_eth_src_mac
=
m_eth_src_mac_reg
;
assign
m_eth_type
=
m_eth_type_reg
;
// mux for incoming packet
wire
[
DATA_WIDTH
-
1
:
0
]
current_s_tdata
=
s_eth_payload_axis_tdata
[
grant_encoded
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
current_s_tkeep
=
s_eth_payload_axis_tkeep
[
grant_encoded
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
wire
current_s_tvalid
=
s_eth_payload_axis_tvalid
[
grant_encoded
];
wire
current_s_tready
=
s_eth_payload_axis_tready
[
grant_encoded
];
wire
current_s_tlast
=
s_eth_payload_axis_tlast
[
grant_encoded
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_tid
=
s_eth_payload_axis_tid
[
grant_encoded
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
current_s_tdest
=
s_eth_payload_axis_tdest
[
grant_encoded
*
DEST_WIDTH
+:
DEST_WIDTH
];
wire
[
USER_WIDTH
-
1
:
0
]
current_s_tuser
=
s_eth_payload_axis_tuser
[
grant_encoded
*
USER_WIDTH
+:
USER_WIDTH
];
// arbiter instance
arbiter
#(
.
PORTS
(
S_COUNT
),
.
TYPE
(
ARB_TYPE
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
request
),
.
acknowledge
(
acknowledge
),
.
grant
(
grant
),
.
grant_valid
(
grant_valid
),
.
grant_encoded
(
grant_encoded
)
);
assign
request
=
s_eth_hdr_valid
&
~
grant
;
assign
acknowledge
=
grant
&
s_eth_payload_axis_tvalid
&
s_eth_payload_axis_tready
&
s_eth_payload_axis_tlast
;
always
@*
begin
frame_next
=
frame_reg
;
s_eth_hdr_ready_mask_next
=
s_eth_hdr_ready_mask_reg
;
m_eth_hdr_valid_next
=
m_eth_hdr_valid_reg
&&
!
m_eth_hdr_ready
;
m_eth_dest_mac_next
=
m_eth_dest_mac_reg
;
m_eth_src_mac_next
=
m_eth_src_mac_reg
;
m_eth_type_next
=
m_eth_type_reg
;
if
(
s_eth_payload_axis_tvalid
[
grant_encoded
]
&&
s_eth_payload_axis_tready
[
grant_encoded
])
begin
// end of frame detection
if
(
s_eth_payload_axis_tlast
[
grant_encoded
])
begin
frame_next
=
1'b0
;
s_eth_hdr_ready_mask_next
=
1'b0
;
end
end
if
(
!
frame_reg
&&
grant_valid
)
begin
// start of frame
frame_next
=
1'b1
;
s_eth_hdr_ready_mask_next
=
1'b1
;
m_eth_hdr_valid_next
=
1'b1
;
m_eth_dest_mac_next
=
s_eth_dest_mac
[
grant_encoded
*
48
+:
48
];
m_eth_src_mac_next
=
s_eth_src_mac
[
grant_encoded
*
48
+:
48
];
m_eth_type_next
=
s_eth_type
[
grant_encoded
*
16
+:
16
];
end
// pass through selected packet data
m_eth_payload_axis_tdata_int
=
current_s_tdata
;
m_eth_payload_axis_tkeep_int
=
current_s_tkeep
;
m_eth_payload_axis_tvalid_int
=
current_s_tvalid
&&
m_eth_payload_axis_tready_int_reg
&&
grant_valid
;
m_eth_payload_axis_tlast_int
=
current_s_tlast
;
m_eth_payload_axis_tid_int
=
current_s_tid
;
m_eth_payload_axis_tdest_int
=
current_s_tdest
;
m_eth_payload_axis_tuser_int
=
current_s_tuser
;
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
frame_reg
<=
1'b0
;
s_eth_hdr_ready_mask_reg
<=
1'b0
;
m_eth_hdr_valid_reg
<=
1'b0
;
end
else
begin
frame_reg
<=
frame_next
;
s_eth_hdr_ready_mask_reg
<=
s_eth_hdr_ready_mask_next
;
m_eth_hdr_valid_reg
<=
m_eth_hdr_valid_next
;
end
m_eth_dest_mac_reg
<=
m_eth_dest_mac_next
;
m_eth_src_mac_reg
<=
m_eth_src_mac_next
;
m_eth_type_reg
<=
m_eth_type_next
;
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_eth_payload_axis_tvalid_reg
=
1'b0
,
m_eth_payload_axis_tvalid_next
;
reg
m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_eth_payload_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_eth_payload_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_eth_payload_axis_tvalid_reg
=
1'b0
,
temp_m_eth_payload_axis_tvalid_next
;
reg
temp_m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_eth_payload_axis_temp_to_output
;
assign
m_eth_payload_axis_tdata
=
m_eth_payload_axis_tdata_reg
;
assign
m_eth_payload_axis_tkeep
=
KEEP_ENABLE
?
m_eth_payload_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_eth_payload_axis_tvalid
=
m_eth_payload_axis_tvalid_reg
;
assign
m_eth_payload_axis_tlast
=
m_eth_payload_axis_tlast_reg
;
assign
m_eth_payload_axis_tid
=
ID_ENABLE
?
m_eth_payload_axis_tid_reg
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_eth_payload_axis_tdest
=
DEST_ENABLE
?
m_eth_payload_axis_tdest_reg
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_eth_payload_axis_tuser
=
USER_ENABLE
?
m_eth_payload_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_eth_payload_axis_tready_int_early
=
m_eth_payload_axis_tready
||
(
!
temp_m_eth_payload_axis_tvalid_reg
&&
(
!
m_eth_payload_axis_tvalid_reg
||
!
m_eth_payload_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b0
;
if
(
m_eth_payload_axis_tready_int_reg
)
begin
// input is ready
if
(
m_eth_payload_axis_tready
||
!
m_eth_payload_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_eth_payload_axis_tready
)
begin
// input is not ready, but output is ready
m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_eth_payload_axis_tvalid_reg
<=
1'b0
;
m_eth_payload_axis_tready_int_reg
<=
1'b0
;
temp_m_eth_payload_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_eth_payload_axis_tvalid_reg
<=
m_eth_payload_axis_tvalid_next
;
m_eth_payload_axis_tready_int_reg
<=
m_eth_payload_axis_tready_int_early
;
temp_m_eth_payload_axis_tvalid_reg
<=
temp_m_eth_payload_axis_tvalid_next
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
m_eth_payload_axis_tid_reg
<=
m_eth_payload_axis_tid_int
;
m_eth_payload_axis_tdest_reg
<=
m_eth_payload_axis_tdest_int
;
m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
else
if
(
store_eth_payload_axis_temp_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
temp_m_eth_payload_axis_tdata_reg
;
m_eth_payload_axis_tkeep_reg
<=
temp_m_eth_payload_axis_tkeep_reg
;
m_eth_payload_axis_tlast_reg
<=
temp_m_eth_payload_axis_tlast_reg
;
m_eth_payload_axis_tid_reg
<=
temp_m_eth_payload_axis_tid_reg
;
m_eth_payload_axis_tdest_reg
<=
temp_m_eth_payload_axis_tdest_reg
;
m_eth_payload_axis_tuser_reg
<=
temp_m_eth_payload_axis_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
temp_m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
temp_m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
temp_m_eth_payload_axis_tid_reg
<=
m_eth_payload_axis_tid_int
;
temp_m_eth_payload_axis_tdest_reg
<=
m_eth_payload_axis_tdest_int
;
temp_m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/rtl/eth_axis_rx.v
0 → 100644
View file @
738c1fef
/*
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
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream ethernet frame receiver (AXI in, Ethernet frame out)
*/
module
eth_axis_rx
#
(
// 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
,
/*
* AXI 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
s_axis_tuser
,
/*
* Ethernet frame output
*/
output
wire
m_eth_hdr_valid
,
input
wire
m_eth_hdr_ready
,
output
wire
[
47
:
0
]
m_eth_dest_mac
,
output
wire
[
47
:
0
]
m_eth_src_mac
,
output
wire
[
15
:
0
]
m_eth_type
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep
,
output
wire
m_eth_payload_axis_tvalid
,
input
wire
m_eth_payload_axis_tready
,
output
wire
m_eth_payload_axis_tlast
,
output
wire
m_eth_payload_axis_tuser
,
/*
* Status signals
*/
output
wire
busy
,
output
wire
error_header_early_termination
);
parameter
CYCLE_COUNT
=
(
14
+
KEEP_WIDTH
-
1
)
/
KEEP_WIDTH
;
parameter
PTR_WIDTH
=
$
clog2
(
CYCLE_COUNT
);
parameter
OFFSET
=
14
%
KEEP_WIDTH
;
// bus width assertions
initial
begin
if
(
KEEP_WIDTH
*
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 on an AXI stream interface, decodes
and strips the headers, then produces the header fields in parallel along
with the payload in a separate AXI stream.
*/
reg
read_eth_header_reg
=
1'b1
,
read_eth_header_next
;
reg
read_eth_payload_reg
=
1'b0
,
read_eth_payload_next
;
reg
[
PTR_WIDTH
-
1
:
0
]
ptr_reg
=
0
,
ptr_next
;
reg
flush_save
;
reg
transfer_in_save
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
m_eth_hdr_valid_reg
=
1'b0
,
m_eth_hdr_valid_next
;
reg
[
47
:
0
]
m_eth_dest_mac_reg
=
48'd0
,
m_eth_dest_mac_next
;
reg
[
47
:
0
]
m_eth_src_mac_reg
=
48'd0
,
m_eth_src_mac_next
;
reg
[
15
:
0
]
m_eth_type_reg
=
16'd0
,
m_eth_type_next
;
reg
busy_reg
=
1'b0
;
reg
error_header_early_termination_reg
=
1'b0
,
error_header_early_termination_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
save_axis_tdata_reg
=
64'd0
;
reg
[
KEEP_WIDTH
-
1
:
0
]
save_axis_tkeep_reg
=
8'd0
;
reg
save_axis_tlast_reg
=
1'b0
;
reg
save_axis_tuser_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
shift_axis_tdata
;
reg
[
KEEP_WIDTH
-
1
:
0
]
shift_axis_tkeep
;
reg
shift_axis_tvalid
;
reg
shift_axis_tlast
;
reg
shift_axis_tuser
;
reg
shift_axis_input_tready
;
reg
shift_axis_extra_cycle_reg
=
1'b0
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_int
;
reg
m_eth_payload_axis_tvalid_int
;
reg
m_eth_payload_axis_tready_int_reg
=
1'b0
;
reg
m_eth_payload_axis_tlast_int
;
reg
m_eth_payload_axis_tuser_int
;
wire
m_eth_payload_axis_tready_int_early
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
m_eth_hdr_valid
=
m_eth_hdr_valid_reg
;
assign
m_eth_dest_mac
=
m_eth_dest_mac_reg
;
assign
m_eth_src_mac
=
m_eth_src_mac_reg
;
assign
m_eth_type
=
m_eth_type_reg
;
assign
busy
=
busy_reg
;
assign
error_header_early_termination
=
error_header_early_termination_reg
;
always
@*
begin
if
(
OFFSET
==
0
)
begin
// passthrough if no overlap
shift_axis_tdata
=
s_axis_tdata
;
shift_axis_tkeep
=
s_axis_tkeep
;
shift_axis_tvalid
=
s_axis_tvalid
;
shift_axis_tlast
=
s_axis_tlast
;
shift_axis_tuser
=
s_axis_tuser
;
shift_axis_input_tready
=
1'b1
;
end
else
if
(
shift_axis_extra_cycle_reg
)
begin
shift_axis_tdata
=
{
s_axis_tdata
,
save_axis_tdata_reg
}
>>
(
OFFSET
*
8
);
shift_axis_tkeep
=
{{
KEEP_WIDTH
{
1'b0
}}
,
save_axis_tkeep_reg
}
>>
OFFSET
;
shift_axis_tvalid
=
1'b1
;
shift_axis_tlast
=
save_axis_tlast_reg
;
shift_axis_tuser
=
save_axis_tuser_reg
;
shift_axis_input_tready
=
flush_save
;
end
else
begin
shift_axis_tdata
=
{
s_axis_tdata
,
save_axis_tdata_reg
}
>>
(
OFFSET
*
8
);
shift_axis_tkeep
=
{
s_axis_tkeep
,
save_axis_tkeep_reg
}
>>
OFFSET
;
shift_axis_tvalid
=
s_axis_tvalid
;
shift_axis_tlast
=
(
s_axis_tlast
&&
((
s_axis_tkeep
&
(
{
KEEP_WIDTH
{
1'b1
}}
<<
OFFSET
))
==
0
));
shift_axis_tuser
=
(
s_axis_tuser
&&
((
s_axis_tkeep
&
(
{
KEEP_WIDTH
{
1'b1
}}
<<
OFFSET
))
==
0
));
shift_axis_input_tready
=
!
(
s_axis_tlast
&&
s_axis_tready
&&
s_axis_tvalid
);
end
end
always
@*
begin
read_eth_header_next
=
read_eth_header_reg
;
read_eth_payload_next
=
read_eth_payload_reg
;
ptr_next
=
ptr_reg
;
s_axis_tready_next
=
m_eth_payload_axis_tready_int_early
&&
shift_axis_input_tready
&&
(
!
m_eth_hdr_valid
||
m_eth_hdr_ready
);
flush_save
=
1'b0
;
transfer_in_save
=
1'b0
;
m_eth_hdr_valid_next
=
m_eth_hdr_valid_reg
&&
!
m_eth_hdr_ready
;
m_eth_dest_mac_next
=
m_eth_dest_mac_reg
;
m_eth_src_mac_next
=
m_eth_src_mac_reg
;
m_eth_type_next
=
m_eth_type_reg
;
error_header_early_termination_next
=
1'b0
;
m_eth_payload_axis_tdata_int
=
shift_axis_tdata
;
m_eth_payload_axis_tkeep_int
=
shift_axis_tkeep
;
m_eth_payload_axis_tvalid_int
=
1'b0
;
m_eth_payload_axis_tlast_int
=
shift_axis_tlast
;
m_eth_payload_axis_tuser_int
=
shift_axis_tuser
;
if
((
s_axis_tready
&&
s_axis_tvalid
)
||
(
m_eth_payload_axis_tready_int_reg
&&
shift_axis_extra_cycle_reg
))
begin
transfer_in_save
=
1'b1
;
if
(
read_eth_header_reg
)
begin
// word transfer in - store it
ptr_next
=
ptr_reg
+
1
;
`define
_HEADER_FIELD_
(
offset
,
field
)
\
if
(
ptr_reg
==
offset
/
KEEP_WIDTH
&&
(!
KEEP_ENABLE
||
s_axis_tkeep
[
offset
%
KEEP_WIDTH
]))
begin \
field
=
s_axis_tdata
[(
offset
%
KEEP_WIDTH
)*
8
+:
8
]
;
\
end
`_HEADER_FIELD_
(
0
,
m_eth_dest_mac_next
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
1
,
m_eth_dest_mac_next
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
2
,
m_eth_dest_mac_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
3
,
m_eth_dest_mac_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
4
,
m_eth_dest_mac_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
5
,
m_eth_dest_mac_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
6
,
m_eth_src_mac_next
[
5
*
8
+:
8
])
`_HEADER_FIELD_
(
7
,
m_eth_src_mac_next
[
4
*
8
+:
8
])
`_HEADER_FIELD_
(
8
,
m_eth_src_mac_next
[
3
*
8
+:
8
])
`_HEADER_FIELD_
(
9
,
m_eth_src_mac_next
[
2
*
8
+:
8
])
`_HEADER_FIELD_
(
10
,
m_eth_src_mac_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
11
,
m_eth_src_mac_next
[
0
*
8
+:
8
])
`_HEADER_FIELD_
(
12
,
m_eth_type_next
[
1
*
8
+:
8
])
`_HEADER_FIELD_
(
13
,
m_eth_type_next
[
0
*
8
+:
8
])
if
(
ptr_reg
==
13
/
KEEP_WIDTH
&&
(
!
KEEP_ENABLE
||
s_axis_tkeep
[
13
%
KEEP_WIDTH
]))
begin
if
(
!
shift_axis_tlast
)
begin
m_eth_hdr_valid_next
=
1'b1
;
read_eth_header_next
=
1'b0
;
read_eth_payload_next
=
1'b1
;
end
end
`undef
_
HEADER_FIELD_
end
if
(
read_eth_payload_reg
)
begin
// transfer payload
m_eth_payload_axis_tdata_int
=
shift_axis_tdata
;
m_eth_payload_axis_tkeep_int
=
shift_axis_tkeep
;
m_eth_payload_axis_tvalid_int
=
1'b1
;
m_eth_payload_axis_tlast_int
=
shift_axis_tlast
;
m_eth_payload_axis_tuser_int
=
shift_axis_tuser
;
end
if
(
shift_axis_tlast
)
begin
if
(
read_eth_header_next
)
begin
// don't have the whole header
error_header_early_termination_next
=
1'b1
;
end
flush_save
=
1'b1
;
ptr_next
=
1'b0
;
read_eth_header_next
=
1'b1
;
read_eth_payload_next
=
1'b0
;
end
end
end
always
@
(
posedge
clk
)
begin
read_eth_header_reg
<=
read_eth_header_next
;
read_eth_payload_reg
<=
read_eth_payload_next
;
ptr_reg
<=
ptr_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
m_eth_hdr_valid_reg
<=
m_eth_hdr_valid_next
;
m_eth_dest_mac_reg
<=
m_eth_dest_mac_next
;
m_eth_src_mac_reg
<=
m_eth_src_mac_next
;
m_eth_type_reg
<=
m_eth_type_next
;
error_header_early_termination_reg
<=
error_header_early_termination_next
;
busy_reg
<=
(
read_eth_payload_next
||
ptr_next
!=
0
);
if
(
transfer_in_save
)
begin
save_axis_tdata_reg
<=
s_axis_tdata
;
save_axis_tkeep_reg
<=
s_axis_tkeep
;
save_axis_tuser_reg
<=
s_axis_tuser
;
end
if
(
flush_save
)
begin
save_axis_tlast_reg
<=
1'b0
;
shift_axis_extra_cycle_reg
<=
1'b0
;
end
else
if
(
transfer_in_save
)
begin
save_axis_tlast_reg
<=
s_axis_tlast
;
shift_axis_extra_cycle_reg
<=
OFFSET
?
s_axis_tlast
&&
((
s_axis_tkeep
&
(
{
KEEP_WIDTH
{
1'b1
}}
<<
OFFSET
))
!=
0
)
:
1'b0
;
end
if
(
rst
)
begin
read_eth_header_reg
<=
1'b1
;
read_eth_payload_reg
<=
1'b0
;
ptr_reg
<=
0
;
s_axis_tready_reg
<=
1'b0
;
m_eth_hdr_valid_reg
<=
1'b0
;
save_axis_tlast_reg
<=
1'b0
;
shift_axis_extra_cycle_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
error_header_early_termination_reg
<=
1'b0
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_eth_payload_axis_tvalid_reg
=
1'b0
,
m_eth_payload_axis_tvalid_next
;
reg
m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
m_eth_payload_axis_tuser_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_eth_payload_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_eth_payload_axis_tvalid_reg
=
1'b0
,
temp_m_eth_payload_axis_tvalid_next
;
reg
temp_m_eth_payload_axis_tlast_reg
=
1'b0
;
reg
temp_m_eth_payload_axis_tuser_reg
=
1'b0
;
// datapath control
reg
store_eth_payload_int_to_output
;
reg
store_eth_payload_int_to_temp
;
reg
store_eth_payload_axis_temp_to_output
;
assign
m_eth_payload_axis_tdata
=
m_eth_payload_axis_tdata_reg
;
assign
m_eth_payload_axis_tkeep
=
KEEP_ENABLE
?
m_eth_payload_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_eth_payload_axis_tvalid
=
m_eth_payload_axis_tvalid_reg
;
assign
m_eth_payload_axis_tlast
=
m_eth_payload_axis_tlast_reg
;
assign
m_eth_payload_axis_tuser
=
m_eth_payload_axis_tuser_reg
;
// 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_eth_payload_axis_tready_int_early
=
m_eth_payload_axis_tready
||
(
!
temp_m_eth_payload_axis_tvalid_reg
&&
(
!
m_eth_payload_axis_tvalid_reg
||
!
m_eth_payload_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
store_eth_payload_int_to_output
=
1'b0
;
store_eth_payload_int_to_temp
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b0
;
if
(
m_eth_payload_axis_tready_int_reg
)
begin
// input is ready
if
(
m_eth_payload_axis_tready
||
!
m_eth_payload_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_eth_payload_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_eth_payload_axis_tvalid_next
=
m_eth_payload_axis_tvalid_int
;
store_eth_payload_int_to_temp
=
1'b1
;
end
end
else
if
(
m_eth_payload_axis_tready
)
begin
// input is not ready, but output is ready
m_eth_payload_axis_tvalid_next
=
temp_m_eth_payload_axis_tvalid_reg
;
temp_m_eth_payload_axis_tvalid_next
=
1'b0
;
store_eth_payload_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_eth_payload_axis_tvalid_reg
<=
1'b0
;
m_eth_payload_axis_tready_int_reg
<=
1'b0
;
temp_m_eth_payload_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_eth_payload_axis_tvalid_reg
<=
m_eth_payload_axis_tvalid_next
;
m_eth_payload_axis_tready_int_reg
<=
m_eth_payload_axis_tready_int_early
;
temp_m_eth_payload_axis_tvalid_reg
<=
temp_m_eth_payload_axis_tvalid_next
;
end
// datapath
if
(
store_eth_payload_int_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
else
if
(
store_eth_payload_axis_temp_to_output
)
begin
m_eth_payload_axis_tdata_reg
<=
temp_m_eth_payload_axis_tdata_reg
;
m_eth_payload_axis_tkeep_reg
<=
temp_m_eth_payload_axis_tkeep_reg
;
m_eth_payload_axis_tlast_reg
<=
temp_m_eth_payload_axis_tlast_reg
;
m_eth_payload_axis_tuser_reg
<=
temp_m_eth_payload_axis_tuser_reg
;
end
if
(
store_eth_payload_int_to_temp
)
begin
temp_m_eth_payload_axis_tdata_reg
<=
m_eth_payload_axis_tdata_int
;
temp_m_eth_payload_axis_tkeep_reg
<=
m_eth_payload_axis_tkeep_int
;
temp_m_eth_payload_axis_tlast_reg
<=
m_eth_payload_axis_tlast_int
;
temp_m_eth_payload_axis_tuser_reg
<=
m_eth_payload_axis_tuser_int
;
end
end
endmodule
Prev
1
2
3
4
5
6
7
8
Next
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment