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
5175 additions
and
0 deletions
+5175
-0
corundum/lib/eth/lib/axis/AUTHORS
corundum/lib/eth/lib/axis/AUTHORS
+1
-0
corundum/lib/eth/lib/axis/COPYING
corundum/lib/eth/lib/axis/COPYING
+19
-0
corundum/lib/eth/lib/axis/README
corundum/lib/eth/lib/axis/README
+1
-0
corundum/lib/eth/lib/axis/README.md
corundum/lib/eth/lib/axis/README.md
+305
-0
corundum/lib/eth/lib/axis/rtl/arbiter.v
corundum/lib/eth/lib/axis/rtl/arbiter.v
+153
-0
corundum/lib/eth/lib/axis/rtl/axis_adapter.v
corundum/lib/eth/lib/axis/rtl/axis_adapter.v
+554
-0
corundum/lib/eth/lib/axis/rtl/axis_arb_mux.v
corundum/lib/eth/lib/axis/rtl/axis_arb_mux.v
+249
-0
corundum/lib/eth/lib/axis/rtl/axis_arb_mux_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_arb_mux_wrap.py
+180
-0
corundum/lib/eth/lib/axis/rtl/axis_async_fifo.v
corundum/lib/eth/lib/axis/rtl/axis_async_fifo.v
+538
-0
corundum/lib/eth/lib/axis/rtl/axis_async_fifo_adapter.v
corundum/lib/eth/lib/axis/rtl/axis_async_fifo_adapter.v
+348
-0
corundum/lib/eth/lib/axis/rtl/axis_broadcast.v
corundum/lib/eth/lib/axis/rtl/axis_broadcast.v
+191
-0
corundum/lib/eth/lib/axis/rtl/axis_cobs_decode.v
corundum/lib/eth/lib/axis/rtl/axis_cobs_decode.v
+328
-0
corundum/lib/eth/lib/axis/rtl/axis_cobs_encode.v
corundum/lib/eth/lib/axis/rtl/axis_cobs_encode.v
+506
-0
corundum/lib/eth/lib/axis/rtl/axis_crosspoint.v
corundum/lib/eth/lib/axis/rtl/axis_crosspoint.v
+151
-0
corundum/lib/eth/lib/axis/rtl/axis_crosspoint_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_crosspoint_wrap.py
+192
-0
corundum/lib/eth/lib/axis/rtl/axis_demux.v
corundum/lib/eth/lib/axis/rtl/axis_demux.v
+266
-0
corundum/lib/eth/lib/axis/rtl/axis_demux_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_demux_wrap.py
+186
-0
corundum/lib/eth/lib/axis/rtl/axis_fifo.v
corundum/lib/eth/lib/axis/rtl/axis_fifo.v
+342
-0
corundum/lib/eth/lib/axis/rtl/axis_fifo_adapter.v
corundum/lib/eth/lib/axis/rtl/axis_fifo_adapter.v
+338
-0
corundum/lib/eth/lib/axis/rtl/axis_frame_join.v
corundum/lib/eth/lib/axis/rtl/axis_frame_join.v
+327
-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/lib/axis/AUTHORS
0 → 100644
View file @
738c1fef
Alex Forencich <alex@alexforencich.com>
corundum/lib/eth/lib/axis/COPYING
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.
corundum/lib/eth/lib/axis/README
0 → 120000
View file @
738c1fef
README.md
\ No newline at end of file
corundum/lib/eth/lib/axis/README.md
0 → 100644
View file @
738c1fef
# Verilog AXI Stream Components Readme
For more information and updates: http://alexforencich.com/wiki/en/verilog/axis/start
GitHub repository: https://github.com/alexforencich/verilog-axis
## Introduction
Collection of AXI Stream bus components. Most components are fully
parametrizable in interface widths. Includes full MyHDL testbench with
intelligent bus cosimulation endpoints.
## Documentation
### arbiter module
General-purpose parametrizable arbiter. Supports priority and round-robin
arbitration. Supports blocking until request release or acknowledge.
### axis_adapter module
The axis_adapter module bridges AXI stream busses of differing widths. The
module is parametrizable, but there are certain restrictions. First, the bus
word widths must be identical (e.g. one 8-bit lane and eight 8-bit lanes, but
not one 16-bit lane and one 32-bit lane). Second, the bus widths must be
related by an integer multiple (e.g. 2 words and 6 words, but not 4 words
and 6 words). Wait states will be inserted on the wider bus side when
necessary.
### axis_arb_mux module
Frame-aware AXI stream arbitrated muliplexer with parametrizable data width
and port count. Supports priority and round-robin arbitration.
Wrappers can generated with axis_arb_mux_wrap.py.
### axis_async_fifo module
Configurable word-based or frame-based asynchronous FIFO with parametrizable
data width, depth, type, and bad frame detection. Supports power of two
depths only.
### axis_async_fifo_adapter module
Configurable word-based or frame-based asynchronous FIFO with parametrizable
data width, depth, type, and bad frame detection. Supports different input
and output data widths, inserting an axis_adapter instance appropriately.
Supports power of two depths only.
### axis_broadcast module
AXI stream broadcaster. Duplicates one input stream across multiple output
streams.
### axis_cobs_decode
Consistent Overhead Byte Stuffing (COBS) decoder. Fixed 8 bit width.
### axis_cobs_encode
Consistent Overhead Byte Stuffing (COBS) encoder. Fixed 8 bit width.
Configurable zero insertion.
### axis_crosspoint module
Basic crosspoint switch. tready signal not supported. Parametrizable data
width.
Wrappers can generated with axis_crosspoint_wrap.py.
### axis_demux module
Frame-aware AXI stream demuliplexer with parametrizable data width and port
count.
### axis_fifo module
Configurable word-based or frame-based synchronous FIFO with parametrizable
data width, depth, type, and bad frame detection. Supports power of two
depths only.
### axis_fifo_adapter module
Configurable word-based or frame-based synchronous FIFO with parametrizable
data width, depth, type, and bad frame detection. Supports different input
and output data widths, inserting an axis_adapter instance appropriately.
Supports power of two depths only.
### axis_frame_join module
Frame joiner with optional tag and parametrizable port count. 8 bit data path
only.
Wrappers can generated with axis_frame_join_wrap.py.
### axis_frame_length_adjust module
Frame length adjuster module. Truncates or pads frames as necessary to meet
the specified minimum and maximum length. Reports the original and current
lengths as well as whether the packet was truncated or padded. Length limits
are configurable at run time.
### axis_frame_length_adjust_fifo module
Frame length adjuster module with FIFO. Truncates or pads frames as necessary
to meet the specified minimum and maximum length. Reports the original and
current lengths as well as whether the packet was truncated or padded. FIFOs
are used so that the status information can be read before the packet itself.
Length limits are configurable at run time.
### axis_ll_bridge module
AXI stream to LocalLink bridge.
### axis_mux module
Frame-aware AXI stream muliplexer with parametrizable data width and port
count.
Wrappers can generated with axis_mux_wrap.py.
### axis_pipeline_register module
Parametrizable register pipeline. LENGTH parameter determines number of
register stages.
### axis_ram_switch module
Frame-aware AXI stream RAM switch with parametrizable data width, port count,
and FIFO size. Uses block RAM for storing packets in transit, time-sharing
the RAM interface between ports. Functionally equivalent to a combination of
per-port frame FIFOs and width converters connected to an AXI stream switch.
### axis_rate_limit module
Fractional rate limiter, supports word and frame modes. Inserts wait states
to limit data rate to specified ratio. Frame mode inserts wait states at end
of frames, word mode ignores frames and inserts wait states at any point.
Parametrizable data width. Rate and mode are configurable at run time.
### axis_register module
Datapath register with parameter to select between skid buffer, simple buffer,
and bypass. Use to improve timing for long routes.
### axis_srl_fifo module
SRL-based FIFO. Good for small FIFOs. SRLs on Xilinx FPGAs have a very fast
input setup time, so this module can be used to aid in timing closure.
### axis_srl_register module
SRL-based register. SRLs on Xilinx FPGAs have a very fast input setup time,
so this module can be used to aid in timing closure.
### axis_stat_counter module
Statistics counter module. Counts bytes and frames passing through monitored
AXI stream interface. Trigger signal used to reset and dump counts out of AXI
interface, along with tag value. Use with axis_frame_join_N to form a single
monolithic frame from multiple monitored points with the same trigger.
### axis_switch module
Frame-aware AXI stream switch with parametrizable data width and port count.
Wrappers can generated with axis_switch_wrap.py.
### axis_tap module
AXI stream tap module. Used to make a copy of an AXI stream bus without
affecting the bus. Back-pressure on the output results in truncated frames
with tuser set.
### ll_axis_bridge module
LocalLink to AXI stream bridge.
### priority_encoder module
Parametrizable priority encoder.
### Common signals
tdata : Data (width generally DATA_WIDTH)
tkeep : Data word valid (width generally KEEP_WIDTH)
tvalid : Data valid
tready : Sink ready
tlast : End-of-frame
tid : Identifier tag (width generally ID_WIDTH)
tdest : Destination tag (width generally DEST_WIDTH)
tuser : User sideband signals (width generally USER_WIDTH)
### Common parameters
DATA_WIDTH : width of tdata signal
KEEP_ENABLE : enable tkeep signal (default DATA_WIDTH>8)
KEEP_WIDTH : width of tkeep signal (default DATA_WIDTH/8)
LAST_ENABLE : enable tlast signal
ID_ENABLE : enable tid signal
ID_WIDTH : width of tid signal
DEST_ENABLE : enable tdest signal
DEST_WIDTH : width of tdest signal
USER_ENABLE : enable tuser signal
USER_WIDTH : width of tuser signal
USER_BAD_FRAME_VALUE : value of tuser indicating bad frame
USER_BAD_FRAME_MASK : bitmask for tuser bad frame indication
### Source Files
arbiter.v : General-purpose parametrizable arbiter
axis_adapter.v : Parametrizable bus width adapter
axis_arb_mux.v : Parametrizable arbitrated multiplexer
axis_async_fifo.v : Parametrizable asynchronous FIFO
axis_async_fifo_adapter.v : FIFO/width adapter wrapper
axis_broadcast.v : AXI stream broadcaster
axis_cobs_decode.v : COBS decoder
axis_cobs_encode.v : COBS encoder
axis_crosspoint.v : Parametrizable crosspoint switch
axis_demux.v : Parametrizable demultiplexer
axis_fifo.v : Parametrizable synchronous FIFO
axis_fifo_adapter.v : FIFO/width adapter wrapper
axis_frame_join.v : Parametrizable frame joiner
axis_frame_length_adjust.v : Frame length adjuster
axis_frame_length_adjust_fifo.v : Frame length adjuster with FIFO
axis_ll_bridge.v : AXI stream to LocalLink bridge
axis_mux.v : Multiplexer generator
axis_ram_switch.v : AXI stream RAM switch
axis_rate_limit.v : Fractional rate limiter
axis_register.v : AXI Stream register
axis_srl_fifo.v : SRL-based FIFO
axis_srl_register.v : SRL-based register
axis_switch.v : Parametrizable AXI stream switch
axis_stat_counter.v : Statistics counter
axis_tap.v : AXI stream tap
ll_axis_bridge.v : LocalLink to AXI stream bridge
priority_encoder.v : Parametrizable priority encoder
### AXI Stream Interface Example
two byte transfer with sink pause after each byte
__ __ __ __ __ __ __ __ __
clk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
_____ _________________
tdata XXXXXXXXX_D0__X_D1______________XXXXXXXXXXXXXXXXXXXXXXXX
_____ _________________
tkeep XXXXXXXXX_K0__X_K1______________XXXXXXXXXXXXXXXXXXXXXXXX
_______________________
tvalid ________/ \_______________________
______________ _____ ___________
tready \___________/ \___________/
_________________
tlast ______________/ \_______________________
tuser ________________________________________________________
two back-to-back packets, no pauses
__ __ __ __ __ __ __ __ __
clk __/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__
_____ _____ _____ _____ _____ _____
tdata XXXXXXXXX_A0__X_A1__X_A2__X_B0__X_B1__X_B2__XXXXXXXXXXXX
_____ _____ _____ _____ _____ _____
tkeep XXXXXXXXX_K0__X_K1__X_K2__X_K0__X_K1__X_K2__XXXXXXXXXXXX
___________________________________
tvalid ________/ \___________
________________________________________________________
tready
_____ _____
tlast ____________________/ \___________/ \___________
tuser ________________________________________________________
bad frame
__ __ __ __ __ __
clk __/ \__/ \__/ \__/ \__/ \__/ \__
_____ _____ _____
tdata XXXXXXXXX_A0__X_A1__X_A2__XXXXXXXXXXXX
_____ _____ _____
tkeep XXXXXXXXX_K0__X_K1__X_K2__XXXXXXXXXXXX
_________________
tvalid ________/ \___________
______________________________________
tready
_____
tlast ____________________/ \___________
_____
tuser ____________________/ \___________
## Testing
Running the included testbenches requires MyHDL and Icarus Verilog. Make sure
that myhdl.vpi is installed properly for cosimulation to work correctly. The
testbenches can be run with a Python test runner like nose or py.test, or the
individual test scripts can be run with python directly.
### Testbench Files
tb/axis_ep.py : MyHDL AXI Stream endpoints
tb/ll_ep.py : MyHDL LocalLink endpoints
corundum/lib/eth/lib/axis/rtl/arbiter.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
/*
* Arbiter module
*/
module
arbiter
#
(
parameter
PORTS
=
4
,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
TYPE
=
"PRIORITY"
,
// block type: "NONE", "REQUEST", "ACKNOWLEDGE"
parameter
BLOCK
=
"NONE"
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"LOW"
)
(
input
wire
clk
,
input
wire
rst
,
input
wire
[
PORTS
-
1
:
0
]
request
,
input
wire
[
PORTS
-
1
:
0
]
acknowledge
,
output
wire
[
PORTS
-
1
:
0
]
grant
,
output
wire
grant_valid
,
output
wire
[$
clog2
(
PORTS
)
-
1
:
0
]
grant_encoded
);
reg
[
PORTS
-
1
:
0
]
grant_reg
=
0
,
grant_next
;
reg
grant_valid_reg
=
0
,
grant_valid_next
;
reg
[$
clog2
(
PORTS
)
-
1
:
0
]
grant_encoded_reg
=
0
,
grant_encoded_next
;
assign
grant_valid
=
grant_valid_reg
;
assign
grant
=
grant_reg
;
assign
grant_encoded
=
grant_encoded_reg
;
wire
request_valid
;
wire
[$
clog2
(
PORTS
)
-
1
:
0
]
request_index
;
wire
[
PORTS
-
1
:
0
]
request_mask
;
priority_encoder
#(
.
WIDTH
(
PORTS
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
priority_encoder_inst
(
.
input_unencoded
(
request
),
.
output_valid
(
request_valid
),
.
output_encoded
(
request_index
),
.
output_unencoded
(
request_mask
)
);
reg
[
PORTS
-
1
:
0
]
mask_reg
=
0
,
mask_next
;
wire
masked_request_valid
;
wire
[$
clog2
(
PORTS
)
-
1
:
0
]
masked_request_index
;
wire
[
PORTS
-
1
:
0
]
masked_request_mask
;
priority_encoder
#(
.
WIDTH
(
PORTS
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
priority_encoder_masked
(
.
input_unencoded
(
request
&
mask_reg
),
.
output_valid
(
masked_request_valid
),
.
output_encoded
(
masked_request_index
),
.
output_unencoded
(
masked_request_mask
)
);
always
@*
begin
grant_next
=
0
;
grant_valid_next
=
0
;
grant_encoded_next
=
0
;
mask_next
=
mask_reg
;
if
(
BLOCK
==
"REQUEST"
&&
grant_reg
&
request
)
begin
// granted request still asserted; hold it
grant_valid_next
=
grant_valid_reg
;
grant_next
=
grant_reg
;
grant_encoded_next
=
grant_encoded_reg
;
end
else
if
(
BLOCK
==
"ACKNOWLEDGE"
&&
grant_valid
&&
!
(
grant_reg
&
acknowledge
))
begin
// granted request not yet acknowledged; hold it
grant_valid_next
=
grant_valid_reg
;
grant_next
=
grant_reg
;
grant_encoded_next
=
grant_encoded_reg
;
end
else
if
(
request_valid
)
begin
if
(
TYPE
==
"PRIORITY"
)
begin
grant_valid_next
=
1
;
grant_next
=
request_mask
;
grant_encoded_next
=
request_index
;
end
else
if
(
TYPE
==
"ROUND_ROBIN"
)
begin
if
(
masked_request_valid
)
begin
grant_valid_next
=
1
;
grant_next
=
masked_request_mask
;
grant_encoded_next
=
masked_request_index
;
if
(
LSB_PRIORITY
==
"LOW"
)
begin
mask_next
=
{
PORTS
{
1'b1
}}
>>
(
PORTS
-
masked_request_index
);
end
else
begin
mask_next
=
{
PORTS
{
1'b1
}}
<<
(
masked_request_index
+
1
);
end
end
else
begin
grant_valid_next
=
1
;
grant_next
=
request_mask
;
grant_encoded_next
=
request_index
;
if
(
LSB_PRIORITY
==
"LOW"
)
begin
mask_next
=
{
PORTS
{
1'b1
}}
>>
(
PORTS
-
request_index
);
end
else
begin
mask_next
=
{
PORTS
{
1'b1
}}
<<
(
request_index
+
1
);
end
end
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
grant_reg
<=
0
;
grant_valid_reg
<=
0
;
grant_encoded_reg
<=
0
;
mask_reg
<=
0
;
end
else
begin
grant_reg
<=
grant_next
;
grant_valid_reg
<=
grant_valid_next
;
grant_encoded_reg
<=
grant_encoded_next
;
mask_reg
<=
mask_next
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_adapter.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
/*
* AXI4-Stream bus width adapter
*/
module
axis_adapter
#
(
// Width of input AXI stream interface in bits
parameter
S_DATA_WIDTH
=
8
,
// Propagate tkeep signal on input interface
// If disabled, tkeep assumed to be 1'b1
parameter
S_KEEP_ENABLE
=
(
S_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on input interface
parameter
S_KEEP_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output AXI stream interface in bits
parameter
M_DATA_WIDTH
=
8
,
// Propagate tkeep signal on output interface
// If disabled, tkeep assumed to be 1'b1
parameter
M_KEEP_ENABLE
=
(
M_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on output interface
parameter
M_KEEP_WIDTH
=
(
M_DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
);
// force keep width to 1 when disabled
parameter
S_KEEP_WIDTH_INT
=
S_KEEP_ENABLE
?
S_KEEP_WIDTH
:
1
;
parameter
M_KEEP_WIDTH_INT
=
M_KEEP_ENABLE
?
M_KEEP_WIDTH
:
1
;
// bus word sizes (must be identical)
parameter
S_DATA_WORD_SIZE
=
S_DATA_WIDTH
/
S_KEEP_WIDTH_INT
;
parameter
M_DATA_WORD_SIZE
=
M_DATA_WIDTH
/
M_KEEP_WIDTH_INT
;
// output bus is wider
parameter
EXPAND_BUS
=
M_KEEP_WIDTH_INT
>
S_KEEP_WIDTH_INT
;
// total data and keep widths
parameter
DATA_WIDTH
=
EXPAND_BUS
?
M_DATA_WIDTH
:
S_DATA_WIDTH
;
parameter
KEEP_WIDTH
=
EXPAND_BUS
?
M_KEEP_WIDTH_INT
:
S_KEEP_WIDTH_INT
;
// required number of segments in wider bus
parameter
SEGMENT_COUNT
=
EXPAND_BUS
?
(
M_KEEP_WIDTH_INT
/
S_KEEP_WIDTH_INT
)
:
(
S_KEEP_WIDTH_INT
/
M_KEEP_WIDTH_INT
);
parameter
SEGMENT_COUNT_WIDTH
=
SEGMENT_COUNT
==
1
?
1
:
$
clog2
(
SEGMENT_COUNT
);
// data width and keep width per segment
parameter
SEGMENT_DATA_WIDTH
=
DATA_WIDTH
/
SEGMENT_COUNT
;
parameter
SEGMENT_KEEP_WIDTH
=
KEEP_WIDTH
/
SEGMENT_COUNT
;
// bus width assertions
initial
begin
if
(
S_DATA_WORD_SIZE
*
S_KEEP_WIDTH_INT
!=
S_DATA_WIDTH
)
begin
$
error
(
"Error: input data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
M_DATA_WORD_SIZE
*
M_KEEP_WIDTH_INT
!=
M_DATA_WIDTH
)
begin
$
error
(
"Error: output data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
S_DATA_WORD_SIZE
!=
M_DATA_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
end
// state register
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_TRANSFER_IN
=
3'd1
,
STATE_TRANSFER_OUT
=
3'd2
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
SEGMENT_COUNT_WIDTH
-
1
:
0
]
segment_count_reg
=
0
,
segment_count_next
;
reg
last_segment
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
temp_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
temp_tkeep_next
;
reg
temp_tlast_reg
=
1'b0
,
temp_tlast_next
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
temp_tid_next
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
,
temp_tdest_next
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
,
temp_tuser_next
;
// internal datapath
reg
[
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
M_KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
segment_count_next
=
segment_count_reg
;
last_segment
=
0
;
temp_tdata_next
=
temp_tdata_reg
;
temp_tkeep_next
=
temp_tkeep_reg
;
temp_tlast_next
=
temp_tlast_reg
;
temp_tid_next
=
temp_tid_reg
;
temp_tdest_next
=
temp_tdest_reg
;
temp_tuser_next
=
temp_tuser_reg
;
if
(
EXPAND_BUS
)
begin
m_axis_tdata_int
=
temp_tdata_reg
;
m_axis_tkeep_int
=
temp_tkeep_reg
;
m_axis_tlast_int
=
temp_tlast_reg
;
end
else
begin
m_axis_tdata_int
=
{
M_DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_int
=
{
M_KEEP_WIDTH
{
1'b0
}}
;
m_axis_tlast_int
=
1'b0
;
end
m_axis_tvalid_int
=
1'b0
;
m_axis_tid_int
=
temp_tid_reg
;
m_axis_tdest_int
=
temp_tdest_reg
;
m_axis_tuser_int
=
temp_tuser_reg
;
s_axis_tready_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - no data in registers
if
(
SEGMENT_COUNT
==
1
)
begin
// output and input same width - just act like a register
// accept data next cycle if output register ready next cycle
s_axis_tready_next
=
m_axis_tready_int_early
;
// transfer through
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tkeep_int
=
S_KEEP_ENABLE
?
s_axis_tkeep
:
1'b1
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
s_axis_tlast
;
m_axis_tid_int
=
s_axis_tid
;
m_axis_tdest_int
=
s_axis_tdest
;
m_axis_tuser_int
=
s_axis_tuser
;
state_next
=
STATE_IDLE
;
end
else
if
(
EXPAND_BUS
)
begin
// output bus is wider
// accept new data
s_axis_tready_next
=
1'b1
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// word transfer in - store it in data register
// pass complete input word, zero-extended to temp register
temp_tdata_next
=
s_axis_tdata
;
temp_tkeep_next
=
S_KEEP_ENABLE
?
s_axis_tkeep
:
1'b1
;
temp_tlast_next
=
s_axis_tlast
;
temp_tid_next
=
s_axis_tid
;
temp_tdest_next
=
s_axis_tdest
;
temp_tuser_next
=
s_axis_tuser
;
// first input segment complete
segment_count_next
=
1
;
if
(
s_axis_tlast
)
begin
// got last signal on first segment, so output it
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_TRANSFER_OUT
;
end
else
begin
// otherwise, transfer in the rest of the words
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_TRANSFER_IN
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
// output bus is narrower
// accept new data
s_axis_tready_next
=
1'b1
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// word transfer in - store it in data register
segment_count_next
=
0
;
// is this the last segment?
if
(
SEGMENT_COUNT
==
1
)
begin
// last segment by counter value
last_segment
=
1'b1
;
end
else
if
(
S_KEEP_ENABLE
&&
s_axis_tkeep
[
SEGMENT_KEEP_WIDTH
-
1
:
0
]
!=
{
SEGMENT_KEEP_WIDTH
{
1'b1
}}
)
begin
// last segment by tkeep fall in current segment
last_segment
=
1'b1
;
end
else
if
(
S_KEEP_ENABLE
&&
s_axis_tkeep
[(
SEGMENT_KEEP_WIDTH
*
2
)
-
1
:
SEGMENT_KEEP_WIDTH
]
==
{
SEGMENT_KEEP_WIDTH
{
1'b0
}}
)
begin
// last segment by tkeep fall at end of current segment
last_segment
=
1'b1
;
end
else
begin
last_segment
=
1'b0
;
end
// pass complete input word, zero-extended to temp register
temp_tdata_next
=
s_axis_tdata
;
temp_tkeep_next
=
S_KEEP_ENABLE
?
s_axis_tkeep
:
1'b1
;
temp_tlast_next
=
s_axis_tlast
;
temp_tid_next
=
s_axis_tid
;
temp_tdest_next
=
s_axis_tdest
;
temp_tuser_next
=
s_axis_tuser
;
// short-circuit and get first word out the door
m_axis_tdata_int
=
s_axis_tdata
[
SEGMENT_DATA_WIDTH
-
1
:
0
];
m_axis_tkeep_int
=
s_axis_tkeep
[
SEGMENT_KEEP_WIDTH
-
1
:
0
];
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
s_axis_tlast
&
last_segment
;
m_axis_tid_int
=
s_axis_tid
;
m_axis_tdest_int
=
s_axis_tdest
;
m_axis_tuser_int
=
s_axis_tuser
;
if
(
m_axis_tready_int_reg
)
begin
// if output register is ready for first word, then move on to the next one
segment_count_next
=
1
;
end
if
(
!
last_segment
||
!
m_axis_tready_int_reg
)
begin
// continue outputting words
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_TRANSFER_OUT
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
end
STATE_TRANSFER_IN:
begin
// transfer word to temp registers
// only used when output is wider
// accept new data
s_axis_tready_next
=
1'b1
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// word transfer in - store in data register
temp_tdata_next
[
segment_count_reg
*
SEGMENT_DATA_WIDTH
+:
SEGMENT_DATA_WIDTH
]
=
s_axis_tdata
;
temp_tkeep_next
[
segment_count_reg
*
SEGMENT_KEEP_WIDTH
+:
SEGMENT_KEEP_WIDTH
]
=
S_KEEP_ENABLE
?
s_axis_tkeep
:
1'b1
;
temp_tlast_next
=
s_axis_tlast
;
temp_tid_next
=
s_axis_tid
;
temp_tdest_next
=
s_axis_tdest
;
temp_tuser_next
=
s_axis_tuser
;
segment_count_next
=
segment_count_reg
+
1
;
if
((
segment_count_reg
==
SEGMENT_COUNT
-
1
)
||
s_axis_tlast
)
begin
// terminated by counter or tlast signal, output complete word
// read input word next cycle if output will be ready
s_axis_tready_next
=
m_axis_tready_int_early
;
state_next
=
STATE_TRANSFER_OUT
;
end
else
begin
// more words to read
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_TRANSFER_IN
;
end
end
else
begin
state_next
=
STATE_TRANSFER_IN
;
end
end
STATE_TRANSFER_OUT:
begin
// transfer word to output registers
if
(
EXPAND_BUS
)
begin
// output bus is wider
// do not accept new data
s_axis_tready_next
=
1'b0
;
// single-cycle output of entire stored word (output wider)
m_axis_tdata_int
=
temp_tdata_reg
;
m_axis_tkeep_int
=
temp_tkeep_reg
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
temp_tlast_reg
;
m_axis_tid_int
=
temp_tid_reg
;
m_axis_tdest_int
=
temp_tdest_reg
;
m_axis_tuser_int
=
temp_tuser_reg
;
if
(
m_axis_tready_int_reg
)
begin
// word transfer out
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// word transfer in
// pass complete input word, zero-extended to temp register
temp_tdata_next
=
s_axis_tdata
;
temp_tkeep_next
=
S_KEEP_ENABLE
?
s_axis_tkeep
:
1'b1
;
temp_tlast_next
=
s_axis_tlast
;
temp_tid_next
=
s_axis_tid
;
temp_tdest_next
=
s_axis_tdest
;
temp_tuser_next
=
s_axis_tuser
;
// first input segment complete
segment_count_next
=
1
;
if
(
s_axis_tlast
)
begin
// got last signal on first segment, so output it
s_axis_tready_next
=
1'b0
;
state_next
=
STATE_TRANSFER_OUT
;
end
else
begin
// otherwise, transfer in the rest of the words
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_TRANSFER_IN
;
end
end
else
begin
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_TRANSFER_OUT
;
end
end
else
begin
// output bus is narrower
// do not accept new data
s_axis_tready_next
=
1'b0
;
// is this the last segment?
if
(
segment_count_reg
==
SEGMENT_COUNT
-
1
)
begin
// last segment by counter value
last_segment
=
1'b1
;
end
else
if
(
temp_tkeep_reg
[
segment_count_reg
*
SEGMENT_KEEP_WIDTH
+:
SEGMENT_KEEP_WIDTH
]
!=
{
SEGMENT_KEEP_WIDTH
{
1'b1
}}
)
begin
// last segment by tkeep fall in current segment
last_segment
=
1'b1
;
end
else
if
(
temp_tkeep_reg
[(
segment_count_reg
+
1
)
*
SEGMENT_KEEP_WIDTH
+:
SEGMENT_KEEP_WIDTH
]
==
{
SEGMENT_KEEP_WIDTH
{
1'b0
}}
)
begin
// last segment by tkeep fall at end of current segment
last_segment
=
1'b1
;
end
else
begin
last_segment
=
1'b0
;
end
// output current part of stored word (output narrower)
m_axis_tdata_int
=
temp_tdata_reg
[
segment_count_reg
*
SEGMENT_DATA_WIDTH
+:
SEGMENT_DATA_WIDTH
];
m_axis_tkeep_int
=
temp_tkeep_reg
[
segment_count_reg
*
SEGMENT_KEEP_WIDTH
+:
SEGMENT_KEEP_WIDTH
];
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
temp_tlast_reg
&&
last_segment
;
m_axis_tid_int
=
temp_tid_reg
;
m_axis_tdest_int
=
temp_tdest_reg
;
m_axis_tuser_int
=
temp_tuser_reg
;
if
(
m_axis_tready_int_reg
)
begin
// word transfer out
segment_count_next
=
segment_count_reg
+
1
;
if
(
last_segment
)
begin
// terminated by counter or tlast signal
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
begin
// more words to write
state_next
=
STATE_TRANSFER_OUT
;
end
end
else
begin
state_next
=
STATE_TRANSFER_OUT
;
end
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
s_axis_tready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
end
segment_count_reg
<=
segment_count_next
;
temp_tdata_reg
<=
temp_tdata_next
;
temp_tkeep_reg
<=
temp_tkeep_next
;
temp_tlast_reg
<=
temp_tlast_next
;
temp_tid_reg
<=
temp_tid_next
;
temp_tdest_reg
<=
temp_tdest_next
;
temp_tuser_reg
<=
temp_tuser_next
;
end
// output datapath logic
reg
[
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
M_DATA_WIDTH
{
1'b0
}}
;
reg
[
M_KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
M_KEEP_WIDTH
{
1'b0
}}
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
M_DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
M_DATA_WIDTH
{
1'b0
}}
;
reg
[
M_KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
M_KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
M_KEEP_ENABLE
?
m_axis_tkeep_reg
:
{
M_KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
m_axis_tlast_reg
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_tid_reg
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_tdest_reg
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_tuser_reg
:
{
USER_WIDTH
{
1'b0
}}
;
// 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_tid_reg
<=
m_axis_tid_int
;
m_axis_tdest_reg
<=
m_axis_tdest_int
;
m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_tdata_reg
<=
temp_m_axis_tdata_reg
;
m_axis_tkeep_reg
<=
temp_m_axis_tkeep_reg
;
m_axis_tlast_reg
<=
temp_m_axis_tlast_reg
;
m_axis_tid_reg
<=
temp_m_axis_tid_reg
;
m_axis_tdest_reg
<=
temp_m_axis_tdest_reg
;
m_axis_tuser_reg
<=
temp_m_axis_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_tdata_reg
<=
m_axis_tdata_int
;
temp_m_axis_tkeep_reg
<=
m_axis_tkeep_int
;
temp_m_axis_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tid_reg
<=
m_axis_tid_int
;
temp_m_axis_tdest_reg
<=
m_axis_tdest_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_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
/*
* AXI4-Stream arbitrated multiplexer
*/
module
axis_arb_mux
#
(
// Number of AXI stream inputs
parameter
S_COUNT
=
4
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
ARB_TYPE
=
"PRIORITY"
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"HIGH"
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI Stream inputs
*/
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axis_tready
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tlast
,
input
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI Stream output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
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_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
assign
s_axis_tready
=
(
m_axis_tready_int_reg
&&
grant_valid
)
<<
grant_encoded
;
// mux for incoming packet
wire
[
DATA_WIDTH
-
1
:
0
]
current_s_tdata
=
s_axis_tdata
[
grant_encoded
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
current_s_tkeep
=
s_axis_tkeep
[
grant_encoded
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
wire
current_s_tvalid
=
s_axis_tvalid
[
grant_encoded
];
wire
current_s_tready
=
s_axis_tready
[
grant_encoded
];
wire
current_s_tlast
=
s_axis_tlast
[
grant_encoded
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_tid
=
s_axis_tid
[
grant_encoded
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
current_s_tdest
=
s_axis_tdest
[
grant_encoded
*
DEST_WIDTH
+:
DEST_WIDTH
];
wire
[
USER_WIDTH
-
1
:
0
]
current_s_tuser
=
s_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_axis_tvalid
&
~
grant
;
assign
acknowledge
=
grant
&
s_axis_tvalid
&
s_axis_tready
&
s_axis_tlast
;
always
@*
begin
// pass through selected packet data
m_axis_tdata_int
=
current_s_tdata
;
m_axis_tkeep_int
=
current_s_tkeep
;
m_axis_tvalid_int
=
current_s_tvalid
&&
m_axis_tready_int_reg
&&
grant_valid
;
m_axis_tlast_int
=
current_s_tlast
;
m_axis_tid_int
=
current_s_tid
;
m_axis_tdest_int
=
current_s_tdest
;
m_axis_tuser_int
=
current_s_tuser
;
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
m_axis_tlast_reg
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_tid_reg
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_tdest_reg
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_tuser_reg
:
{
USER_WIDTH
{
1'b0
}}
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_tready_int_early
=
m_axis_tready
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid_reg
||
!
m_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
// input is ready
if
(
m_axis_tready
||
!
m_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_tready
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
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_tid_reg
<=
m_axis_tid_int
;
m_axis_tdest_reg
<=
m_axis_tdest_int
;
m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_tdata_reg
<=
temp_m_axis_tdata_reg
;
m_axis_tkeep_reg
<=
temp_m_axis_tkeep_reg
;
m_axis_tlast_reg
<=
temp_m_axis_tlast_reg
;
m_axis_tid_reg
<=
temp_m_axis_tid_reg
;
m_axis_tdest_reg
<=
temp_m_axis_tdest_reg
;
m_axis_tuser_reg
<=
temp_m_axis_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_tdata_reg
<=
m_axis_tdata_int
;
temp_m_axis_tkeep_reg
<=
m_axis_tkeep_int
;
temp_m_axis_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tid_reg
<=
m_axis_tid_int
;
temp_m_axis_tdest_reg
<=
m_axis_tdest_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_arb_mux_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream arbitrated mux wrapper with the specified number of ports
"""
from
__future__
import
print_function
import
argparse
import
math
from
jinja2
import
Template
def
main
():
parser
=
argparse
.
ArgumentParser
(
description
=
__doc__
.
strip
())
parser
.
add_argument
(
'-p'
,
'--ports'
,
type
=
int
,
default
=
4
,
help
=
"number of ports"
)
parser
.
add_argument
(
'-n'
,
'--name'
,
type
=
str
,
help
=
"module name"
)
parser
.
add_argument
(
'-o'
,
'--output'
,
type
=
str
,
help
=
"output file name"
)
args
=
parser
.
parse_args
()
try
:
generate
(
**
args
.
__dict__
)
except
IOError
as
ex
:
print
(
ex
)
exit
(
1
)
def
generate
(
ports
=
4
,
name
=
None
,
output
=
None
):
n
=
ports
if
name
is
None
:
name
=
"axis_arb_mux_wrap_{0}"
.
format
(
n
)
if
output
is
None
:
output
=
name
+
".v"
print
(
"Opening file '{0}'..."
.
format
(
output
))
output_file
=
open
(
output
,
'w'
)
print
(
"Generating {0} port AXI stream arbitrated mux wrapper {1}..."
.
format
(
n
,
name
))
cn
=
int
(
math
.
ceil
(
math
.
log
(
n
,
2
)))
t
=
Template
(
u
"""/*
Copyright (c) 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 1ns / 1ps
/*
* AXI4-Stream {{n}} port arbitrated mux (wrapper)
*/
module {{name}} #
(
// Width of AXI stream interfaces in bits
parameter DATA_WIDTH = 8,
// Propagate tkeep signal
parameter KEEP_ENABLE = (DATA_WIDTH>8),
// tkeep signal width (words per cycle)
parameter KEEP_WIDTH = (DATA_WIDTH/8),
// Propagate tid signal
parameter ID_ENABLE = 0,
// tid signal width
parameter ID_WIDTH = 8,
// Propagate tdest signal
parameter DEST_ENABLE = 0,
// tdest signal width
parameter DEST_WIDTH = 8,
// Propagate tuser signal
parameter USER_ENABLE = 1,
// tuser signal width
parameter USER_WIDTH = 1,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "PRIORITY",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
input wire clk,
input wire rst,
/*
* AXI Stream inputs
*/
{%- for p in range(n) %}
input wire [DATA_WIDTH-1:0] s{{'%02d'%p}}_axis_tdata,
input wire [KEEP_WIDTH-1:0] s{{'%02d'%p}}_axis_tkeep,
input wire s{{'%02d'%p}}_axis_tvalid,
output wire s{{'%02d'%p}}_axis_tready,
input wire s{{'%02d'%p}}_axis_tlast,
input wire [ID_WIDTH-1:0] s{{'%02d'%p}}_axis_tid,
input wire [DEST_WIDTH-1:0] s{{'%02d'%p}}_axis_tdest,
input wire [USER_WIDTH-1:0] s{{'%02d'%p}}_axis_tuser,
{% endfor %}
/*
* AXI Stream output
*/
output wire [DATA_WIDTH-1:0] m_axis_tdata,
output wire [KEEP_WIDTH-1:0] m_axis_tkeep,
output wire m_axis_tvalid,
input wire m_axis_tready,
output wire m_axis_tlast,
output wire [ID_WIDTH-1:0] m_axis_tid,
output wire [DEST_WIDTH-1:0] m_axis_tdest,
output wire [USER_WIDTH-1:0] m_axis_tuser
);
axis_arb_mux #(
.S_COUNT({{n}}),
.DATA_WIDTH(DATA_WIDTH),
.KEEP_ENABLE(KEEP_ENABLE),
.KEEP_WIDTH(KEEP_WIDTH),
.ID_ENABLE(ID_ENABLE),
.ID_WIDTH(ID_WIDTH),
.DEST_ENABLE(DEST_ENABLE),
.DEST_WIDTH(DEST_WIDTH),
.USER_ENABLE(USER_ENABLE),
.USER_WIDTH(USER_WIDTH),
.ARB_TYPE(ARB_TYPE),
.LSB_PRIORITY(LSB_PRIORITY)
)
axis_arb_mux_inst (
.clk(clk),
.rst(rst),
// AXI inputs
.s_axis_tdata({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tkeep({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tvalid({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tready({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tready{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tlast({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tid({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tdest({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tuser({ {% for p in range(n-1,-1,-1) %}s{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }),
// AXI output
.m_axis_tdata(m_axis_tdata),
.m_axis_tkeep(m_axis_tkeep),
.m_axis_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
.m_axis_tlast(m_axis_tlast),
.m_axis_tid(m_axis_tid),
.m_axis_tdest(m_axis_tdest),
.m_axis_tuser(m_axis_tuser)
);
endmodule
"""
)
output_file
.
write
(
t
.
render
(
n
=
n
,
cn
=
cn
,
name
=
name
))
print
(
"Done"
)
if
__name__
==
"__main__"
:
main
()
corundum/lib/eth/lib/axis/rtl/axis_async_fifo.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
/*
* AXI4-Stream asynchronous FIFO
*/
module
axis_async_fifo
#
(
// FIFO depth in words
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
// Rounded up to nearest power of 2 cycles
parameter
DEPTH
=
4096
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
// If disabled, tkeep assumed to be 1'b1
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tlast signal
parameter
LAST_ENABLE
=
1
,
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// Frame FIFO mode - operate on frames instead of cycles
// When set, m_axis_tvalid will not be deasserted within a frame
// Requires LAST_ENABLE set
parameter
FRAME_FIFO
=
0
,
// tuser value for bad frame marker
parameter
USER_BAD_FRAME_VALUE
=
1'b1
,
// tuser mask for bad frame marker
parameter
USER_BAD_FRAME_MASK
=
1'b1
,
// Drop frames marked bad
// Requires FRAME_FIFO set
parameter
DROP_BAD_FRAME
=
0
,
// Drop incoming frames when full
// When set, s_axis_tready is always asserted
// Requires FRAME_FIFO set
parameter
DROP_WHEN_FULL
=
0
)
(
/*
* Common asynchronous reset
*/
input
wire
async_rst
,
/*
* AXI input
*/
input
wire
s_clk
,
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
input
wire
m_clk
,
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Status
*/
output
wire
s_status_overflow
,
output
wire
s_status_bad_frame
,
output
wire
s_status_good_frame
,
output
wire
m_status_overflow
,
output
wire
m_status_bad_frame
,
output
wire
m_status_good_frame
);
parameter
ADDR_WIDTH
=
(
KEEP_ENABLE
&&
KEEP_WIDTH
>
1
)
?
$
clog2
(
DEPTH
/
KEEP_WIDTH
)
:
$
clog2
(
DEPTH
);
// check configuration
initial
begin
if
(
FRAME_FIFO
&&
!
LAST_ENABLE
)
begin
$
error
(
"Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"
);
$
finish
;
end
if
(
DROP_BAD_FRAME
&&
!
FRAME_FIFO
)
begin
$
error
(
"Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"
);
$
finish
;
end
if
(
DROP_WHEN_FULL
&&
!
FRAME_FIFO
)
begin
$
error
(
"Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"
);
$
finish
;
end
if
(
DROP_BAD_FRAME
&&
(
USER_BAD_FRAME_MASK
&
{
USER_WIDTH
{
1'b1
}}
)
==
0
)
begin
$
error
(
"Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"
);
$
finish
;
end
end
localparam
KEEP_OFFSET
=
DATA_WIDTH
;
localparam
LAST_OFFSET
=
KEEP_OFFSET
+
(
KEEP_ENABLE
?
KEEP_WIDTH
:
0
);
localparam
ID_OFFSET
=
LAST_OFFSET
+
(
LAST_ENABLE
?
1
:
0
);
localparam
DEST_OFFSET
=
ID_OFFSET
+
(
ID_ENABLE
?
ID_WIDTH
:
0
);
localparam
USER_OFFSET
=
DEST_OFFSET
+
(
DEST_ENABLE
?
DEST_WIDTH
:
0
);
localparam
WIDTH
=
USER_OFFSET
+
(
USER_ENABLE
?
USER_WIDTH
:
0
);
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_cur_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_cur_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_gray_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_gray_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_sync_gray_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_sync_gray_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_cur_gray_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_cur_gray_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_addr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
rd_ptr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
ADDR_WIDTH
:
0
]
rd_ptr_gray_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_gray_next
;
reg
[
ADDR_WIDTH
:
0
]
rd_addr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_gray_sync1_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_gray_sync2_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
rd_ptr_gray_sync1_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
rd_ptr_gray_sync2_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
wr_ptr_update_valid_reg
=
1'b0
,
wr_ptr_update_valid_next
;
reg
wr_ptr_update_reg
=
1'b0
,
wr_ptr_update_next
;
reg
wr_ptr_update_sync1_reg
=
1'b0
;
reg
wr_ptr_update_sync2_reg
=
1'b0
;
reg
wr_ptr_update_sync3_reg
=
1'b0
;
reg
wr_ptr_update_ack_sync1_reg
=
1'b0
;
reg
wr_ptr_update_ack_sync2_reg
=
1'b0
;
reg
s_rst_sync1_reg
=
1'b1
;
reg
s_rst_sync2_reg
=
1'b1
;
reg
s_rst_sync3_reg
=
1'b1
;
reg
m_rst_sync1_reg
=
1'b1
;
reg
m_rst_sync2_reg
=
1'b1
;
reg
m_rst_sync3_reg
=
1'b1
;
reg
[
WIDTH
-
1
:
0
]
mem
[(
2
**
ADDR_WIDTH
)
-
1
:
0
];
reg
[
WIDTH
-
1
:
0
]
mem_read_data_reg
;
reg
mem_read_data_valid_reg
=
1'b0
,
mem_read_data_valid_next
;
wire
[
WIDTH
-
1
:
0
]
s_axis
;
reg
[
WIDTH
-
1
:
0
]
m_axis_reg
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
// full when first TWO MSBs do NOT match, but rest matches
// (gray code equivalent of first MSB different but rest same)
wire
full
=
((
wr_ptr_gray_reg
[
ADDR_WIDTH
]
!=
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_gray_reg
[
ADDR_WIDTH
-
1
]
!=
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
-
1
])
&&
(
wr_ptr_gray_reg
[
ADDR_WIDTH
-
2
:
0
]
==
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
-
2
:
0
]));
wire
full_cur
=
((
wr_ptr_cur_gray_reg
[
ADDR_WIDTH
]
!=
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_cur_gray_reg
[
ADDR_WIDTH
-
1
]
!=
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
-
1
])
&&
(
wr_ptr_cur_gray_reg
[
ADDR_WIDTH
-
2
:
0
]
==
rd_ptr_gray_sync2_reg
[
ADDR_WIDTH
-
2
:
0
]));
// empty when pointers match exactly
wire
empty
=
rd_ptr_gray_reg
==
(
FRAME_FIFO
?
wr_ptr_gray_sync1_reg
:
wr_ptr_gray_sync2_reg
);
// overflow within packet
wire
full_wr
=
((
wr_ptr_reg
[
ADDR_WIDTH
]
!=
wr_ptr_cur_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]
==
wr_ptr_cur_reg
[
ADDR_WIDTH
-
1
:
0
]));
// control signals
reg
write
;
reg
read
;
reg
store_output
;
reg
drop_frame_reg
=
1'b0
,
drop_frame_next
;
reg
overflow_reg
=
1'b0
,
overflow_next
;
reg
bad_frame_reg
=
1'b0
,
bad_frame_next
;
reg
good_frame_reg
=
1'b0
,
good_frame_next
;
reg
overflow_sync1_reg
=
1'b0
;
reg
overflow_sync2_reg
=
1'b0
;
reg
overflow_sync3_reg
=
1'b0
;
reg
overflow_sync4_reg
=
1'b0
;
reg
bad_frame_sync1_reg
=
1'b0
;
reg
bad_frame_sync2_reg
=
1'b0
;
reg
bad_frame_sync3_reg
=
1'b0
;
reg
bad_frame_sync4_reg
=
1'b0
;
reg
good_frame_sync1_reg
=
1'b0
;
reg
good_frame_sync2_reg
=
1'b0
;
reg
good_frame_sync3_reg
=
1'b0
;
reg
good_frame_sync4_reg
=
1'b0
;
assign
s_axis_tready
=
(
FRAME_FIFO
?
(
!
full_cur
||
full_wr
||
DROP_WHEN_FULL
)
:
!
full
)
&&
!
s_rst_sync3_reg
;
generate
assign
s_axis
[
DATA_WIDTH
-
1
:
0
]
=
s_axis_tdata
;
if
(
KEEP_ENABLE
)
assign
s_axis
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
=
s_axis_tkeep
;
if
(
LAST_ENABLE
)
assign
s_axis
[
LAST_OFFSET
]
=
s_axis_tlast
;
if
(
ID_ENABLE
)
assign
s_axis
[
ID_OFFSET
+:
ID_WIDTH
]
=
s_axis_tid
;
if
(
DEST_ENABLE
)
assign
s_axis
[
DEST_OFFSET
+:
DEST_WIDTH
]
=
s_axis_tdest
;
if
(
USER_ENABLE
)
assign
s_axis
[
USER_OFFSET
+:
USER_WIDTH
]
=
s_axis_tuser
;
endgenerate
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tdata
=
m_axis_reg
[
DATA_WIDTH
-
1
:
0
];
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_reg
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tlast
=
LAST_ENABLE
?
m_axis_reg
[
LAST_OFFSET
]
:
1'b1
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_reg
[
ID_OFFSET
+:
ID_WIDTH
]
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_reg
[
DEST_OFFSET
+:
DEST_WIDTH
]
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_reg
[
USER_OFFSET
+:
USER_WIDTH
]
:
{
USER_WIDTH
{
1'b0
}}
;
assign
s_status_overflow
=
overflow_reg
;
assign
s_status_bad_frame
=
bad_frame_reg
;
assign
s_status_good_frame
=
good_frame_reg
;
assign
m_status_overflow
=
overflow_sync3_reg
^
overflow_sync4_reg
;
assign
m_status_bad_frame
=
bad_frame_sync3_reg
^
bad_frame_sync4_reg
;
assign
m_status_good_frame
=
good_frame_sync3_reg
^
good_frame_sync4_reg
;
// reset synchronization
always
@
(
posedge
s_clk
or
posedge
async_rst
)
begin
if
(
async_rst
)
begin
s_rst_sync1_reg
<=
1'b1
;
s_rst_sync2_reg
<=
1'b1
;
s_rst_sync3_reg
<=
1'b1
;
end
else
begin
s_rst_sync1_reg
<=
1'b0
;
s_rst_sync2_reg
<=
s_rst_sync1_reg
||
m_rst_sync1_reg
;
s_rst_sync3_reg
<=
s_rst_sync2_reg
;
end
end
always
@
(
posedge
m_clk
or
posedge
async_rst
)
begin
if
(
async_rst
)
begin
m_rst_sync1_reg
<=
1'b1
;
m_rst_sync2_reg
<=
1'b1
;
m_rst_sync3_reg
<=
1'b1
;
end
else
begin
m_rst_sync1_reg
<=
1'b0
;
m_rst_sync2_reg
<=
s_rst_sync1_reg
||
m_rst_sync1_reg
;
m_rst_sync3_reg
<=
m_rst_sync2_reg
;
end
end
// Write logic
always
@*
begin
write
=
1'b0
;
drop_frame_next
=
drop_frame_reg
;
overflow_next
=
1'b0
;
bad_frame_next
=
1'b0
;
good_frame_next
=
1'b0
;
wr_ptr_next
=
wr_ptr_reg
;
wr_ptr_cur_next
=
wr_ptr_cur_reg
;
wr_ptr_gray_next
=
wr_ptr_gray_reg
;
wr_ptr_sync_gray_next
=
wr_ptr_sync_gray_reg
;
wr_ptr_cur_gray_next
=
wr_ptr_cur_gray_reg
;
wr_ptr_update_valid_next
=
wr_ptr_update_valid_reg
;
wr_ptr_update_next
=
wr_ptr_update_reg
;
if
(
FRAME_FIFO
&&
wr_ptr_update_valid_reg
)
begin
// have updated pointer to sync
if
(
wr_ptr_update_next
==
wr_ptr_update_ack_sync2_reg
)
begin
// no sync in progress; sync update
wr_ptr_update_valid_next
=
1'b0
;
wr_ptr_sync_gray_next
=
wr_ptr_gray_reg
;
wr_ptr_update_next
=
!
wr_ptr_update_ack_sync2_reg
;
end
end
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// transfer in
if
(
!
FRAME_FIFO
)
begin
// normal FIFO mode
write
=
1'b1
;
wr_ptr_next
=
wr_ptr_reg
+
1
;
wr_ptr_gray_next
=
wr_ptr_next
^
(
wr_ptr_next
>>
1
);
end
else
if
(
full_cur
||
full_wr
||
drop_frame_reg
)
begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next
=
1'b1
;
if
(
s_axis_tlast
)
begin
// end of frame, reset write pointer
wr_ptr_cur_next
=
wr_ptr_reg
;
wr_ptr_cur_gray_next
=
wr_ptr_cur_next
^
(
wr_ptr_cur_next
>>
1
);
drop_frame_next
=
1'b0
;
overflow_next
=
1'b1
;
end
end
else
begin
write
=
1'b1
;
wr_ptr_cur_next
=
wr_ptr_cur_reg
+
1
;
wr_ptr_cur_gray_next
=
wr_ptr_cur_next
^
(
wr_ptr_cur_next
>>
1
);
if
(
s_axis_tlast
)
begin
// end of frame
if
(
DROP_BAD_FRAME
&&
USER_BAD_FRAME_MASK
&
~
(
s_axis_tuser
^
USER_BAD_FRAME_VALUE
))
begin
// bad packet, reset write pointer
wr_ptr_cur_next
=
wr_ptr_reg
;
wr_ptr_cur_gray_next
=
wr_ptr_cur_next
^
(
wr_ptr_cur_next
>>
1
);
bad_frame_next
=
1'b1
;
end
else
begin
// good packet, update write pointer
wr_ptr_next
=
wr_ptr_cur_reg
+
1
;
wr_ptr_gray_next
=
wr_ptr_next
^
(
wr_ptr_next
>>
1
);
if
(
wr_ptr_update_next
==
wr_ptr_update_ack_sync2_reg
)
begin
// no sync in progress; sync update
wr_ptr_update_valid_next
=
1'b0
;
wr_ptr_sync_gray_next
=
wr_ptr_gray_next
;
wr_ptr_update_next
=
!
wr_ptr_update_ack_sync2_reg
;
end
else
begin
// sync in progress; flag it for later
wr_ptr_update_valid_next
=
1'b1
;
end
good_frame_next
=
1'b1
;
end
end
end
end
end
always
@
(
posedge
s_clk
)
begin
if
(
s_rst_sync3_reg
)
begin
wr_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_cur_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_gray_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_sync_gray_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_cur_gray_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_update_valid_reg
<=
1'b0
;
wr_ptr_update_reg
<=
1'b0
;
drop_frame_reg
<=
1'b0
;
overflow_reg
<=
1'b0
;
bad_frame_reg
<=
1'b0
;
good_frame_reg
<=
1'b0
;
end
else
begin
wr_ptr_reg
<=
wr_ptr_next
;
wr_ptr_cur_reg
<=
wr_ptr_cur_next
;
wr_ptr_gray_reg
<=
wr_ptr_gray_next
;
wr_ptr_sync_gray_reg
<=
wr_ptr_sync_gray_next
;
wr_ptr_cur_gray_reg
<=
wr_ptr_cur_gray_next
;
wr_ptr_update_valid_reg
<=
wr_ptr_update_valid_next
;
wr_ptr_update_reg
<=
wr_ptr_update_next
;
drop_frame_reg
<=
drop_frame_next
;
overflow_reg
<=
overflow_next
;
bad_frame_reg
<=
bad_frame_next
;
good_frame_reg
<=
good_frame_next
;
end
if
(
FRAME_FIFO
)
begin
wr_addr_reg
<=
wr_ptr_cur_next
;
end
else
begin
wr_addr_reg
<=
wr_ptr_next
;
end
if
(
write
)
begin
mem
[
wr_addr_reg
[
ADDR_WIDTH
-
1
:
0
]]
<=
s_axis
;
end
end
// pointer synchronization
always
@
(
posedge
s_clk
)
begin
if
(
s_rst_sync3_reg
)
begin
rd_ptr_gray_sync1_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
rd_ptr_gray_sync2_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_update_ack_sync1_reg
<=
1'b0
;
wr_ptr_update_ack_sync2_reg
<=
1'b0
;
end
else
begin
rd_ptr_gray_sync1_reg
<=
rd_ptr_gray_reg
;
rd_ptr_gray_sync2_reg
<=
rd_ptr_gray_sync1_reg
;
wr_ptr_update_ack_sync1_reg
<=
wr_ptr_update_sync3_reg
;
wr_ptr_update_ack_sync2_reg
<=
wr_ptr_update_ack_sync1_reg
;
end
end
always
@
(
posedge
m_clk
)
begin
if
(
m_rst_sync3_reg
)
begin
wr_ptr_gray_sync1_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_gray_sync2_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_update_sync1_reg
<=
1'b0
;
wr_ptr_update_sync2_reg
<=
1'b0
;
wr_ptr_update_sync3_reg
<=
1'b0
;
end
else
begin
if
(
!
FRAME_FIFO
)
begin
wr_ptr_gray_sync1_reg
<=
wr_ptr_gray_reg
;
end
else
if
(
wr_ptr_update_sync2_reg
^
wr_ptr_update_sync3_reg
)
begin
wr_ptr_gray_sync1_reg
<=
wr_ptr_sync_gray_reg
;
end
wr_ptr_gray_sync2_reg
<=
wr_ptr_gray_sync1_reg
;
wr_ptr_update_sync1_reg
<=
wr_ptr_update_reg
;
wr_ptr_update_sync2_reg
<=
wr_ptr_update_sync1_reg
;
wr_ptr_update_sync3_reg
<=
wr_ptr_update_sync2_reg
;
end
end
// status synchronization
always
@
(
posedge
s_clk
)
begin
if
(
s_rst_sync3_reg
)
begin
overflow_sync1_reg
<=
1'b0
;
bad_frame_sync1_reg
<=
1'b0
;
good_frame_sync1_reg
<=
1'b0
;
end
else
begin
overflow_sync1_reg
<=
overflow_sync1_reg
^
overflow_reg
;
bad_frame_sync1_reg
<=
bad_frame_sync1_reg
^
bad_frame_reg
;
good_frame_sync1_reg
<=
good_frame_sync1_reg
^
good_frame_reg
;
end
end
always
@
(
posedge
m_clk
)
begin
if
(
m_rst_sync3_reg
)
begin
overflow_sync2_reg
<=
1'b0
;
overflow_sync3_reg
<=
1'b0
;
overflow_sync4_reg
<=
1'b0
;
bad_frame_sync2_reg
<=
1'b0
;
bad_frame_sync3_reg
<=
1'b0
;
bad_frame_sync4_reg
<=
1'b0
;
good_frame_sync2_reg
<=
1'b0
;
good_frame_sync3_reg
<=
1'b0
;
good_frame_sync4_reg
<=
1'b0
;
end
else
begin
overflow_sync2_reg
<=
overflow_sync1_reg
;
overflow_sync3_reg
<=
overflow_sync2_reg
;
overflow_sync4_reg
<=
overflow_sync3_reg
;
bad_frame_sync2_reg
<=
bad_frame_sync1_reg
;
bad_frame_sync3_reg
<=
bad_frame_sync2_reg
;
bad_frame_sync4_reg
<=
bad_frame_sync3_reg
;
good_frame_sync2_reg
<=
good_frame_sync1_reg
;
good_frame_sync3_reg
<=
good_frame_sync2_reg
;
good_frame_sync4_reg
<=
good_frame_sync3_reg
;
end
end
// Read logic
always
@*
begin
read
=
1'b0
;
rd_ptr_next
=
rd_ptr_reg
;
rd_ptr_gray_next
=
rd_ptr_gray_reg
;
mem_read_data_valid_next
=
mem_read_data_valid_reg
;
if
(
store_output
||
!
mem_read_data_valid_reg
)
begin
// output data not valid OR currently being transferred
if
(
!
empty
)
begin
// not empty, perform read
read
=
1'b1
;
mem_read_data_valid_next
=
1'b1
;
rd_ptr_next
=
rd_ptr_reg
+
1
;
rd_ptr_gray_next
=
rd_ptr_next
^
(
rd_ptr_next
>>
1
);
end
else
begin
// empty, invalidate
mem_read_data_valid_next
=
1'b0
;
end
end
end
always
@
(
posedge
m_clk
)
begin
if
(
m_rst_sync3_reg
)
begin
rd_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
rd_ptr_gray_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
mem_read_data_valid_reg
<=
1'b0
;
end
else
begin
rd_ptr_reg
<=
rd_ptr_next
;
rd_ptr_gray_reg
<=
rd_ptr_gray_next
;
mem_read_data_valid_reg
<=
mem_read_data_valid_next
;
end
rd_addr_reg
<=
rd_ptr_next
;
if
(
read
)
begin
mem_read_data_reg
<=
mem
[
rd_addr_reg
[
ADDR_WIDTH
-
1
:
0
]];
end
end
// Output register
always
@*
begin
store_output
=
1'b0
;
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
if
(
m_axis_tready
||
!
m_axis_tvalid
)
begin
store_output
=
1'b1
;
m_axis_tvalid_next
=
mem_read_data_valid_reg
;
end
end
always
@
(
posedge
m_clk
)
begin
if
(
m_rst_sync3_reg
)
begin
m_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
end
if
(
store_output
)
begin
m_axis_reg
<=
mem_read_data_reg
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_async_fifo_adapter.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 asynchronous FIFO with width converter
*/
module
axis_async_fifo_adapter
#
(
// FIFO depth in words
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
// Rounded up to nearest power of 2 cycles
parameter
DEPTH
=
4096
,
// Width of input AXI stream interface in bits
parameter
S_DATA_WIDTH
=
8
,
// Propagate tkeep signal on input interface
// If disabled, tkeep assumed to be 1'b1
parameter
S_KEEP_ENABLE
=
(
S_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on input interface
parameter
S_KEEP_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output AXI stream interface in bits
parameter
M_DATA_WIDTH
=
8
,
// Propagate tkeep signal on output interface
// If disabled, tkeep assumed to be 1'b1
parameter
M_KEEP_ENABLE
=
(
M_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on output interface
parameter
M_KEEP_WIDTH
=
(
M_DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// Frame FIFO mode - operate on frames instead of cycles
// When set, m_axis_tvalid will not be deasserted within a frame
// Requires LAST_ENABLE set
parameter
FRAME_FIFO
=
0
,
// tuser value for bad frame marker
parameter
USER_BAD_FRAME_VALUE
=
1'b1
,
// tuser mask for bad frame marker
parameter
USER_BAD_FRAME_MASK
=
1'b1
,
// Drop frames marked bad
// Requires FRAME_FIFO set
parameter
DROP_BAD_FRAME
=
0
,
// Drop incoming frames when full
// When set, s_axis_tready is always asserted
// Requires FRAME_FIFO set
parameter
DROP_WHEN_FULL
=
0
)
(
/*
* AXI input
*/
input
wire
s_clk
,
input
wire
s_rst
,
input
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
input
wire
m_clk
,
input
wire
m_rst
,
output
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Status
*/
output
wire
s_status_overflow
,
output
wire
s_status_bad_frame
,
output
wire
s_status_good_frame
,
output
wire
m_status_overflow
,
output
wire
m_status_bad_frame
,
output
wire
m_status_good_frame
);
// force keep width to 1 when disabled
parameter
S_KEEP_WIDTH_INT
=
S_KEEP_ENABLE
?
S_KEEP_WIDTH
:
1
;
parameter
M_KEEP_WIDTH_INT
=
M_KEEP_ENABLE
?
M_KEEP_WIDTH
:
1
;
// bus word sizes (must be identical)
parameter
S_DATA_WORD_SIZE
=
S_DATA_WIDTH
/
S_KEEP_WIDTH_INT
;
parameter
M_DATA_WORD_SIZE
=
M_DATA_WIDTH
/
M_KEEP_WIDTH_INT
;
// output bus is wider
parameter
EXPAND_BUS
=
M_KEEP_WIDTH_INT
>
S_KEEP_WIDTH_INT
;
// total data and keep widths
parameter
DATA_WIDTH
=
EXPAND_BUS
?
M_DATA_WIDTH
:
S_DATA_WIDTH
;
parameter
KEEP_WIDTH
=
EXPAND_BUS
?
M_KEEP_WIDTH_INT
:
S_KEEP_WIDTH_INT
;
// bus width assertions
initial
begin
if
(
S_DATA_WORD_SIZE
*
S_KEEP_WIDTH_INT
!=
S_DATA_WIDTH
)
begin
$
error
(
"Error: input data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
M_DATA_WORD_SIZE
*
M_KEEP_WIDTH_INT
!=
M_DATA_WIDTH
)
begin
$
error
(
"Error: output data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
S_DATA_WORD_SIZE
!=
M_DATA_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
end
wire
[
DATA_WIDTH
-
1
:
0
]
pre_fifo_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
pre_fifo_axis_tkeep
;
wire
pre_fifo_axis_tvalid
;
wire
pre_fifo_axis_tready
;
wire
pre_fifo_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
pre_fifo_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
pre_fifo_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
pre_fifo_axis_tuser
;
wire
[
DATA_WIDTH
-
1
:
0
]
post_fifo_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
post_fifo_axis_tkeep
;
wire
post_fifo_axis_tvalid
;
wire
post_fifo_axis_tready
;
wire
post_fifo_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
post_fifo_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
post_fifo_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
post_fifo_axis_tuser
;
generate
if
(
M_KEEP_WIDTH
==
S_KEEP_WIDTH
)
begin
// same width, no adapter needed
assign
pre_fifo_axis_tdata
=
s_axis_tdata
;
assign
pre_fifo_axis_tkeep
=
s_axis_tkeep
;
assign
pre_fifo_axis_tvalid
=
s_axis_tvalid
;
assign
s_axis_tready
=
pre_fifo_axis_tready
;
assign
pre_fifo_axis_tlast
=
s_axis_tlast
;
assign
pre_fifo_axis_tid
=
s_axis_tid
;
assign
pre_fifo_axis_tdest
=
s_axis_tdest
;
assign
pre_fifo_axis_tuser
=
s_axis_tuser
;
assign
m_axis_tdata
=
post_fifo_axis_tdata
;
assign
m_axis_tkeep
=
post_fifo_axis_tkeep
;
assign
m_axis_tvalid
=
post_fifo_axis_tvalid
;
assign
post_fifo_axis_tready
=
m_axis_tready
;
assign
m_axis_tlast
=
post_fifo_axis_tlast
;
assign
m_axis_tid
=
post_fifo_axis_tid
;
assign
m_axis_tdest
=
post_fifo_axis_tdest
;
assign
m_axis_tuser
=
post_fifo_axis_tuser
;
end
else
if
(
EXPAND_BUS
)
begin
// output wider, adapt width before FIFO
axis_adapter
#(
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_KEEP_ENABLE
(
S_KEEP_ENABLE
),
.
S_KEEP_WIDTH
(
S_KEEP_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_KEEP_ENABLE
(
M_KEEP_ENABLE
),
.
M_KEEP_WIDTH
(
M_KEEP_WIDTH
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
)
)
adapter_inst
(
.
clk
(
s_clk
),
.
rst
(
s_rst
),
// AXI input
.
s_axis_tdata
(
s_axis_tdata
),
.
s_axis_tkeep
(
s_axis_tkeep
),
.
s_axis_tvalid
(
s_axis_tvalid
),
.
s_axis_tready
(
s_axis_tready
),
.
s_axis_tlast
(
s_axis_tlast
),
.
s_axis_tid
(
s_axis_tid
),
.
s_axis_tdest
(
s_axis_tdest
),
.
s_axis_tuser
(
s_axis_tuser
),
// AXI output
.
m_axis_tdata
(
pre_fifo_axis_tdata
),
.
m_axis_tkeep
(
pre_fifo_axis_tkeep
),
.
m_axis_tvalid
(
pre_fifo_axis_tvalid
),
.
m_axis_tready
(
pre_fifo_axis_tready
),
.
m_axis_tlast
(
pre_fifo_axis_tlast
),
.
m_axis_tid
(
pre_fifo_axis_tid
),
.
m_axis_tdest
(
pre_fifo_axis_tdest
),
.
m_axis_tuser
(
pre_fifo_axis_tuser
)
);
assign
m_axis_tdata
=
post_fifo_axis_tdata
;
assign
m_axis_tkeep
=
post_fifo_axis_tkeep
;
assign
m_axis_tvalid
=
post_fifo_axis_tvalid
;
assign
post_fifo_axis_tready
=
m_axis_tready
;
assign
m_axis_tlast
=
post_fifo_axis_tlast
;
assign
m_axis_tid
=
post_fifo_axis_tid
;
assign
m_axis_tdest
=
post_fifo_axis_tdest
;
assign
m_axis_tuser
=
post_fifo_axis_tuser
;
end
else
begin
// input wider, adapt width after FIFO
assign
pre_fifo_axis_tdata
=
s_axis_tdata
;
assign
pre_fifo_axis_tkeep
=
s_axis_tkeep
;
assign
pre_fifo_axis_tvalid
=
s_axis_tvalid
;
assign
s_axis_tready
=
pre_fifo_axis_tready
;
assign
pre_fifo_axis_tlast
=
s_axis_tlast
;
assign
pre_fifo_axis_tid
=
s_axis_tid
;
assign
pre_fifo_axis_tdest
=
s_axis_tdest
;
assign
pre_fifo_axis_tuser
=
s_axis_tuser
;
axis_adapter
#(
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_KEEP_ENABLE
(
S_KEEP_ENABLE
),
.
S_KEEP_WIDTH
(
S_KEEP_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_KEEP_ENABLE
(
M_KEEP_ENABLE
),
.
M_KEEP_WIDTH
(
M_KEEP_WIDTH
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
)
)
adapter_inst
(
.
clk
(
m_clk
),
.
rst
(
m_rst
),
// AXI input
.
s_axis_tdata
(
post_fifo_axis_tdata
),
.
s_axis_tkeep
(
post_fifo_axis_tkeep
),
.
s_axis_tvalid
(
post_fifo_axis_tvalid
),
.
s_axis_tready
(
post_fifo_axis_tready
),
.
s_axis_tlast
(
post_fifo_axis_tlast
),
.
s_axis_tid
(
post_fifo_axis_tid
),
.
s_axis_tdest
(
post_fifo_axis_tdest
),
.
s_axis_tuser
(
post_fifo_axis_tuser
),
// AXI output
.
m_axis_tdata
(
m_axis_tdata
),
.
m_axis_tkeep
(
m_axis_tkeep
),
.
m_axis_tvalid
(
m_axis_tvalid
),
.
m_axis_tready
(
m_axis_tready
),
.
m_axis_tlast
(
m_axis_tlast
),
.
m_axis_tid
(
m_axis_tid
),
.
m_axis_tdest
(
m_axis_tdest
),
.
m_axis_tuser
(
m_axis_tuser
)
);
end
endgenerate
axis_async_fifo
#(
.
DEPTH
(
DEPTH
),
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
EXPAND_BUS
?
M_KEEP_ENABLE
:
S_KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
),
.
FRAME_FIFO
(
FRAME_FIFO
),
.
USER_BAD_FRAME_VALUE
(
USER_BAD_FRAME_VALUE
),
.
USER_BAD_FRAME_MASK
(
USER_BAD_FRAME_MASK
),
.
DROP_BAD_FRAME
(
DROP_BAD_FRAME
),
.
DROP_WHEN_FULL
(
DROP_WHEN_FULL
)
)
fifo_inst
(
// Common reset
.
async_rst
(
s_rst
|
m_rst
),
// AXI input
.
s_clk
(
s_clk
),
.
s_axis_tdata
(
pre_fifo_axis_tdata
),
.
s_axis_tkeep
(
pre_fifo_axis_tkeep
),
.
s_axis_tvalid
(
pre_fifo_axis_tvalid
),
.
s_axis_tready
(
pre_fifo_axis_tready
),
.
s_axis_tlast
(
pre_fifo_axis_tlast
),
.
s_axis_tid
(
pre_fifo_axis_tid
),
.
s_axis_tdest
(
pre_fifo_axis_tdest
),
.
s_axis_tuser
(
pre_fifo_axis_tuser
),
// AXI output
.
m_clk
(
m_clk
),
.
m_axis_tdata
(
post_fifo_axis_tdata
),
.
m_axis_tkeep
(
post_fifo_axis_tkeep
),
.
m_axis_tvalid
(
post_fifo_axis_tvalid
),
.
m_axis_tready
(
post_fifo_axis_tready
),
.
m_axis_tlast
(
post_fifo_axis_tlast
),
.
m_axis_tid
(
post_fifo_axis_tid
),
.
m_axis_tdest
(
post_fifo_axis_tdest
),
.
m_axis_tuser
(
post_fifo_axis_tuser
),
// Status
.
s_status_overflow
(
s_status_overflow
),
.
s_status_bad_frame
(
s_status_bad_frame
),
.
s_status_good_frame
(
s_status_good_frame
),
.
m_status_overflow
(
m_status_overflow
),
.
m_status_bad_frame
(
m_status_bad_frame
),
.
m_status_good_frame
(
m_status_good_frame
)
);
endmodule
corundum/lib/eth/lib/axis/rtl/axis_broadcast.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 broadcaster
*/
module
axis_broadcast
#
(
// Number of AXI stream outputs
parameter
M_COUNT
=
4
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tlast signal
parameter
LAST_ENABLE
=
1
,
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
)
(
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
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI outputs
*/
output
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_COUNT
*
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axis_tready
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tlast
,
output
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
M_COUNT
*
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
M_COUNT
*
USER_WIDTH
-
1
:
0
]
m_axis_tuser
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
// datapath registers
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
-
1
:
0
]
m_axis_tvalid_reg
=
{
M_COUNT
{
1'b0
}}
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// // datapath control
reg
store_axis_input_to_output
;
reg
store_axis_input_to_temp
;
reg
store_axis_temp_to_output
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
m_axis_tdata
=
{
M_COUNT
{
m_axis_tdata_reg
}}
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
{
M_COUNT
{
m_axis_tkeep_reg
}}
:
{
M_COUNT
*
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
LAST_ENABLE
?
{
M_COUNT
{
m_axis_tlast_reg
}}
:
{
M_COUNT
{
1'b1
}}
;
assign
m_axis_tid
=
ID_ENABLE
?
{
M_COUNT
{
m_axis_tid_reg
}}
:
{
M_COUNT
*
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
{
M_COUNT
{
m_axis_tdest_reg
}}
:
{
M_COUNT
*
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
{
M_COUNT
{
m_axis_tuser_reg
}}
:
{
M_COUNT
*
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)
wire
s_axis_tready_early
=
((
m_axis_tready
&
m_axis_tvalid
)
==
m_axis_tvalid
)
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid
||
!
s_axis_tvalid
));
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
&
~
m_axis_tready
;
temp_m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
store_axis_input_to_output
=
1'b0
;
store_axis_input_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
s_axis_tready_reg
)
begin
// input is ready
if
(((
m_axis_tready
&
m_axis_tvalid
)
==
m_axis_tvalid
)
||
!
m_axis_tvalid
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
{
M_COUNT
{
s_axis_tvalid
}}
;
store_axis_input_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next
=
s_axis_tvalid
;
store_axis_input_to_temp
=
1'b1
;
end
end
else
if
((
m_axis_tready
&
m_axis_tvalid
)
==
m_axis_tvalid
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
{
M_COUNT
{
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
s_axis_tready_reg
<=
1'b0
;
m_axis_tvalid_reg
<=
{
M_COUNT
{
1'b0
}}
;
temp_m_axis_tvalid_reg
<=
{
M_COUNT
{
1'b0
}}
;
end
else
begin
s_axis_tready_reg
<=
s_axis_tready_early
;
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
temp_m_axis_tvalid_reg
<=
temp_m_axis_tvalid_next
;
end
// datapath
if
(
store_axis_input_to_output
)
begin
m_axis_tdata_reg
<=
s_axis_tdata
;
m_axis_tkeep_reg
<=
s_axis_tkeep
;
m_axis_tlast_reg
<=
s_axis_tlast
;
m_axis_tid_reg
<=
s_axis_tid
;
m_axis_tdest_reg
<=
s_axis_tdest
;
m_axis_tuser_reg
<=
s_axis_tuser
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_tdata_reg
<=
temp_m_axis_tdata_reg
;
m_axis_tkeep_reg
<=
temp_m_axis_tkeep_reg
;
m_axis_tlast_reg
<=
temp_m_axis_tlast_reg
;
m_axis_tid_reg
<=
temp_m_axis_tid_reg
;
m_axis_tdest_reg
<=
temp_m_axis_tdest_reg
;
m_axis_tuser_reg
<=
temp_m_axis_tuser_reg
;
end
if
(
store_axis_input_to_temp
)
begin
temp_m_axis_tdata_reg
<=
s_axis_tdata
;
temp_m_axis_tkeep_reg
<=
s_axis_tkeep
;
temp_m_axis_tlast_reg
<=
s_axis_tlast
;
temp_m_axis_tid_reg
<=
s_axis_tid
;
temp_m_axis_tdest_reg
<=
s_axis_tdest
;
temp_m_axis_tuser_reg
<=
s_axis_tuser
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_cobs_decode.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2016-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream consistent overhead byte stuffing (COBS) decoder
*/
module
axis_cobs_decode
(
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
);
// state register
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_SEGMENT
=
2'd1
,
STATE_NEXT_SEGMENT
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
7
:
0
]
count_reg
=
8'd0
,
count_next
;
reg
suppress_zero_reg
=
1'b0
,
suppress_zero_next
;
reg
[
7
:
0
]
temp_tdata_reg
=
8'd0
,
temp_tdata_next
;
reg
temp_tvalid_reg
=
1'b0
,
temp_tvalid_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
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
always
@*
begin
state_next
=
STATE_IDLE
;
count_next
=
count_reg
;
suppress_zero_next
=
suppress_zero_reg
;
temp_tdata_next
=
temp_tdata_reg
;
temp_tvalid_next
=
temp_tvalid_reg
;
m_axis_tdata_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
s_axis_tready_next
=
1'b0
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state
s_axis_tready_next
=
m_axis_tready_int_early
||
!
temp_tvalid_reg
;
// output final word
m_axis_tdata_int
=
temp_tdata_reg
;
m_axis_tvalid_int
=
temp_tvalid_reg
;
m_axis_tlast_int
=
temp_tvalid_reg
;
temp_tvalid_next
=
temp_tvalid_reg
&&
!
m_axis_tready_int_reg
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// valid input data
// skip any leading zeros
if
(
s_axis_tdata
!=
8'd0
)
begin
// store count value and zero suppress
count_next
=
s_axis_tdata
-
1
;
suppress_zero_next
=
(
s_axis_tdata
==
8'd255
);
s_axis_tready_next
=
m_axis_tready_int_early
;
if
(
s_axis_tdata
==
8'd1
)
begin
// next byte will be count value
state_next
=
STATE_NEXT_SEGMENT
;
end
else
begin
// next byte will be data
state_next
=
STATE_SEGMENT
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_SEGMENT:
begin
// receive segment
s_axis_tready_next
=
m_axis_tready_int_early
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// valid input data
// store in temp register
temp_tdata_next
=
s_axis_tdata
;
temp_tvalid_next
=
1'b1
;
// move temp to output
m_axis_tdata_int
=
temp_tdata_reg
;
m_axis_tvalid_int
=
temp_tvalid_reg
;
// decrement count
count_next
=
count_reg
-
1
;
if
(
s_axis_tdata
==
8'd0
)
begin
// got a zero byte in a frame - mark it as an error and re-sync
temp_tvalid_next
=
1'b0
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
if
(
s_axis_tlast
)
begin
// end of frame
if
(
count_reg
==
8'd1
&&
!
s_axis_tuser
)
begin
// end of frame indication at correct time, go to idle to output final byte
state_next
=
STATE_IDLE
;
end
else
begin
// end of frame indication at invalid time or tuser assert, so mark as an error and re-sync
temp_tvalid_next
=
1'b0
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
if
(
count_reg
==
8'd1
)
begin
// next byte will be count value
state_next
=
STATE_NEXT_SEGMENT
;
end
else
begin
// next byte will be data
state_next
=
STATE_SEGMENT
;
end
end
else
begin
state_next
=
STATE_SEGMENT
;
end
end
STATE_NEXT_SEGMENT:
begin
// next segment
s_axis_tready_next
=
m_axis_tready_int_early
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// valid input data
// store zero in temp if not suppressed
temp_tdata_next
=
8'd0
;
temp_tvalid_next
=
!
suppress_zero_reg
;
// move temp to output
m_axis_tdata_int
=
temp_tdata_reg
;
m_axis_tvalid_int
=
temp_tvalid_reg
;
if
(
s_axis_tdata
==
8'd0
)
begin
// got a zero byte delineating the end of the frame, so mark as such and re-sync
temp_tvalid_next
=
1'b0
;
m_axis_tuser_int
=
s_axis_tuser
;
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
else
if
(
s_axis_tlast
)
begin
if
(
s_axis_tdata
==
8'd1
&&
!
s_axis_tuser
)
begin
// end of frame indication at correct time, go to idle to output final byte
state_next
=
STATE_IDLE
;
end
else
begin
// end of frame indication at invalid time or tuser assert, so mark as an error and re-sync
temp_tvalid_next
=
1'b0
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tuser_int
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
s_axis_tready_next
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
// otherwise, store count value and zero suppress
count_next
=
s_axis_tdata
-
1
;
suppress_zero_next
=
(
s_axis_tdata
==
8'd255
);
s_axis_tready_next
=
m_axis_tready_int_early
;
if
(
s_axis_tdata
==
8'd1
)
begin
// next byte will be count value
state_next
=
STATE_NEXT_SEGMENT
;
end
else
begin
// next byte will be data
state_next
=
STATE_SEGMENT
;
end
end
end
else
begin
state_next
=
STATE_NEXT_SEGMENT
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
temp_tvalid_reg
<=
1'b0
;
s_axis_tready_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
temp_tvalid_reg
<=
temp_tvalid_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
end
temp_tdata_reg
<=
temp_tdata_next
;
count_reg
<=
count_next
;
suppress_zero_reg
<=
suppress_zero_next
;
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/lib/axis/rtl/axis_cobs_encode.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2016-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream consistent overhead byte stuffing (COBS) encoder
*/
module
axis_cobs_encode
#
(
// append zero for in band framing
parameter
APPEND_ZERO
=
1
)
(
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
);
// state register
localparam
[
1
:
0
]
INPUT_STATE_IDLE
=
2'd0
,
INPUT_STATE_SEGMENT
=
2'd1
,
INPUT_STATE_FINAL_ZERO
=
2'd2
,
INPUT_STATE_APPEND_ZERO
=
2'd3
;
reg
[
1
:
0
]
input_state_reg
=
INPUT_STATE_IDLE
,
input_state_next
;
localparam
[
0
:
0
]
OUTPUT_STATE_IDLE
=
1'd0
,
OUTPUT_STATE_SEGMENT
=
1'd1
;
reg
[
0
:
0
]
output_state_reg
=
OUTPUT_STATE_IDLE
,
output_state_next
;
reg
[
7
:
0
]
input_count_reg
=
8'd0
,
input_count_next
;
reg
[
7
:
0
]
output_count_reg
=
8'd0
,
output_count_next
;
reg
fail_frame_reg
=
1'b0
,
fail_frame_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
;
reg
s_axis_tready_mask
;
reg
[
7
:
0
]
code_fifo_in_tdata
;
reg
code_fifo_in_tvalid
;
reg
code_fifo_in_tlast
;
reg
code_fifo_in_tuser
;
wire
code_fifo_in_tready
;
wire
[
7
:
0
]
code_fifo_out_tdata
;
wire
code_fifo_out_tvalid
;
wire
code_fifo_out_tlast
;
wire
code_fifo_out_tuser
;
reg
code_fifo_out_tready
;
assign
s_axis_tready
=
code_fifo_in_tready
&&
data_fifo_in_tready
&&
s_axis_tready_mask
;
axis_fifo
#(
.
DEPTH
(
256
),
.
DATA_WIDTH
(
8
),
.
KEEP_ENABLE
(
0
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
0
),
.
DEST_ENABLE
(
0
),
.
USER_ENABLE
(
1
),
.
USER_WIDTH
(
1
),
.
FRAME_FIFO
(
0
)
)
code_fifo_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
code_fifo_in_tdata
),
.
s_axis_tkeep
(
0
),
.
s_axis_tvalid
(
code_fifo_in_tvalid
),
.
s_axis_tready
(
code_fifo_in_tready
),
.
s_axis_tlast
(
code_fifo_in_tlast
),
.
s_axis_tid
(
0
),
.
s_axis_tdest
(
0
),
.
s_axis_tuser
(
code_fifo_in_tuser
),
// AXI output
.
m_axis_tdata
(
code_fifo_out_tdata
),
.
m_axis_tkeep
(),
.
m_axis_tvalid
(
code_fifo_out_tvalid
),
.
m_axis_tready
(
code_fifo_out_tready
),
.
m_axis_tlast
(
code_fifo_out_tlast
),
.
m_axis_tid
(),
.
m_axis_tdest
(),
.
m_axis_tuser
(
code_fifo_out_tuser
),
// Status
.
status_overflow
(),
.
status_bad_frame
(),
.
status_good_frame
()
);
reg
[
7
:
0
]
data_fifo_in_tdata
;
reg
data_fifo_in_tvalid
;
reg
data_fifo_in_tlast
;
wire
data_fifo_in_tready
;
wire
[
7
:
0
]
data_fifo_out_tdata
;
wire
data_fifo_out_tvalid
;
wire
data_fifo_out_tlast
;
reg
data_fifo_out_tready
;
axis_fifo
#(
.
DEPTH
(
256
),
.
DATA_WIDTH
(
8
),
.
KEEP_ENABLE
(
0
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
0
),
.
DEST_ENABLE
(
0
),
.
USER_ENABLE
(
0
),
.
FRAME_FIFO
(
0
)
)
data_fifo_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
data_fifo_in_tdata
),
.
s_axis_tkeep
(
0
),
.
s_axis_tvalid
(
data_fifo_in_tvalid
),
.
s_axis_tready
(
data_fifo_in_tready
),
.
s_axis_tlast
(
data_fifo_in_tlast
),
.
s_axis_tid
(
0
),
.
s_axis_tdest
(
0
),
.
s_axis_tuser
(
0
),
// AXI output
.
m_axis_tdata
(
data_fifo_out_tdata
),
.
m_axis_tkeep
(),
.
m_axis_tvalid
(
data_fifo_out_tvalid
),
.
m_axis_tready
(
data_fifo_out_tready
),
.
m_axis_tlast
(
data_fifo_out_tlast
),
.
m_axis_tid
(),
.
m_axis_tdest
(),
.
m_axis_tuser
(),
// Status
.
status_overflow
(),
.
status_bad_frame
(),
.
status_good_frame
()
);
always
@*
begin
input_state_next
=
INPUT_STATE_IDLE
;
input_count_next
=
input_count_reg
;
fail_frame_next
=
fail_frame_reg
;
s_axis_tready_mask
=
1'b0
;
code_fifo_in_tdata
=
8'd0
;
code_fifo_in_tvalid
=
1'b0
;
code_fifo_in_tlast
=
1'b0
;
code_fifo_in_tuser
=
1'b0
;
data_fifo_in_tdata
=
s_axis_tdata
;
data_fifo_in_tvalid
=
1'b0
;
data_fifo_in_tlast
=
1'b0
;
case
(
input_state_reg
)
INPUT_STATE_IDLE:
begin
// idle state
s_axis_tready_mask
=
1'b1
;
fail_frame_next
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// valid input data
if
(
s_axis_tdata
==
8'd0
||
(
s_axis_tlast
&&
s_axis_tuser
))
begin
// got a zero or propagated error, so store a zero code
code_fifo_in_tdata
=
8'd1
;
code_fifo_in_tvalid
=
1'b1
;
if
(
s_axis_tlast
)
begin
// last byte, so close out the frame
fail_frame_next
=
s_axis_tuser
;
input_state_next
=
INPUT_STATE_FINAL_ZERO
;
end
else
begin
// return to idle to await next segment
input_state_next
=
INPUT_STATE_IDLE
;
end
end
else
begin
// got something other than a zero, so store it and init the segment counter
input_count_next
=
8'd2
;
data_fifo_in_tdata
=
s_axis_tdata
;
data_fifo_in_tvalid
=
1'b1
;
if
(
s_axis_tlast
)
begin
// last byte, so store the code and close out the frame
code_fifo_in_tdata
=
8'd2
;
code_fifo_in_tvalid
=
1'b1
;
if
(
APPEND_ZERO
)
begin
// zero frame mode, need to add a zero code to end the frame
input_state_next
=
INPUT_STATE_APPEND_ZERO
;
end
else
begin
// normal frame mode, close out the frame
data_fifo_in_tlast
=
1'b1
;
input_state_next
=
INPUT_STATE_IDLE
;
end
end
else
begin
// await more segment data
input_state_next
=
INPUT_STATE_SEGMENT
;
end
end
end
else
begin
input_state_next
=
INPUT_STATE_IDLE
;
end
end
INPUT_STATE_SEGMENT:
begin
// encode segment
s_axis_tready_mask
=
1'b1
;
fail_frame_next
=
1'b0
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// valid input data
if
(
s_axis_tdata
==
8'd0
||
(
s_axis_tlast
&&
s_axis_tuser
))
begin
// got a zero or propagated error, so store the code
code_fifo_in_tdata
=
input_count_reg
;
code_fifo_in_tvalid
=
1'b1
;
if
(
s_axis_tlast
)
begin
// last byte, so close out the frame
fail_frame_next
=
s_axis_tuser
;
input_state_next
=
INPUT_STATE_FINAL_ZERO
;
end
else
begin
// return to idle to await next segment
input_state_next
=
INPUT_STATE_IDLE
;
end
end
else
begin
// got something other than a zero, so store it and increment the segment counter
input_count_next
=
input_count_reg
+
1
;
data_fifo_in_tdata
=
s_axis_tdata
;
data_fifo_in_tvalid
=
1'b1
;
if
(
input_count_reg
==
8'd254
)
begin
// 254 bytes in frame, so dump and reset counter
code_fifo_in_tdata
=
input_count_reg
+
1
;
code_fifo_in_tvalid
=
1'b1
;
input_count_next
=
8'd1
;
end
if
(
s_axis_tlast
)
begin
// last byte, so store the code and close out the frame
code_fifo_in_tdata
=
input_count_reg
+
1
;
code_fifo_in_tvalid
=
1'b1
;
if
(
APPEND_ZERO
)
begin
// zero frame mode, need to add a zero code to end the frame
input_state_next
=
INPUT_STATE_APPEND_ZERO
;
end
else
begin
// normal frame mode, close out the frame
data_fifo_in_tlast
=
1'b1
;
input_state_next
=
INPUT_STATE_IDLE
;
end
end
else
begin
// await more segment data
input_state_next
=
INPUT_STATE_SEGMENT
;
end
end
end
else
begin
input_state_next
=
INPUT_STATE_SEGMENT
;
end
end
INPUT_STATE_FINAL_ZERO:
begin
// final zero code required
s_axis_tready_mask
=
1'b0
;
if
(
code_fifo_in_tready
)
begin
// push a zero code and close out frame
if
(
fail_frame_reg
)
begin
code_fifo_in_tdata
=
8'd2
;
code_fifo_in_tuser
=
1'b1
;
end
else
begin
code_fifo_in_tdata
=
8'd1
;
end
code_fifo_in_tvalid
=
1'b1
;
if
(
APPEND_ZERO
)
begin
// zero frame mode, need to add a zero code to end the frame
input_state_next
=
INPUT_STATE_APPEND_ZERO
;
end
else
begin
// normal frame mode, close out the frame
code_fifo_in_tlast
=
1'b1
;
fail_frame_next
=
1'b0
;
input_state_next
=
INPUT_STATE_IDLE
;
end
end
else
begin
input_state_next
=
INPUT_STATE_FINAL_ZERO
;
end
end
INPUT_STATE_APPEND_ZERO:
begin
// append zero for zero framing
s_axis_tready_mask
=
1'b0
;
if
(
code_fifo_in_tready
)
begin
// push frame termination code and close out frame
code_fifo_in_tdata
=
8'd0
;
code_fifo_in_tlast
=
1'b1
;
code_fifo_in_tuser
=
fail_frame_reg
;
code_fifo_in_tvalid
=
1'b1
;
fail_frame_next
=
1'b0
;
input_state_next
=
INPUT_STATE_IDLE
;
end
else
begin
input_state_next
=
INPUT_STATE_APPEND_ZERO
;
end
end
endcase
end
always
@*
begin
output_state_next
=
OUTPUT_STATE_IDLE
;
output_count_next
=
output_count_reg
;
m_axis_tdata_int
=
8'd0
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tuser_int
=
1'b0
;
code_fifo_out_tready
=
1'b0
;
data_fifo_out_tready
=
1'b0
;
case
(
output_state_reg
)
OUTPUT_STATE_IDLE:
begin
// idle state
if
(
m_axis_tready_int_reg
&&
code_fifo_out_tvalid
)
begin
// transfer out code byte and load counter
m_axis_tdata_int
=
code_fifo_out_tdata
;
m_axis_tlast_int
=
code_fifo_out_tlast
;
m_axis_tuser_int
=
code_fifo_out_tuser
&&
code_fifo_out_tlast
;
output_count_next
=
code_fifo_out_tdata
-
1
;
m_axis_tvalid_int
=
1'b1
;
code_fifo_out_tready
=
1'b1
;
if
(
code_fifo_out_tdata
==
8'd0
||
code_fifo_out_tdata
==
8'd1
||
code_fifo_out_tuser
)
begin
// frame termination and zero codes will be followed by codes
output_state_next
=
OUTPUT_STATE_IDLE
;
end
else
begin
// transfer out data
output_state_next
=
OUTPUT_STATE_SEGMENT
;
end
end
else
begin
output_state_next
=
OUTPUT_STATE_IDLE
;
end
end
OUTPUT_STATE_SEGMENT:
begin
// segment output
if
(
m_axis_tready_int_reg
&&
data_fifo_out_tvalid
)
begin
// transfer out data byte and decrement counter
m_axis_tdata_int
=
data_fifo_out_tdata
;
m_axis_tlast_int
=
data_fifo_out_tlast
;
output_count_next
=
output_count_reg
-
1
;
m_axis_tvalid_int
=
1'b1
;
data_fifo_out_tready
=
1'b1
;
if
(
output_count_reg
==
1'b1
)
begin
// done with segment, get a code byte next
output_state_next
=
OUTPUT_STATE_IDLE
;
end
else
begin
// more data to transfer
output_state_next
=
OUTPUT_STATE_SEGMENT
;
end
end
else
begin
output_state_next
=
OUTPUT_STATE_SEGMENT
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
input_state_reg
<=
INPUT_STATE_IDLE
;
output_state_reg
<=
OUTPUT_STATE_IDLE
;
end
else
begin
input_state_reg
<=
input_state_next
;
output_state_reg
<=
output_state_next
;
end
input_count_reg
<=
input_count_next
;
output_count_reg
<=
output_count_next
;
fail_frame_reg
<=
fail_frame_next
;
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/lib/axis/rtl/axis_crosspoint.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
/*
* AXI4-Stream crosspoint
*/
module
axis_crosspoint
#
(
// Number of AXI stream inputs
parameter
S_COUNT
=
4
,
// Number of AXI stream outputs
parameter
M_COUNT
=
4
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tlast signal
parameter
LAST_ENABLE
=
1
,
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI Stream inputs
*/
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tvalid
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tlast
,
input
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI Stream outputs
*/
output
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_COUNT
*
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tvalid
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tlast
,
output
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
M_COUNT
*
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
M_COUNT
*
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Control
*/
input
wire
[
M_COUNT
*
$
clog2
(
S_COUNT
)
-
1
:
0
]
select
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
reg
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_reg
=
{
S_COUNT
*
DATA_WIDTH
{
1'b0
}}
;
reg
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep_reg
=
{
S_COUNT
*
KEEP_WIDTH
{
1'b0
}}
;
reg
[
S_COUNT
-
1
:
0
]
s_axis_tvalid_reg
=
{
S_COUNT
{
1'b0
}}
;
reg
[
S_COUNT
-
1
:
0
]
s_axis_tlast_reg
=
{
S_COUNT
{
1'b0
}}
;
reg
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
s_axis_tid_reg
=
{
S_COUNT
*
ID_WIDTH
{
1'b0
}}
;
reg
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
s_axis_tdest_reg
=
{
S_COUNT
*
DEST_WIDTH
{
1'b0
}}
;
reg
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
s_axis_tuser_reg
=
{
S_COUNT
*
USER_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
M_COUNT
*
DATA_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
*
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
M_COUNT
*
KEEP_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
-
1
:
0
]
m_axis_tvalid_reg
=
{
M_COUNT
{
1'b0
}}
;
reg
[
M_COUNT
-
1
:
0
]
m_axis_tlast_reg
=
{
M_COUNT
{
1'b0
}}
;
reg
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
M_COUNT
*
ID_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
*
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
M_COUNT
*
DEST_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
*
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
M_COUNT
*
USER_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
*
CL_S_COUNT
-
1
:
0
]
select_reg
=
{
M_COUNT
*
CL_S_COUNT
{
1'b0
}}
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_tkeep_reg
:
{
M_COUNT
*
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
LAST_ENABLE
?
m_axis_tlast_reg
:
{
M_COUNT
{
1'b1
}}
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_tid_reg
:
{
M_COUNT
*
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_tdest_reg
:
{
M_COUNT
*
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_tuser_reg
:
{
M_COUNT
*
USER_WIDTH
{
1'b0
}}
;
integer
i
;
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axis_tvalid_reg
<=
{
S_COUNT
{
1'b0
}}
;
m_axis_tvalid_reg
<=
{
S_COUNT
{
1'b0
}}
;
select_reg
<=
{
M_COUNT
*
CL_S_COUNT
{
1'b0
}}
;
end
else
begin
s_axis_tvalid_reg
<=
s_axis_tvalid
;
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
m_axis_tvalid_reg
[
i
]
=
s_axis_tvalid_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]];
end
select_reg
<=
select
;
end
s_axis_tdata_reg
<=
s_axis_tdata
;
s_axis_tkeep_reg
<=
s_axis_tkeep
;
s_axis_tlast_reg
<=
s_axis_tlast
;
s_axis_tid_reg
<=
s_axis_tid
;
s_axis_tdest_reg
<=
s_axis_tdest
;
s_axis_tuser_reg
<=
s_axis_tuser
;
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
m_axis_tdata_reg
[
i
*
DATA_WIDTH
+:
DATA_WIDTH
]
<=
s_axis_tdata_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]
*
DATA_WIDTH
+:
DATA_WIDTH
];
m_axis_tkeep_reg
[
i
*
KEEP_WIDTH
+:
KEEP_WIDTH
]
<=
s_axis_tkeep_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
m_axis_tlast_reg
[
i
]
<=
s_axis_tlast_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]];
m_axis_tid_reg
[
i
*
ID_WIDTH
+:
ID_WIDTH
]
<=
s_axis_tid_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]
*
ID_WIDTH
+:
ID_WIDTH
];
m_axis_tdest_reg
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
s_axis_tdest_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]
*
DEST_WIDTH
+:
DEST_WIDTH
];
m_axis_tuser_reg
[
i
*
USER_WIDTH
+:
USER_WIDTH
]
<=
s_axis_tuser_reg
[
select_reg
[
i
*
CL_S_COUNT
+:
CL_S_COUNT
]
*
USER_WIDTH
+:
USER_WIDTH
];
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_crosspoint_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream crosspoint wrapper with the specified number of ports
"""
from
__future__
import
print_function
import
argparse
import
math
from
jinja2
import
Template
def
main
():
parser
=
argparse
.
ArgumentParser
(
description
=
__doc__
.
strip
())
parser
.
add_argument
(
'-p'
,
'--ports'
,
type
=
int
,
default
=
[
4
],
nargs
=
'+'
,
help
=
"number of ports"
)
parser
.
add_argument
(
'-n'
,
'--name'
,
type
=
str
,
help
=
"module name"
)
parser
.
add_argument
(
'-o'
,
'--output'
,
type
=
str
,
help
=
"output file name"
)
args
=
parser
.
parse_args
()
try
:
generate
(
**
args
.
__dict__
)
except
IOError
as
ex
:
print
(
ex
)
exit
(
1
)
def
generate
(
ports
=
4
,
name
=
None
,
output
=
None
):
if
type
(
ports
)
is
int
:
m
=
n
=
ports
elif
len
(
ports
)
==
1
:
m
=
n
=
ports
[
0
]
else
:
m
,
n
=
ports
if
name
is
None
:
name
=
"axis_crosspoint_wrap_{0}x{1}"
.
format
(
m
,
n
)
if
output
is
None
:
output
=
name
+
".v"
print
(
"Opening file '{0}'..."
.
format
(
output
))
output_file
=
open
(
output
,
'w'
)
print
(
"Generating {0}x{1} port AXI stream crosspoint wrapper {2}..."
.
format
(
m
,
n
,
name
))
cm
=
int
(
math
.
ceil
(
math
.
log
(
m
,
2
)))
cn
=
int
(
math
.
ceil
(
math
.
log
(
n
,
2
)))
t
=
Template
(
u
"""/*
Copyright (c) 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 1ns / 1ps
/*
* AXI4-Stream {{m}}x{{n}} crosspoint (wrapper)
*/
module {{name}} #
(
// Width of AXI stream interfaces in bits
parameter DATA_WIDTH = 8,
// Propagate tkeep signal
parameter KEEP_ENABLE = (DATA_WIDTH>8),
// tkeep signal width (words per cycle)
parameter KEEP_WIDTH = (DATA_WIDTH/8),
// Propagate tlast signal
parameter LAST_ENABLE = 1,
// Propagate tid signal
parameter ID_ENABLE = 0,
// tid signal width
parameter ID_WIDTH = 8,
// Propagate tdest signal
parameter DEST_ENABLE = 0,
// tdest signal width
parameter DEST_WIDTH = 8,
// Propagate tuser signal
parameter USER_ENABLE = 1,
// tuser signal width
parameter USER_WIDTH = 1
)
(
input wire clk,
input wire rst,
/*
* AXI Stream inputs
*/
{%- for p in range(m) %}
input wire [DATA_WIDTH-1:0] s{{'%02d'%p}}_axis_tdata,
input wire [KEEP_WIDTH-1:0] s{{'%02d'%p}}_axis_tkeep,
input wire s{{'%02d'%p}}_axis_tvalid,
input wire s{{'%02d'%p}}_axis_tlast,
input wire [ID_WIDTH-1:0] s{{'%02d'%p}}_axis_tid,
input wire [DEST_WIDTH-1:0] s{{'%02d'%p}}_axis_tdest,
input wire [USER_WIDTH-1:0] s{{'%02d'%p}}_axis_tuser,
{% endfor %}
/*
* AXI Stream outputs
*/
{%- for p in range(n) %}
output wire [DATA_WIDTH-1:0] m{{'%02d'%p}}_axis_tdata,
output wire [KEEP_WIDTH-1:0] m{{'%02d'%p}}_axis_tkeep,
output wire m{{'%02d'%p}}_axis_tvalid,
output wire m{{'%02d'%p}}_axis_tlast,
output wire [ID_WIDTH-1:0] m{{'%02d'%p}}_axis_tid,
output wire [DEST_WIDTH-1:0] m{{'%02d'%p}}_axis_tdest,
output wire [USER_WIDTH-1:0] m{{'%02d'%p}}_axis_tuser,
{% endfor %}
/*
* Control
*/
{%- for p in range(n) %}
input wire [{{cm-1}}:0] m{{'%02d'%p}}_select{% if not loop.last %},{% endif %}
{%- endfor %}
);
axis_crosspoint #(
.S_COUNT({{m}}),
.M_COUNT({{n}}),
.DATA_WIDTH(DATA_WIDTH),
.KEEP_ENABLE(KEEP_ENABLE),
.KEEP_WIDTH(KEEP_WIDTH),
.LAST_ENABLE(LAST_ENABLE),
.ID_ENABLE(ID_ENABLE),
.ID_WIDTH(ID_WIDTH),
.DEST_ENABLE(DEST_ENABLE),
.DEST_WIDTH(DEST_WIDTH),
.USER_ENABLE(USER_ENABLE),
.USER_WIDTH(USER_WIDTH)
)
axis_crosspoint_inst (
.clk(clk),
.rst(rst),
// AXI inputs
.s_axis_tdata({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tkeep({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tvalid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tlast({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tid({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tdest({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }),
.s_axis_tuser({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }),
// AXI output
.m_axis_tdata({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tkeep({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tlast({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tdest({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tuser({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }),
// Control
.select({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_select{% if not loop.last %}, {% endif %}{% endfor %} })
);
endmodule
"""
)
output_file
.
write
(
t
.
render
(
m
=
m
,
n
=
n
,
cm
=
cm
,
cn
=
cn
,
name
=
name
))
print
(
"Done"
)
if
__name__
==
"__main__"
:
main
()
corundum/lib/eth/lib/axis/rtl/axis_demux.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 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 demultiplexer
*/
module
axis_demux
#
(
// Number of AXI stream outputs
parameter
M_COUNT
=
4
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI outputs
*/
output
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_COUNT
*
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tvalid
,
input
wire
[
M_COUNT
-
1
:
0
]
m_axis_tready
,
output
wire
[
M_COUNT
-
1
:
0
]
m_axis_tlast
,
output
wire
[
M_COUNT
*
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
M_COUNT
*
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
M_COUNT
*
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Control
*/
input
wire
enable
,
input
wire
drop
,
input
wire
[$
clog2
(
M_COUNT
)
-
1
:
0
]
select
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
reg
[
CL_M_COUNT
-
1
:
0
]
select_reg
=
{
CL_M_COUNT
{
1'b0
}}
,
select_ctl
,
select_next
;
reg
drop_reg
=
1'b0
,
drop_ctl
,
drop_next
;
reg
frame_reg
=
1'b0
,
frame_ctl
,
frame_next
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
[
M_COUNT
-
1
:
0
]
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
assign
s_axis_tready
=
s_axis_tready_reg
&&
enable
;
always
@*
begin
select_next
=
select_reg
;
select_ctl
=
select_reg
;
drop_next
=
drop_reg
;
drop_ctl
=
drop_reg
;
frame_next
=
frame_reg
;
frame_ctl
=
frame_reg
;
s_axis_tready_next
=
1'b0
;
if
(
s_axis_tvalid
&&
s_axis_tready
)
begin
// end of frame detection
if
(
s_axis_tlast
)
begin
frame_next
=
1'b0
;
drop_next
=
1'b0
;
end
end
if
(
!
frame_reg
&&
s_axis_tvalid
&&
s_axis_tready
)
begin
// start of frame, grab select value
select_ctl
=
select
;
drop_ctl
=
drop
;
frame_ctl
=
1'b1
;
if
(
!
(
s_axis_tready
&&
s_axis_tvalid
&&
s_axis_tlast
))
begin
select_next
=
select_ctl
;
drop_next
=
drop_ctl
;
frame_next
=
1'b1
;
end
end
s_axis_tready_next
=
(
m_axis_tready_int_early
||
drop_ctl
);
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
(
s_axis_tvalid
&&
s_axis_tready
&&
!
drop_ctl
)
<<
select_ctl
;
m_axis_tlast_int
=
s_axis_tlast
;
m_axis_tid_int
=
s_axis_tid
;
m_axis_tdest_int
=
s_axis_tdest
;
m_axis_tuser_int
=
s_axis_tuser
;
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
select_reg
<=
2'd0
;
drop_reg
<=
1'b0
;
frame_reg
<=
1'b0
;
s_axis_tready_reg
<=
1'b0
;
end
else
begin
select_reg
<=
select_next
;
drop_reg
<=
drop_next
;
frame_reg
<=
frame_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
-
1
:
0
]
m_axis_tvalid_reg
=
{
M_COUNT
{
1'b0
}}
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
[
M_COUNT
-
1
:
0
]
temp_m_axis_tvalid_reg
=
{
M_COUNT
{
1'b0
}}
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
{
M_COUNT
{
m_axis_tdata_reg
}}
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
{
M_COUNT
{
m_axis_tkeep_reg
}}
:
{
M_COUNT
*
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
{
M_COUNT
{
m_axis_tlast_reg
}}
;
assign
m_axis_tid
=
ID_ENABLE
?
{
M_COUNT
{
m_axis_tid_reg
}}
:
{
M_COUNT
*
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
{
M_COUNT
{
m_axis_tdest_reg
}}
:
{
M_COUNT
*
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
{
M_COUNT
{
m_axis_tuser_reg
}}
:
{
M_COUNT
*
USER_WIDTH
{
1'b0
}}
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_tready_int_early
=
(
m_axis_tready
&
m_axis_tvalid
)
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid
||
!
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
)
||
!
m_axis_tvalid
)
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
&
m_axis_tvalid
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
{
M_COUNT
{
1'b0
}}
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_tvalid_reg
<=
{
M_COUNT
{
1'b0
}}
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
{
M_COUNT
{
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_tid_reg
<=
m_axis_tid_int
;
m_axis_tdest_reg
<=
m_axis_tdest_int
;
m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_tdata_reg
<=
temp_m_axis_tdata_reg
;
m_axis_tkeep_reg
<=
temp_m_axis_tkeep_reg
;
m_axis_tlast_reg
<=
temp_m_axis_tlast_reg
;
m_axis_tid_reg
<=
temp_m_axis_tid_reg
;
m_axis_tdest_reg
<=
temp_m_axis_tdest_reg
;
m_axis_tuser_reg
<=
temp_m_axis_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_tdata_reg
<=
m_axis_tdata_int
;
temp_m_axis_tkeep_reg
<=
m_axis_tkeep_int
;
temp_m_axis_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tid_reg
<=
m_axis_tid_int
;
temp_m_axis_tdest_reg
<=
m_axis_tdest_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_demux_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream demux wrapper with the specified number of ports
"""
from
__future__
import
print_function
import
argparse
import
math
from
jinja2
import
Template
def
main
():
parser
=
argparse
.
ArgumentParser
(
description
=
__doc__
.
strip
())
parser
.
add_argument
(
'-p'
,
'--ports'
,
type
=
int
,
default
=
4
,
help
=
"number of ports"
)
parser
.
add_argument
(
'-n'
,
'--name'
,
type
=
str
,
help
=
"module name"
)
parser
.
add_argument
(
'-o'
,
'--output'
,
type
=
str
,
help
=
"output file name"
)
args
=
parser
.
parse_args
()
try
:
generate
(
**
args
.
__dict__
)
except
IOError
as
ex
:
print
(
ex
)
exit
(
1
)
def
generate
(
ports
=
4
,
name
=
None
,
output
=
None
):
n
=
ports
if
name
is
None
:
name
=
"axis_demux_wrap_{0}"
.
format
(
n
)
if
output
is
None
:
output
=
name
+
".v"
print
(
"Opening file '{0}'..."
.
format
(
output
))
output_file
=
open
(
output
,
'w'
)
print
(
"Generating {0} port AXI stream demux wrapper {1}..."
.
format
(
n
,
name
))
cn
=
int
(
math
.
ceil
(
math
.
log
(
n
,
2
)))
t
=
Template
(
u
"""/*
Copyright (c) 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 1ns / 1ps
/*
* AXI4-Stream {{n}} port demux (wrapper)
*/
module {{name}} #
(
// Width of AXI stream interfaces in bits
parameter DATA_WIDTH = 8,
// Propagate tkeep signal
parameter KEEP_ENABLE = (DATA_WIDTH>8),
// tkeep signal width (words per cycle)
parameter KEEP_WIDTH = (DATA_WIDTH/8),
// Propagate tid signal
parameter ID_ENABLE = 0,
// tid signal width
parameter ID_WIDTH = 8,
// Propagate tdest signal
parameter DEST_ENABLE = 0,
// tdest signal width
parameter DEST_WIDTH = 8,
// Propagate tuser signal
parameter USER_ENABLE = 1,
// tuser signal width
parameter USER_WIDTH = 1
)
(
input wire clk,
input wire rst,
/*
* AXI Stream input
*/
input wire [DATA_WIDTH-1:0] s_axis_tdata,
input wire [KEEP_WIDTH-1:0] s_axis_tkeep,
input wire s_axis_tvalid,
output wire s_axis_tready,
input wire s_axis_tlast,
input wire [ID_WIDTH-1:0] s_axis_tid,
input wire [DEST_WIDTH-1:0] s_axis_tdest,
input wire [USER_WIDTH-1:0] s_axis_tuser,
/*
* AXI Stream outputs
*/
{%- for p in range(n) %}
output wire [DATA_WIDTH-1:0] m{{'%02d'%p}}_axis_tdata,
output wire [KEEP_WIDTH-1:0] m{{'%02d'%p}}_axis_tkeep,
output wire m{{'%02d'%p}}_axis_tvalid,
input wire m{{'%02d'%p}}_axis_tready,
output wire m{{'%02d'%p}}_axis_tlast,
output wire [ID_WIDTH-1:0] m{{'%02d'%p}}_axis_tid,
output wire [DEST_WIDTH-1:0] m{{'%02d'%p}}_axis_tdest,
output wire [USER_WIDTH-1:0] m{{'%02d'%p}}_axis_tuser,
{% endfor -%}
/*
* Control
*/
input wire enable,
input wire drop,
input wire [{{cn-1}}:0] select
);
axis_demux #(
.M_COUNT({{n}}),
.DATA_WIDTH(DATA_WIDTH),
.KEEP_ENABLE(KEEP_ENABLE),
.KEEP_WIDTH(KEEP_WIDTH),
.ID_ENABLE(ID_ENABLE),
.ID_WIDTH(ID_WIDTH),
.DEST_ENABLE(DEST_ENABLE),
.DEST_WIDTH(DEST_WIDTH),
.USER_ENABLE(USER_ENABLE),
.USER_WIDTH(USER_WIDTH)
)
axis_demux_inst (
.clk(clk),
.rst(rst),
// AXI inputs
.s_axis_tdata(s_axis_tdata),
.s_axis_tkeep(s_axis_tkeep),
.s_axis_tvalid(s_axis_tvalid),
.s_axis_tready(s_axis_tready),
.s_axis_tlast(s_axis_tlast),
.s_axis_tid(s_axis_tid),
.s_axis_tdest(s_axis_tdest),
.s_axis_tuser(s_axis_tuser),
// AXI output
.m_axis_tdata({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdata{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tkeep({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tkeep{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tvalid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tvalid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tready({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tready{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tlast({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tlast{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tid({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tid{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tdest({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tdest{% if not loop.last %}, {% endif %}{% endfor %} }),
.m_axis_tuser({ {% for p in range(n-1,-1,-1) %}m{{'%02d'%p}}_axis_tuser{% if not loop.last %}, {% endif %}{% endfor %} }),
// Control
.enable(enable),
.drop(drop),
.select(select)
);
endmodule
"""
)
output_file
.
write
(
t
.
render
(
n
=
n
,
cn
=
cn
,
name
=
name
))
print
(
"Done"
)
if
__name__
==
"__main__"
:
main
()
corundum/lib/eth/lib/axis/rtl/axis_fifo.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2013-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 FIFO
*/
module
axis_fifo
#
(
// FIFO depth in words
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
// Rounded up to nearest power of 2 cycles
parameter
DEPTH
=
4096
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Propagate tkeep signal
// If disabled, tkeep assumed to be 1'b1
parameter
KEEP_ENABLE
=
(
DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
KEEP_WIDTH
=
(
DATA_WIDTH
/
8
),
// Propagate tlast signal
parameter
LAST_ENABLE
=
1
,
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// Frame FIFO mode - operate on frames instead of cycles
// When set, m_axis_tvalid will not be deasserted within a frame
// Requires LAST_ENABLE set
parameter
FRAME_FIFO
=
0
,
// tuser value for bad frame marker
parameter
USER_BAD_FRAME_VALUE
=
1'b1
,
// tuser mask for bad frame marker
parameter
USER_BAD_FRAME_MASK
=
1'b1
,
// Drop frames marked bad
// Requires FRAME_FIFO set
parameter
DROP_BAD_FRAME
=
0
,
// Drop incoming frames when full
// When set, s_axis_tready is always asserted
// Requires FRAME_FIFO set
parameter
DROP_WHEN_FULL
=
0
)
(
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
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Status
*/
output
wire
status_overflow
,
output
wire
status_bad_frame
,
output
wire
status_good_frame
);
parameter
ADDR_WIDTH
=
(
KEEP_ENABLE
&&
KEEP_WIDTH
>
1
)
?
$
clog2
(
DEPTH
/
KEEP_WIDTH
)
:
$
clog2
(
DEPTH
);
// check configuration
initial
begin
if
(
FRAME_FIFO
&&
!
LAST_ENABLE
)
begin
$
error
(
"Error: FRAME_FIFO set requires LAST_ENABLE set (instance %m)"
);
$
finish
;
end
if
(
DROP_BAD_FRAME
&&
!
FRAME_FIFO
)
begin
$
error
(
"Error: DROP_BAD_FRAME set requires FRAME_FIFO set (instance %m)"
);
$
finish
;
end
if
(
DROP_WHEN_FULL
&&
!
FRAME_FIFO
)
begin
$
error
(
"Error: DROP_WHEN_FULL set requires FRAME_FIFO set (instance %m)"
);
$
finish
;
end
if
(
DROP_BAD_FRAME
&&
(
USER_BAD_FRAME_MASK
&
{
USER_WIDTH
{
1'b1
}}
)
==
0
)
begin
$
error
(
"Error: Invalid USER_BAD_FRAME_MASK value (instance %m)"
);
$
finish
;
end
end
localparam
KEEP_OFFSET
=
DATA_WIDTH
;
localparam
LAST_OFFSET
=
KEEP_OFFSET
+
(
KEEP_ENABLE
?
KEEP_WIDTH
:
0
);
localparam
ID_OFFSET
=
LAST_OFFSET
+
(
LAST_ENABLE
?
1
:
0
);
localparam
DEST_OFFSET
=
ID_OFFSET
+
(
ID_ENABLE
?
ID_WIDTH
:
0
);
localparam
USER_OFFSET
=
DEST_OFFSET
+
(
DEST_ENABLE
?
DEST_WIDTH
:
0
);
localparam
WIDTH
=
USER_OFFSET
+
(
USER_ENABLE
?
USER_WIDTH
:
0
);
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_ptr_cur_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
wr_ptr_cur_next
;
reg
[
ADDR_WIDTH
:
0
]
wr_addr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
ADDR_WIDTH
:
0
]
rd_ptr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
ADDR_WIDTH
:
0
]
rd_addr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
reg
[
WIDTH
-
1
:
0
]
mem
[(
2
**
ADDR_WIDTH
)
-
1
:
0
];
reg
[
WIDTH
-
1
:
0
]
mem_read_data_reg
;
reg
mem_read_data_valid_reg
=
1'b0
,
mem_read_data_valid_next
;
wire
[
WIDTH
-
1
:
0
]
s_axis
;
reg
[
WIDTH
-
1
:
0
]
m_axis_reg
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
// full when first MSB different but rest same
wire
full
=
((
wr_ptr_reg
[
ADDR_WIDTH
]
!=
rd_ptr_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]
==
rd_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]));
wire
full_cur
=
((
wr_ptr_cur_reg
[
ADDR_WIDTH
]
!=
rd_ptr_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_cur_reg
[
ADDR_WIDTH
-
1
:
0
]
==
rd_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]));
// empty when pointers match exactly
wire
empty
=
wr_ptr_reg
==
rd_ptr_reg
;
// overflow within packet
wire
full_wr
=
((
wr_ptr_reg
[
ADDR_WIDTH
]
!=
wr_ptr_cur_reg
[
ADDR_WIDTH
])
&&
(
wr_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]
==
wr_ptr_cur_reg
[
ADDR_WIDTH
-
1
:
0
]));
// control signals
reg
write
;
reg
read
;
reg
store_output
;
reg
drop_frame_reg
=
1'b0
,
drop_frame_next
;
reg
overflow_reg
=
1'b0
,
overflow_next
;
reg
bad_frame_reg
=
1'b0
,
bad_frame_next
;
reg
good_frame_reg
=
1'b0
,
good_frame_next
;
assign
s_axis_tready
=
FRAME_FIFO
?
(
!
full_cur
||
full_wr
||
DROP_WHEN_FULL
)
:
!
full
;
generate
assign
s_axis
[
DATA_WIDTH
-
1
:
0
]
=
s_axis_tdata
;
if
(
KEEP_ENABLE
)
assign
s_axis
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
=
s_axis_tkeep
;
if
(
LAST_ENABLE
)
assign
s_axis
[
LAST_OFFSET
]
=
s_axis_tlast
;
if
(
ID_ENABLE
)
assign
s_axis
[
ID_OFFSET
+:
ID_WIDTH
]
=
s_axis_tid
;
if
(
DEST_ENABLE
)
assign
s_axis
[
DEST_OFFSET
+:
DEST_WIDTH
]
=
s_axis_tdest
;
if
(
USER_ENABLE
)
assign
s_axis
[
USER_OFFSET
+:
USER_WIDTH
]
=
s_axis_tuser
;
endgenerate
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tdata
=
m_axis_reg
[
DATA_WIDTH
-
1
:
0
];
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_reg
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tlast
=
LAST_ENABLE
?
m_axis_reg
[
LAST_OFFSET
]
:
1'b1
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_reg
[
ID_OFFSET
+:
ID_WIDTH
]
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_reg
[
DEST_OFFSET
+:
DEST_WIDTH
]
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_reg
[
USER_OFFSET
+:
USER_WIDTH
]
:
{
USER_WIDTH
{
1'b0
}}
;
assign
status_overflow
=
overflow_reg
;
assign
status_bad_frame
=
bad_frame_reg
;
assign
status_good_frame
=
good_frame_reg
;
// Write logic
always
@*
begin
write
=
1'b0
;
drop_frame_next
=
drop_frame_reg
;
overflow_next
=
1'b0
;
bad_frame_next
=
1'b0
;
good_frame_next
=
1'b0
;
wr_ptr_next
=
wr_ptr_reg
;
wr_ptr_cur_next
=
wr_ptr_cur_reg
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// transfer in
if
(
!
FRAME_FIFO
)
begin
// normal FIFO mode
write
=
1'b1
;
wr_ptr_next
=
wr_ptr_reg
+
1
;
end
else
if
(
full_cur
||
full_wr
||
drop_frame_reg
)
begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next
=
1'b1
;
if
(
s_axis_tlast
)
begin
// end of frame, reset write pointer
wr_ptr_cur_next
=
wr_ptr_reg
;
drop_frame_next
=
1'b0
;
overflow_next
=
1'b1
;
end
end
else
begin
write
=
1'b1
;
wr_ptr_cur_next
=
wr_ptr_cur_reg
+
1
;
if
(
s_axis_tlast
)
begin
// end of frame
if
(
DROP_BAD_FRAME
&&
USER_BAD_FRAME_MASK
&
~
(
s_axis_tuser
^
USER_BAD_FRAME_VALUE
))
begin
// bad packet, reset write pointer
wr_ptr_cur_next
=
wr_ptr_reg
;
bad_frame_next
=
1'b1
;
end
else
begin
// good packet, update write pointer
wr_ptr_next
=
wr_ptr_cur_reg
+
1
;
good_frame_next
=
1'b1
;
end
end
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
wr_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_cur_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
drop_frame_reg
<=
1'b0
;
overflow_reg
<=
1'b0
;
bad_frame_reg
<=
1'b0
;
good_frame_reg
<=
1'b0
;
end
else
begin
wr_ptr_reg
<=
wr_ptr_next
;
wr_ptr_cur_reg
<=
wr_ptr_cur_next
;
drop_frame_reg
<=
drop_frame_next
;
overflow_reg
<=
overflow_next
;
bad_frame_reg
<=
bad_frame_next
;
good_frame_reg
<=
good_frame_next
;
end
if
(
FRAME_FIFO
)
begin
wr_addr_reg
<=
wr_ptr_cur_next
;
end
else
begin
wr_addr_reg
<=
wr_ptr_next
;
end
if
(
write
)
begin
mem
[
wr_addr_reg
[
ADDR_WIDTH
-
1
:
0
]]
<=
s_axis
;
end
end
// Read logic
always
@*
begin
read
=
1'b0
;
rd_ptr_next
=
rd_ptr_reg
;
mem_read_data_valid_next
=
mem_read_data_valid_reg
;
if
(
store_output
||
!
mem_read_data_valid_reg
)
begin
// output data not valid OR currently being transferred
if
(
!
empty
)
begin
// not empty, perform read
read
=
1'b1
;
mem_read_data_valid_next
=
1'b1
;
rd_ptr_next
=
rd_ptr_reg
+
1
;
end
else
begin
// empty, invalidate
mem_read_data_valid_next
=
1'b0
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
rd_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
mem_read_data_valid_reg
<=
1'b0
;
end
else
begin
rd_ptr_reg
<=
rd_ptr_next
;
mem_read_data_valid_reg
<=
mem_read_data_valid_next
;
end
rd_addr_reg
<=
rd_ptr_next
;
if
(
read
)
begin
mem_read_data_reg
<=
mem
[
rd_addr_reg
[
ADDR_WIDTH
-
1
:
0
]];
end
end
// Output register
always
@*
begin
store_output
=
1'b0
;
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
if
(
m_axis_tready
||
!
m_axis_tvalid
)
begin
store_output
=
1'b1
;
m_axis_tvalid_next
=
mem_read_data_valid_reg
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
end
if
(
store_output
)
begin
m_axis_reg
<=
mem_read_data_reg
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_fifo_adapter.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 FIFO with width converter
*/
module
axis_fifo_adapter
#
(
// FIFO depth in words
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
// Rounded up to nearest power of 2 cycles
parameter
DEPTH
=
4096
,
// Width of input AXI stream interface in bits
parameter
S_DATA_WIDTH
=
8
,
// Propagate tkeep signal on input interface
// If disabled, tkeep assumed to be 1'b1
parameter
S_KEEP_ENABLE
=
(
S_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on input interface
parameter
S_KEEP_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output AXI stream interface in bits
parameter
M_DATA_WIDTH
=
8
,
// Propagate tkeep signal on output interface
// If disabled, tkeep assumed to be 1'b1
parameter
M_KEEP_ENABLE
=
(
M_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle) on output interface
parameter
M_KEEP_WIDTH
=
(
M_DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// Propagate tdest signal
parameter
DEST_ENABLE
=
0
,
// tdest signal width
parameter
DEST_WIDTH
=
8
,
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// Frame FIFO mode - operate on frames instead of cycles
// When set, m_axis_tvalid will not be deasserted within a frame
// Requires LAST_ENABLE set
parameter
FRAME_FIFO
=
0
,
// tuser value for bad frame marker
parameter
USER_BAD_FRAME_VALUE
=
1'b1
,
// tuser mask for bad frame marker
parameter
USER_BAD_FRAME_MASK
=
1'b1
,
// Drop frames marked bad
// Requires FRAME_FIFO set
parameter
DROP_BAD_FRAME
=
0
,
// Drop incoming frames when full
// When set, s_axis_tready is always asserted
// Requires FRAME_FIFO set
parameter
DROP_WHEN_FULL
=
0
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
S_DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
,
/*
* Status
*/
output
wire
status_overflow
,
output
wire
status_bad_frame
,
output
wire
status_good_frame
);
// force keep width to 1 when disabled
parameter
S_KEEP_WIDTH_INT
=
S_KEEP_ENABLE
?
S_KEEP_WIDTH
:
1
;
parameter
M_KEEP_WIDTH_INT
=
M_KEEP_ENABLE
?
M_KEEP_WIDTH
:
1
;
// bus word sizes (must be identical)
parameter
S_DATA_WORD_SIZE
=
S_DATA_WIDTH
/
S_KEEP_WIDTH_INT
;
parameter
M_DATA_WORD_SIZE
=
M_DATA_WIDTH
/
M_KEEP_WIDTH_INT
;
// output bus is wider
parameter
EXPAND_BUS
=
M_KEEP_WIDTH_INT
>
S_KEEP_WIDTH_INT
;
// total data and keep widths
parameter
DATA_WIDTH
=
EXPAND_BUS
?
M_DATA_WIDTH
:
S_DATA_WIDTH
;
parameter
KEEP_WIDTH
=
EXPAND_BUS
?
M_KEEP_WIDTH_INT
:
S_KEEP_WIDTH_INT
;
// bus width assertions
initial
begin
if
(
S_DATA_WORD_SIZE
*
S_KEEP_WIDTH_INT
!=
S_DATA_WIDTH
)
begin
$
error
(
"Error: input data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
M_DATA_WORD_SIZE
*
M_KEEP_WIDTH_INT
!=
M_DATA_WIDTH
)
begin
$
error
(
"Error: output data width not evenly divisble (instance %m)"
);
$
finish
;
end
if
(
S_DATA_WORD_SIZE
!=
M_DATA_WORD_SIZE
)
begin
$
error
(
"Error: word size mismatch (instance %m)"
);
$
finish
;
end
end
wire
[
DATA_WIDTH
-
1
:
0
]
pre_fifo_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
pre_fifo_axis_tkeep
;
wire
pre_fifo_axis_tvalid
;
wire
pre_fifo_axis_tready
;
wire
pre_fifo_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
pre_fifo_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
pre_fifo_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
pre_fifo_axis_tuser
;
wire
[
DATA_WIDTH
-
1
:
0
]
post_fifo_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
post_fifo_axis_tkeep
;
wire
post_fifo_axis_tvalid
;
wire
post_fifo_axis_tready
;
wire
post_fifo_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
post_fifo_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
post_fifo_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
post_fifo_axis_tuser
;
generate
if
(
M_KEEP_WIDTH_INT
==
S_KEEP_WIDTH_INT
)
begin
// same width, no adapter needed
assign
pre_fifo_axis_tdata
=
s_axis_tdata
;
assign
pre_fifo_axis_tkeep
=
s_axis_tkeep
;
assign
pre_fifo_axis_tvalid
=
s_axis_tvalid
;
assign
s_axis_tready
=
pre_fifo_axis_tready
;
assign
pre_fifo_axis_tlast
=
s_axis_tlast
;
assign
pre_fifo_axis_tid
=
s_axis_tid
;
assign
pre_fifo_axis_tdest
=
s_axis_tdest
;
assign
pre_fifo_axis_tuser
=
s_axis_tuser
;
assign
m_axis_tdata
=
post_fifo_axis_tdata
;
assign
m_axis_tkeep
=
post_fifo_axis_tkeep
;
assign
m_axis_tvalid
=
post_fifo_axis_tvalid
;
assign
post_fifo_axis_tready
=
m_axis_tready
;
assign
m_axis_tlast
=
post_fifo_axis_tlast
;
assign
m_axis_tid
=
post_fifo_axis_tid
;
assign
m_axis_tdest
=
post_fifo_axis_tdest
;
assign
m_axis_tuser
=
post_fifo_axis_tuser
;
end
else
if
(
EXPAND_BUS
)
begin
// output wider, adapt width before FIFO
axis_adapter
#(
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_KEEP_ENABLE
(
S_KEEP_ENABLE
),
.
S_KEEP_WIDTH
(
S_KEEP_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_KEEP_ENABLE
(
M_KEEP_ENABLE
),
.
M_KEEP_WIDTH
(
M_KEEP_WIDTH
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
)
)
adapter_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
s_axis_tdata
),
.
s_axis_tkeep
(
s_axis_tkeep
),
.
s_axis_tvalid
(
s_axis_tvalid
),
.
s_axis_tready
(
s_axis_tready
),
.
s_axis_tlast
(
s_axis_tlast
),
.
s_axis_tid
(
s_axis_tid
),
.
s_axis_tdest
(
s_axis_tdest
),
.
s_axis_tuser
(
s_axis_tuser
),
// AXI output
.
m_axis_tdata
(
pre_fifo_axis_tdata
),
.
m_axis_tkeep
(
pre_fifo_axis_tkeep
),
.
m_axis_tvalid
(
pre_fifo_axis_tvalid
),
.
m_axis_tready
(
pre_fifo_axis_tready
),
.
m_axis_tlast
(
pre_fifo_axis_tlast
),
.
m_axis_tid
(
pre_fifo_axis_tid
),
.
m_axis_tdest
(
pre_fifo_axis_tdest
),
.
m_axis_tuser
(
pre_fifo_axis_tuser
)
);
assign
m_axis_tdata
=
post_fifo_axis_tdata
;
assign
m_axis_tkeep
=
post_fifo_axis_tkeep
;
assign
m_axis_tvalid
=
post_fifo_axis_tvalid
;
assign
post_fifo_axis_tready
=
m_axis_tready
;
assign
m_axis_tlast
=
post_fifo_axis_tlast
;
assign
m_axis_tid
=
post_fifo_axis_tid
;
assign
m_axis_tdest
=
post_fifo_axis_tdest
;
assign
m_axis_tuser
=
post_fifo_axis_tuser
;
end
else
begin
// input wider, adapt width after FIFO
assign
pre_fifo_axis_tdata
=
s_axis_tdata
;
assign
pre_fifo_axis_tkeep
=
s_axis_tkeep
;
assign
pre_fifo_axis_tvalid
=
s_axis_tvalid
;
assign
s_axis_tready
=
pre_fifo_axis_tready
;
assign
pre_fifo_axis_tlast
=
s_axis_tlast
;
assign
pre_fifo_axis_tid
=
s_axis_tid
;
assign
pre_fifo_axis_tdest
=
s_axis_tdest
;
assign
pre_fifo_axis_tuser
=
s_axis_tuser
;
axis_adapter
#(
.
S_DATA_WIDTH
(
S_DATA_WIDTH
),
.
S_KEEP_ENABLE
(
S_KEEP_ENABLE
),
.
S_KEEP_WIDTH
(
S_KEEP_WIDTH
),
.
M_DATA_WIDTH
(
M_DATA_WIDTH
),
.
M_KEEP_ENABLE
(
M_KEEP_ENABLE
),
.
M_KEEP_WIDTH
(
M_KEEP_WIDTH
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
)
)
adapter_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
post_fifo_axis_tdata
),
.
s_axis_tkeep
(
post_fifo_axis_tkeep
),
.
s_axis_tvalid
(
post_fifo_axis_tvalid
),
.
s_axis_tready
(
post_fifo_axis_tready
),
.
s_axis_tlast
(
post_fifo_axis_tlast
),
.
s_axis_tid
(
post_fifo_axis_tid
),
.
s_axis_tdest
(
post_fifo_axis_tdest
),
.
s_axis_tuser
(
post_fifo_axis_tuser
),
// AXI output
.
m_axis_tdata
(
m_axis_tdata
),
.
m_axis_tkeep
(
m_axis_tkeep
),
.
m_axis_tvalid
(
m_axis_tvalid
),
.
m_axis_tready
(
m_axis_tready
),
.
m_axis_tlast
(
m_axis_tlast
),
.
m_axis_tid
(
m_axis_tid
),
.
m_axis_tdest
(
m_axis_tdest
),
.
m_axis_tuser
(
m_axis_tuser
)
);
end
endgenerate
axis_fifo
#(
.
DEPTH
(
DEPTH
),
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
EXPAND_BUS
?
M_KEEP_ENABLE
:
S_KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
DEST_ENABLE
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
),
.
FRAME_FIFO
(
FRAME_FIFO
),
.
USER_BAD_FRAME_VALUE
(
USER_BAD_FRAME_VALUE
),
.
USER_BAD_FRAME_MASK
(
USER_BAD_FRAME_MASK
),
.
DROP_BAD_FRAME
(
DROP_BAD_FRAME
),
.
DROP_WHEN_FULL
(
DROP_WHEN_FULL
)
)
fifo_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
pre_fifo_axis_tdata
),
.
s_axis_tkeep
(
pre_fifo_axis_tkeep
),
.
s_axis_tvalid
(
pre_fifo_axis_tvalid
),
.
s_axis_tready
(
pre_fifo_axis_tready
),
.
s_axis_tlast
(
pre_fifo_axis_tlast
),
.
s_axis_tid
(
pre_fifo_axis_tid
),
.
s_axis_tdest
(
pre_fifo_axis_tdest
),
.
s_axis_tuser
(
pre_fifo_axis_tuser
),
// AXI output
.
m_axis_tdata
(
post_fifo_axis_tdata
),
.
m_axis_tkeep
(
post_fifo_axis_tkeep
),
.
m_axis_tvalid
(
post_fifo_axis_tvalid
),
.
m_axis_tready
(
post_fifo_axis_tready
),
.
m_axis_tlast
(
post_fifo_axis_tlast
),
.
m_axis_tid
(
post_fifo_axis_tid
),
.
m_axis_tdest
(
post_fifo_axis_tdest
),
.
m_axis_tuser
(
post_fifo_axis_tuser
),
// Status
.
status_overflow
(
status_overflow
),
.
status_bad_frame
(
status_bad_frame
),
.
status_good_frame
(
status_good_frame
)
);
endmodule
corundum/lib/eth/lib/axis/rtl/axis_frame_join.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
/*
* AXI4-Stream frame joiner
*/
module
axis_frame_join
#
(
// Number of AXI stream inputs
parameter
S_COUNT
=
4
,
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
8
,
// Prepend data with tag
parameter
TAG_ENABLE
=
1
,
// Tag field width
parameter
TAG_WIDTH
=
16
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI inputs
*/
input
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tvalid
,
output
wire
[
S_COUNT
-
1
:
0
]
s_axis_tready
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tlast
,
input
wire
[
S_COUNT
-
1
:
0
]
s_axis_tuser
,
/*
* AXI output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
m_axis_tuser
,
/*
* Configuration
*/
input
wire
[
TAG_WIDTH
-
1
:
0
]
tag
,
/*
* Status signals
*/
output
wire
busy
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
parameter
TAG_WORD_WIDTH
=
(
TAG_WIDTH
+
DATA_WIDTH
-
1
)
/
DATA_WIDTH
;
parameter
CL_TAG_WORD_WIDTH
=
$
clog2
(
TAG_WORD_WIDTH
);
// state register
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_WRITE_TAG
=
2'd1
,
STATE_TRANSFER
=
2'd2
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
CL_TAG_WORD_WIDTH
-
1
:
0
]
frame_ptr_reg
=
{
CL_TAG_WORD_WIDTH
{
1'b0
}}
,
frame_ptr_next
;
reg
[
CL_S_COUNT
-
1
:
0
]
port_sel_reg
=
{
CL_S_COUNT
{
1'b0
}}
,
port_sel_next
;
reg
busy_reg
=
1'b0
,
busy_next
;
reg
output_tuser_reg
=
1'b0
,
output_tuser_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axis_tready_reg
=
{
S_COUNT
{
1'b0
}}
,
s_axis_tready_next
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
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
;
wire
[
DATA_WIDTH
-
1
:
0
]
input_tdata
=
s_axis_tdata
[
port_sel_reg
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
input_tvalid
=
s_axis_tvalid
[
port_sel_reg
];
wire
input_tlast
=
s_axis_tlast
[
port_sel_reg
];
wire
input_tuser
=
s_axis_tuser
[
port_sel_reg
];
always
@*
begin
state_next
=
STATE_IDLE
;
frame_ptr_next
=
frame_ptr_reg
;
port_sel_next
=
port_sel_reg
;
s_axis_tready_next
=
{
S_COUNT
{
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
;
output_tuser_next
=
output_tuser_reg
;
case
(
state_reg
)
STATE_IDLE:
begin
// idle state - wait for data
frame_ptr_next
=
{
CL_TAG_WORD_WIDTH
{
1'b0
}}
;
port_sel_next
=
{
CL_S_COUNT
{
1'b0
}}
;
output_tuser_next
=
1'b0
;
if
(
TAG_ENABLE
)
begin
// next cycle if started will send tag, so do not enable input
s_axis_tready_next
=
1'b0
;
end
else
begin
// next cycle if started will send data, so enable input
s_axis_tready_next
=
m_axis_tready_int_early
;
end
if
(
s_axis_tvalid
)
begin
// input 0 valid; start transferring data
if
(
TAG_ENABLE
)
begin
// tag enabled, so transmit it
if
(
m_axis_tready_int_reg
)
begin
// output is ready, so short-circuit first tag word
frame_ptr_next
=
1
;
m_axis_tdata_int
=
tag
;
m_axis_tvalid_int
=
1'b1
;
end
state_next
=
STATE_WRITE_TAG
;
end
else
begin
// tag disabled, so transmit data
if
(
m_axis_tready_int_reg
)
begin
// output is ready, so short-circuit first data word
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tvalid_int
=
1'b1
;
end
state_next
=
STATE_TRANSFER
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_WRITE_TAG:
begin
// write tag data
if
(
m_axis_tready_int_reg
)
begin
// output ready, so send tag word
state_next
=
STATE_WRITE_TAG
;
frame_ptr_next
=
frame_ptr_reg
+
1
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tdata_int
=
tag
>>
frame_ptr_reg
*
DATA_WIDTH
;
if
(
frame_ptr_reg
==
TAG_WORD_WIDTH
-
1
)
begin
s_axis_tready_next
=
m_axis_tready_int_early
<<
0
;
state_next
=
STATE_TRANSFER
;
end
end
else
begin
state_next
=
STATE_WRITE_TAG
;
end
end
STATE_TRANSFER:
begin
// transfer input data
// set ready for current input
s_axis_tready_next
=
m_axis_tready_int_early
<<
port_sel_reg
;
if
(
input_tvalid
&&
m_axis_tready_int_reg
)
begin
// output ready, transfer byte
state_next
=
STATE_TRANSFER
;
m_axis_tdata_int
=
input_tdata
;
m_axis_tvalid_int
=
input_tvalid
;
if
(
input_tlast
)
begin
// last flag received, switch to next port
port_sel_next
=
port_sel_reg
+
1
;
// save tuser - assert tuser out if ANY tuser asserts received
output_tuser_next
=
output_tuser_next
|
input_tuser
;
// disable input
s_axis_tready_next
=
{
S_COUNT
{
1'b0
}}
;
if
(
S_COUNT
==
1
||
port_sel_reg
==
S_COUNT
-
1
)
begin
// last port - send tlast and tuser and revert to idle
m_axis_tlast_int
=
1'b1
;
m_axis_tuser_int
=
output_tuser_next
;
state_next
=
STATE_IDLE
;
end
else
begin
// otherwise, disable enable next port
s_axis_tready_next
=
m_axis_tready_int_early
<<
port_sel_next
;
end
end
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
{
CL_TAG_WORD_WIDTH
{
1'b0
}}
;
port_sel_reg
<=
{
CL_S_COUNT
{
1'b0
}}
;
s_axis_tready_reg
<=
{
S_COUNT
{
1'b0
}}
;
output_tuser_reg
<=
1'b0
;
busy_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
port_sel_reg
<=
port_sel_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
output_tuser_reg
<=
output_tuser_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
m_axis_tuser_reg
=
1'b0
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
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
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