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
5237 additions
and
0 deletions
+5237
-0
corundum/lib/eth/lib/axis/rtl/axis_frame_join_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_frame_join_wrap.py
+158
-0
corundum/lib/eth/lib/axis/rtl/axis_frame_len.v
corundum/lib/eth/lib/axis/rtl/axis_frame_len.v
+115
-0
corundum/lib/eth/lib/axis/rtl/axis_frame_length_adjust.v
corundum/lib/eth/lib/axis/rtl/axis_frame_length_adjust.v
+613
-0
corundum/lib/eth/lib/axis/rtl/axis_frame_length_adjust_fifo.v
...ndum/lib/eth/lib/axis/rtl/axis_frame_length_adjust_fifo.v
+237
-0
corundum/lib/eth/lib/axis/rtl/axis_ll_bridge.v
corundum/lib/eth/lib/axis/rtl/axis_ll_bridge.v
+79
-0
corundum/lib/eth/lib/axis/rtl/axis_mux.v
corundum/lib/eth/lib/axis/rtl/axis_mux.v
+263
-0
corundum/lib/eth/lib/axis/rtl/axis_mux_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_mux_wrap.py
+183
-0
corundum/lib/eth/lib/axis/rtl/axis_pipeline_register.v
corundum/lib/eth/lib/axis/rtl/axis_pipeline_register.v
+158
-0
corundum/lib/eth/lib/axis/rtl/axis_ram_switch.v
corundum/lib/eth/lib/axis/rtl/axis_ram_switch.v
+1068
-0
corundum/lib/eth/lib/axis/rtl/axis_rate_limit.v
corundum/lib/eth/lib/axis/rtl/axis_rate_limit.v
+256
-0
corundum/lib/eth/lib/axis/rtl/axis_register.v
corundum/lib/eth/lib/axis/rtl/axis_register.v
+276
-0
corundum/lib/eth/lib/axis/rtl/axis_srl_fifo.v
corundum/lib/eth/lib/axis/rtl/axis_srl_fifo.v
+195
-0
corundum/lib/eth/lib/axis/rtl/axis_srl_register.v
corundum/lib/eth/lib/axis/rtl/axis_srl_register.v
+154
-0
corundum/lib/eth/lib/axis/rtl/axis_stat_counter.v
corundum/lib/eth/lib/axis/rtl/axis_stat_counter.v
+366
-0
corundum/lib/eth/lib/axis/rtl/axis_switch.v
corundum/lib/eth/lib/axis/rtl/axis_switch.v
+350
-0
corundum/lib/eth/lib/axis/rtl/axis_switch_wrap.py
corundum/lib/eth/lib/axis/rtl/axis_switch_wrap.py
+219
-0
corundum/lib/eth/lib/axis/rtl/axis_tap.v
corundum/lib/eth/lib/axis/rtl/axis_tap.v
+328
-0
corundum/lib/eth/lib/axis/rtl/ll_axis_bridge.v
corundum/lib/eth/lib/axis/rtl/ll_axis_bridge.v
+64
-0
corundum/lib/eth/lib/axis/rtl/priority_encoder.v
corundum/lib/eth/lib/axis/rtl/priority_encoder.v
+98
-0
corundum/lib/eth/lib/axis/rtl/sync_reset.v
corundum/lib/eth/lib/axis/rtl/sync_reset.v
+57
-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/rtl/axis_frame_join_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream frame joiner 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_frame_join_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 frame joiner 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 frame joiner (wrapper)
*/
module {{name}} #
(
// 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 Stream inputs
*/
{%- for p in range(n) %}
input wire [DATA_WIDTH-1:0] s{{'%02d'%p}}_axis_tdata,
input wire s{{'%02d'%p}}_axis_tvalid,
output wire s{{'%02d'%p}}_axis_tready,
input wire s{{'%02d'%p}}_axis_tlast,
input wire s{{'%02d'%p}}_axis_tuser,
{% endfor %}
/*
* AXI Stream 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
);
axis_frame_join #(
.S_COUNT({{n}}),
.DATA_WIDTH(DATA_WIDTH),
.TAG_ENABLE(TAG_ENABLE),
.TAG_WIDTH(TAG_WIDTH)
)
axis_frame_join_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_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_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_tvalid(m_axis_tvalid),
.m_axis_tready(m_axis_tready),
.m_axis_tlast(m_axis_tlast),
.m_axis_tuser(m_axis_tuser),
// Configuration
.tag(tag),
// Status
.busy(busy)
);
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_frame_len.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 frame length measurement
*/
module
axis_frame_len
#
(
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
64
,
// 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
),
// Width of length counter
parameter
LEN_WIDTH
=
16
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI monitor
*/
input
wire
[
KEEP_WIDTH
-
1
:
0
]
monitor_axis_tkeep
,
input
wire
monitor_axis_tvalid
,
input
wire
monitor_axis_tready
,
input
wire
monitor_axis_tlast
,
/*
* Status
*/
output
wire
[
LEN_WIDTH
-
1
:
0
]
frame_len
,
output
wire
frame_len_valid
);
reg
[
LEN_WIDTH
-
1
:
0
]
frame_len_reg
=
0
,
frame_len_next
;
reg
frame_len_valid_reg
=
1'b0
,
frame_len_valid_next
;
reg
frame_reg
=
1'b0
,
frame_next
;
assign
frame_len
=
frame_len_reg
;
assign
frame_len_valid
=
frame_len_valid_reg
;
integer
offset
,
i
,
bit_cnt
;
always
@*
begin
frame_len_next
=
frame_len_reg
;
frame_len_valid_next
=
1'b0
;
frame_next
=
frame_reg
;
if
(
monitor_axis_tready
&&
monitor_axis_tvalid
)
begin
// valid transfer cycle
if
(
monitor_axis_tlast
)
begin
// end of frame
frame_len_valid_next
=
1'b1
;
frame_next
=
1'b0
;
end
else
if
(
!
frame_reg
)
begin
// first word after end of frame
frame_len_next
=
0
;
frame_next
=
1'b1
;
end
// increment frame length by number of words transferred
if
(
KEEP_ENABLE
)
begin
bit_cnt
=
0
;
for
(
i
=
0
;
i
<=
KEEP_WIDTH
;
i
=
i
+
1
)
begin
if
(
monitor_axis_tkeep
==
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
i
))
bit_cnt
=
i
;
end
frame_len_next
=
frame_len_next
+
bit_cnt
;
end
else
begin
frame_len_next
=
frame_len_next
+
1
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
frame_len_reg
<=
0
;
frame_len_valid_reg
<=
0
;
frame_reg
<=
1'b0
;
end
else
begin
frame_len_reg
<=
frame_len_next
;
frame_len_valid_reg
<=
frame_len_valid_next
;
frame_reg
<=
frame_next
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_frame_length_adjust.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream frame length adjuster
*/
module
axis_frame_length_adjust
#
(
// 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 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 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_valid
,
input
wire
status_ready
,
output
wire
status_frame_pad
,
output
wire
status_frame_truncate
,
output
wire
[
15
:
0
]
status_frame_length
,
output
wire
[
15
:
0
]
status_frame_original_length
,
/*
* Configuration
*/
input
wire
[
15
:
0
]
length_min
,
input
wire
[
15
:
0
]
length_max
);
// bus word width
localparam
DATA_WORD_WIDTH
=
DATA_WIDTH
/
KEEP_WIDTH
;
// bus width assertions
initial
begin
if
(
DATA_WORD_WIDTH
*
KEEP_WIDTH
!=
DATA_WIDTH
)
begin
$
error
(
"Error: data width not evenly divisble (instance %m)"
);
$
finish
;
end
end
// state register
localparam
[
2
:
0
]
STATE_IDLE
=
3'd0
,
STATE_TRANSFER
=
3'd1
,
STATE_PAD
=
3'd2
,
STATE_TRUNCATE
=
3'd3
;
reg
[
2
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
// datapath control signals
reg
store_last_word
;
reg
[
15
:
0
]
frame_ptr_reg
=
16'd0
,
frame_ptr_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_masked
;
// frame length counters
reg
[
15
:
0
]
short_counter_reg
=
16'd0
,
short_counter_next
=
16'd0
;
reg
[
15
:
0
]
long_counter_reg
=
16'd0
,
long_counter_next
=
16'd0
;
reg
[
DATA_WIDTH
-
1
:
0
]
last_word_data_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
last_word_keep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
[
ID_WIDTH
-
1
:
0
]
last_word_id_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
last_word_dest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
last_word_user_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
status_valid_reg
=
1'b0
,
status_valid_next
;
reg
status_frame_pad_reg
=
1'b0
,
status_frame_pad_next
;
reg
status_frame_truncate_reg
=
1'b0
,
status_frame_truncate_next
;
reg
[
15
:
0
]
status_frame_length_reg
=
16'd0
,
status_frame_length_next
;
reg
[
15
:
0
]
status_frame_original_length_reg
=
16'd0
,
status_frame_original_length_next
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
assign
status_valid
=
status_valid_reg
;
assign
status_frame_pad
=
status_frame_pad_reg
;
assign
status_frame_truncate
=
status_frame_truncate_reg
;
assign
status_frame_length
=
status_frame_length_reg
;
assign
status_frame_original_length
=
status_frame_original_length_reg
;
integer
i
,
word_cnt
;
always
@*
begin
state_next
=
STATE_IDLE
;
store_last_word
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
short_counter_next
=
short_counter_reg
;
long_counter_next
=
long_counter_reg
;
m_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b0
}}
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tid_int
=
{
ID_WIDTH
{
1'b0
}}
;
m_axis_tdest_int
=
{
DEST_WIDTH
{
1'b0
}}
;
m_axis_tuser_int
=
{
USER_WIDTH
{
1'b0
}}
;
s_axis_tready_next
=
1'b0
;
status_valid_next
=
status_valid_reg
&&
!
status_ready
;
status_frame_pad_next
=
status_frame_pad_reg
;
status_frame_truncate_next
=
status_frame_truncate_reg
;
status_frame_length_next
=
status_frame_length_reg
;
status_frame_original_length_next
=
status_frame_original_length_reg
;
if
(
KEEP_ENABLE
)
begin
for
(
i
=
0
;
i
<
KEEP_WIDTH
;
i
=
i
+
1
)
begin
s_axis_tdata_masked
[
i
*
DATA_WORD_WIDTH
+:
DATA_WORD_WIDTH
]
=
s_axis_tkeep
[
i
]
?
s_axis_tdata
[
i
*
DATA_WORD_WIDTH
+:
DATA_WORD_WIDTH
]
:
{
DATA_WORD_WIDTH
{
1'b0
}}
;
end
end
else
begin
s_axis_tdata_masked
=
s_axis_tdata
;
end
case
(
state_reg
)
STATE_IDLE:
begin
// idle state
// accept data next cycle if output register ready next cycle
s_axis_tready_next
=
m_axis_tready_int_early
&&
(
!
status_valid_reg
||
status_ready
);
m_axis_tdata_int
=
s_axis_tdata_masked
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
s_axis_tlast
;
m_axis_tid_int
=
s_axis_tid
;
m_axis_tdest_int
=
s_axis_tdest
;
m_axis_tuser_int
=
s_axis_tuser
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// transfer through
word_cnt
=
0
;
for
(
i
=
0
;
i
<=
KEEP_WIDTH
;
i
=
i
+
1
)
begin
//bit_cnt = bit_cnt + monitor_axis_tkeep[i];
if
(
s_axis_tkeep
==
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
i
))
word_cnt
=
i
;
end
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
if
(
short_counter_reg
>
KEEP_WIDTH
)
begin
short_counter_next
=
short_counter_reg
-
KEEP_WIDTH
;
end
else
begin
short_counter_next
=
16'd0
;
end
if
(
long_counter_reg
>
KEEP_WIDTH
)
begin
long_counter_next
=
long_counter_reg
-
KEEP_WIDTH
;
end
else
begin
long_counter_next
=
16'd0
;
end
if
(
long_counter_reg
<=
word_cnt
)
begin
m_axis_tkeep_int
=
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
long_counter_reg
);
if
(
s_axis_tlast
)
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b0
;
status_frame_truncate_next
=
word_cnt
>
long_counter_reg
;
status_frame_length_next
=
length_max
;
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
else
begin
m_axis_tvalid_int
=
1'b0
;
store_last_word
=
1'b1
;
state_next
=
STATE_TRUNCATE
;
end
end
else
begin
if
(
s_axis_tlast
)
begin
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
if
(
short_counter_reg
>
word_cnt
)
begin
if
(
short_counter_reg
>
KEEP_WIDTH
)
begin
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
s_axis_tready_next
=
1'b0
;
m_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tlast_int
=
1'b0
;
store_last_word
=
1'b1
;
state_next
=
STATE_PAD
;
end
else
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b1
;
status_frame_truncate_next
=
1'b0
;
status_frame_length_next
=
length_min
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
m_axis_tkeep_int
=
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
(
length_min
-
frame_ptr_reg
));
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
end
else
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b0
;
status_frame_truncate_next
=
1'b0
;
status_frame_length_next
=
frame_ptr_reg
+
word_cnt
;
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_TRANSFER:
begin
// transfer data
// accept data next cycle if output register ready next cycle
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
s_axis_tdata_masked
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
s_axis_tvalid
;
m_axis_tlast_int
=
s_axis_tlast
;
m_axis_tid_int
=
s_axis_tid
;
m_axis_tdest_int
=
s_axis_tdest
;
m_axis_tuser_int
=
s_axis_tuser
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// transfer through
word_cnt
=
1
;
for
(
i
=
1
;
i
<=
KEEP_WIDTH
;
i
=
i
+
1
)
begin
//bit_cnt = bit_cnt + monitor_axis_tkeep[i];
if
(
s_axis_tkeep
==
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
i
))
word_cnt
=
i
;
end
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
if
(
short_counter_reg
>
KEEP_WIDTH
)
begin
short_counter_next
=
short_counter_reg
-
KEEP_WIDTH
;
end
else
begin
short_counter_next
=
16'd0
;
end
if
(
long_counter_reg
>
KEEP_WIDTH
)
begin
long_counter_next
=
long_counter_reg
-
KEEP_WIDTH
;
end
else
begin
long_counter_next
=
16'd0
;
end
if
(
long_counter_reg
<=
word_cnt
)
begin
m_axis_tkeep_int
=
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
long_counter_reg
);
if
(
s_axis_tlast
)
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b0
;
status_frame_truncate_next
=
word_cnt
>
long_counter_reg
;
status_frame_length_next
=
length_max
;
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
else
begin
m_axis_tvalid_int
=
1'b0
;
store_last_word
=
1'b1
;
state_next
=
STATE_TRUNCATE
;
end
end
else
begin
if
(
s_axis_tlast
)
begin
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
if
(
short_counter_reg
>
word_cnt
)
begin
if
(
short_counter_reg
>
KEEP_WIDTH
)
begin
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
s_axis_tready_next
=
1'b0
;
m_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tlast_int
=
1'b0
;
store_last_word
=
1'b1
;
state_next
=
STATE_PAD
;
end
else
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b1
;
status_frame_truncate_next
=
1'b0
;
status_frame_length_next
=
length_min
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
m_axis_tkeep_int
=
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
short_counter_reg
);
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
end
else
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b0
;
status_frame_truncate_next
=
1'b0
;
status_frame_length_next
=
frame_ptr_reg
+
word_cnt
;
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
STATE_PAD:
begin
// pad to minimum length
s_axis_tready_next
=
1'b0
;
m_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b1
}}
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b0
;
m_axis_tid_int
=
last_word_id_reg
;
m_axis_tdest_int
=
last_word_dest_reg
;
m_axis_tuser_int
=
last_word_user_reg
;
if
(
m_axis_tready_int_reg
)
begin
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
if
(
short_counter_reg
>
KEEP_WIDTH
)
begin
short_counter_next
=
short_counter_reg
-
KEEP_WIDTH
;
end
else
begin
short_counter_next
=
16'd0
;
end
if
(
long_counter_reg
>
KEEP_WIDTH
)
begin
long_counter_next
=
long_counter_reg
-
KEEP_WIDTH
;
end
else
begin
long_counter_next
=
16'd0
;
end
if
(
short_counter_reg
<=
KEEP_WIDTH
)
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b1
;
status_frame_truncate_next
=
1'b0
;
status_frame_length_next
=
length_min
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
m_axis_tkeep_int
=
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
short_counter_reg
);
m_axis_tlast_int
=
1'b1
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_PAD
;
end
end
else
begin
state_next
=
STATE_PAD
;
end
end
STATE_TRUNCATE:
begin
// drop after maximum length
s_axis_tready_next
=
m_axis_tready_int_early
;
m_axis_tdata_int
=
last_word_data_reg
;
m_axis_tkeep_int
=
last_word_keep_reg
;
m_axis_tvalid_int
=
s_axis_tvalid
&&
s_axis_tlast
;
m_axis_tlast_int
=
s_axis_tlast
;
m_axis_tid_int
=
last_word_id_reg
;
m_axis_tdest_int
=
last_word_dest_reg
;
m_axis_tuser_int
=
s_axis_tuser
;
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
word_cnt
=
0
;
for
(
i
=
0
;
i
<=
KEEP_WIDTH
;
i
=
i
+
1
)
begin
//bit_cnt = bit_cnt + monitor_axis_tkeep[i];
if
(
s_axis_tkeep
==
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
i
))
word_cnt
=
i
;
end
frame_ptr_next
=
frame_ptr_reg
+
KEEP_WIDTH
;
if
(
s_axis_tlast
)
begin
status_valid_next
=
1'b1
;
status_frame_pad_next
=
1'b0
;
status_frame_truncate_next
=
1'b1
;
status_frame_length_next
=
length_max
;
status_frame_original_length_next
=
frame_ptr_reg
+
word_cnt
;
s_axis_tready_next
=
m_axis_tready_int_early
&&
status_ready
;
frame_ptr_next
=
16'd0
;
short_counter_next
=
length_min
;
long_counter_next
=
length_max
;
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_TRUNCATE
;
end
end
else
begin
state_next
=
STATE_TRUNCATE
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_ptr_reg
<=
16'd0
;
short_counter_reg
<=
16'd0
;
long_counter_reg
<=
16'd0
;
s_axis_tready_reg
<=
1'b0
;
status_valid_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
frame_ptr_reg
<=
frame_ptr_next
;
short_counter_reg
<=
short_counter_next
;
long_counter_reg
<=
long_counter_next
;
s_axis_tready_reg
<=
s_axis_tready_next
;
status_valid_reg
<=
status_valid_next
;
end
status_frame_pad_reg
<=
status_frame_pad_next
;
status_frame_truncate_reg
<=
status_frame_truncate_next
;
status_frame_length_reg
<=
status_frame_length_next
;
status_frame_original_length_reg
<=
status_frame_original_length_next
;
if
(
store_last_word
)
begin
last_word_data_reg
<=
m_axis_tdata_int
;
last_word_keep_reg
<=
m_axis_tkeep_int
;
last_word_id_reg
<=
m_axis_tid_int
;
last_word_dest_reg
<=
m_axis_tdest_int
;
last_word_user_reg
<=
m_axis_tuser_int
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
m_axis_tlast_reg
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_tid_reg
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_tdest_reg
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_tuser_reg
:
{
USER_WIDTH
{
1'b0
}}
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_tready_int_early
=
m_axis_tready
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid_reg
||
!
m_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
// input is ready
if
(
m_axis_tready
||
!
m_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_tready
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
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_frame_length_adjust_fifo.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream frame length adjuster with FIFO
*/
module
axis_frame_length_adjust_fifo
#
(
// 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 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
,
// Depth of data FIFO in words
parameter
FRAME_FIFO_DEPTH
=
4096
,
// Depth of header FIFO
parameter
HEADER_FIFO_DEPTH
=
8
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
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_axis_hdr_valid
,
input
wire
m_axis_hdr_ready
,
output
wire
m_axis_hdr_pad
,
output
wire
m_axis_hdr_truncate
,
output
wire
[
15
:
0
]
m_axis_hdr_length
,
output
wire
[
15
:
0
]
m_axis_hdr_original_length
,
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
,
/*
* Configuration
*/
input
wire
[
15
:
0
]
length_min
,
input
wire
[
15
:
0
]
length_max
);
wire
[
DATA_WIDTH
-
1
:
0
]
fifo_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
fifo_axis_tkeep
;
wire
fifo_axis_tvalid
;
wire
fifo_axis_tready
;
wire
fifo_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
fifo_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
fifo_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
fifo_axis_tuser
;
wire
status_valid
;
wire
status_ready
;
wire
status_frame_pad
;
wire
status_frame_truncate
;
wire
[
15
:
0
]
status_frame_length
;
wire
[
15
:
0
]
status_frame_original_length
;
axis_frame_length_adjust
#(
.
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_frame_length_adjust_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
(
fifo_axis_tdata
),
.
m_axis_tkeep
(
fifo_axis_tkeep
),
.
m_axis_tvalid
(
fifo_axis_tvalid
),
.
m_axis_tready
(
fifo_axis_tready
),
.
m_axis_tlast
(
fifo_axis_tlast
),
.
m_axis_tid
(
fifo_axis_tid
),
.
m_axis_tdest
(
fifo_axis_tdest
),
.
m_axis_tuser
(
fifo_axis_tuser
),
// Status
.
status_valid
(
status_valid
),
.
status_ready
(
status_ready
),
.
status_frame_pad
(
status_frame_pad
),
.
status_frame_truncate
(
status_frame_truncate
),
.
status_frame_length
(
status_frame_length
),
.
status_frame_original_length
(
status_frame_original_length
),
// Configuration
.
length_min
(
length_min
),
.
length_max
(
length_max
)
);
axis_fifo
#(
.
DEPTH
(
FRAME_FIFO_DEPTH
),
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
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
(
0
)
)
frame_fifo_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
fifo_axis_tdata
),
.
s_axis_tkeep
(
fifo_axis_tkeep
),
.
s_axis_tvalid
(
fifo_axis_tvalid
),
.
s_axis_tready
(
fifo_axis_tready
),
.
s_axis_tlast
(
fifo_axis_tlast
),
.
s_axis_tid
(
fifo_axis_tid
),
.
s_axis_tdest
(
fifo_axis_tdest
),
.
s_axis_tuser
(
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
),
// Status
.
status_overflow
(),
.
status_bad_frame
(),
.
status_good_frame
()
);
axis_fifo
#(
.
DEPTH
(
HEADER_FIFO_DEPTH
),
.
DATA_WIDTH
(
1
+
1
+
16
+
16
),
.
KEEP_ENABLE
(
0
),
.
LAST_ENABLE
(
0
),
.
ID_ENABLE
(
0
),
.
DEST_ENABLE
(
0
),
.
USER_ENABLE
(
0
),
.
FRAME_FIFO
(
0
)
)
header_fifo_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
{
status_frame_pad
,
status_frame_truncate
,
status_frame_length
,
status_frame_original_length
}
),
.
s_axis_tkeep
(
0
),
.
s_axis_tvalid
(
status_valid
),
.
s_axis_tready
(
status_ready
),
.
s_axis_tlast
(
0
),
.
s_axis_tid
(
0
),
.
s_axis_tdest
(
0
),
.
s_axis_tuser
(
0
),
// AXI output
.
m_axis_tdata
(
{
m_axis_hdr_pad
,
m_axis_hdr_truncate
,
m_axis_hdr_length
,
m_axis_hdr_original_length
}
),
.
m_axis_tkeep
(),
.
m_axis_tvalid
(
m_axis_hdr_valid
),
.
m_axis_tready
(
m_axis_hdr_ready
),
.
m_axis_tlast
(),
.
m_axis_tid
(),
.
m_axis_tdest
(),
.
m_axis_tuser
(),
// Status
.
status_overflow
(),
.
status_bad_frame
(),
.
status_good_frame
()
);
endmodule
corundum/lib/eth/lib/axis/rtl/axis_ll_bridge.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 to LocalLink bridge
*/
module
axis_ll_bridge
#
(
parameter
DATA_WIDTH
=
8
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
/*
* LocalLink output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
ll_data_out
,
output
wire
ll_sof_out_n
,
output
wire
ll_eof_out_n
,
output
wire
ll_src_rdy_out_n
,
input
wire
ll_dst_rdy_in_n
);
reg
last_tlast
=
1'b1
;
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
last_tlast
=
1'b1
;
end
else
begin
if
(
s_axis_tvalid
&&
s_axis_tready
)
last_tlast
=
s_axis_tlast
;
end
end
// high for packet length 1 -> cannot set SOF and EOF in same cycle
// invalid packets are discarded
wire
invalid
=
s_axis_tvalid
&&
s_axis_tlast
&&
last_tlast
;
assign
s_axis_tready
=
!
ll_dst_rdy_in_n
;
assign
ll_data_out
=
s_axis_tdata
;
assign
ll_sof_out_n
=
!
(
last_tlast
&&
s_axis_tvalid
&&
!
invalid
);
assign
ll_eof_out_n
=
!
(
s_axis_tlast
&&
!
invalid
);
assign
ll_src_rdy_out_n
=
!
(
s_axis_tvalid
&&
!
invalid
);
endmodule
corundum/lib/eth/lib/axis/rtl/axis_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 multiplexer
*/
module
axis_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
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI 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 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
,
/*
* Control
*/
input
wire
enable
,
input
wire
[$
clog2
(
S_COUNT
)
-
1
:
0
]
select
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
reg
[
CL_S_COUNT
-
1
:
0
]
select_reg
=
2'd0
,
select_next
;
reg
frame_reg
=
1'b0
,
frame_next
;
reg
[
S_COUNT
-
1
:
0
]
s_axis_tready_reg
=
0
,
s_axis_tready_next
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
assign
s_axis_tready
=
s_axis_tready_reg
;
// mux for incoming packet
wire
[
DATA_WIDTH
-
1
:
0
]
current_s_tdata
=
s_axis_tdata
[
select_reg
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
current_s_tkeep
=
s_axis_tkeep
[
select_reg
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
wire
current_s_tvalid
=
s_axis_tvalid
[
select_reg
];
wire
current_s_tready
=
s_axis_tready
[
select_reg
];
wire
current_s_tlast
=
s_axis_tlast
[
select_reg
];
wire
[
ID_WIDTH
-
1
:
0
]
current_s_tid
=
s_axis_tid
[
select_reg
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
current_s_tdest
=
s_axis_tdest
[
select_reg
*
DEST_WIDTH
+:
DEST_WIDTH
];
wire
[
USER_WIDTH
-
1
:
0
]
current_s_tuser
=
s_axis_tuser
[
select_reg
*
USER_WIDTH
+:
USER_WIDTH
];
always
@*
begin
select_next
=
select_reg
;
frame_next
=
frame_reg
;
s_axis_tready_next
=
0
;
if
(
current_s_tvalid
&
current_s_tready
)
begin
// end of frame detection
if
(
current_s_tlast
)
begin
frame_next
=
1'b0
;
end
end
if
(
!
frame_reg
&&
enable
&&
(
s_axis_tvalid
&
(
1
<<
select
)))
begin
// start of frame, grab select value
frame_next
=
1'b1
;
select_next
=
select
;
end
// generate ready signal on selected port
s_axis_tready_next
=
(
m_axis_tready_int_early
&&
frame_next
)
<<
select_next
;
// 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
&&
current_s_tready
&&
frame_reg
;
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
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
select_reg
<=
0
;
frame_reg
<=
1'b0
;
s_axis_tready_reg
<=
0
;
end
else
begin
select_reg
<=
select_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_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_mux_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream 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_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 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 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
)
(
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,
/*
* Control
*/
input wire enable,
input wire [{{cn-1}}:0] select
);
axis_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)
)
axis_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),
// Control
.enable(enable),
.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_pipeline_register.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 pipeline register
*/
module
axis_pipeline_register
#
(
// 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
,
// Register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
REG_TYPE
=
2
,
// Number of registers in pipeline
parameter
LENGTH
=
2
)
(
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
);
wire
[
DATA_WIDTH
-
1
:
0
]
axis_tdata
[
0
:
LENGTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
axis_tkeep
[
0
:
LENGTH
];
wire
axis_tvalid
[
0
:
LENGTH
];
wire
axis_tready
[
0
:
LENGTH
];
wire
axis_tlast
[
0
:
LENGTH
];
wire
[
ID_WIDTH
-
1
:
0
]
axis_tid
[
0
:
LENGTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
axis_tdest
[
0
:
LENGTH
];
wire
[
USER_WIDTH
-
1
:
0
]
axis_tuser
[
0
:
LENGTH
];
assign
axis_tdata
[
0
]
=
s_axis_tdata
;
assign
axis_tkeep
[
0
]
=
s_axis_tkeep
;
assign
axis_tvalid
[
0
]
=
s_axis_tvalid
;
assign
s_axis_tready
=
axis_tready
[
0
];
assign
axis_tlast
[
0
]
=
s_axis_tlast
;
assign
axis_tid
[
0
]
=
s_axis_tid
;
assign
axis_tdest
[
0
]
=
s_axis_tdest
;
assign
axis_tuser
[
0
]
=
s_axis_tuser
;
assign
m_axis_tdata
=
axis_tdata
[
LENGTH
];
assign
m_axis_tkeep
=
axis_tkeep
[
LENGTH
];
assign
m_axis_tvalid
=
axis_tvalid
[
LENGTH
];
assign
axis_tready
[
LENGTH
]
=
m_axis_tready
;
assign
m_axis_tlast
=
axis_tlast
[
LENGTH
];
assign
m_axis_tid
=
axis_tid
[
LENGTH
];
assign
m_axis_tdest
=
axis_tdest
[
LENGTH
];
assign
m_axis_tuser
=
axis_tuser
[
LENGTH
];
generate
genvar
i
;
for
(
i
=
0
;
i
<
LENGTH
;
i
=
i
+
1
)
begin
:
pipe_reg
axis_register
#(
.
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
),
.
REG_TYPE
(
REG_TYPE
)
)
reg_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
axis_tdata
[
i
]),
.
s_axis_tkeep
(
axis_tkeep
[
i
]),
.
s_axis_tvalid
(
axis_tvalid
[
i
]),
.
s_axis_tready
(
axis_tready
[
i
]),
.
s_axis_tlast
(
axis_tlast
[
i
]),
.
s_axis_tid
(
axis_tid
[
i
]),
.
s_axis_tdest
(
axis_tdest
[
i
]),
.
s_axis_tuser
(
axis_tuser
[
i
]),
// AXI output
.
m_axis_tdata
(
axis_tdata
[
i
+
1
]),
.
m_axis_tkeep
(
axis_tkeep
[
i
+
1
]),
.
m_axis_tvalid
(
axis_tvalid
[
i
+
1
]),
.
m_axis_tready
(
axis_tready
[
i
+
1
]),
.
m_axis_tlast
(
axis_tlast
[
i
+
1
]),
.
m_axis_tid
(
axis_tid
[
i
+
1
]),
.
m_axis_tdest
(
axis_tdest
[
i
+
1
]),
.
m_axis_tuser
(
axis_tuser
[
i
+
1
])
);
end
endgenerate
endmodule
corundum/lib/eth/lib/axis/rtl/axis_ram_switch.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2020 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream RAM switch
*/
module
axis_ram_switch
#
(
// FIFO depth in words (each virtual FIFO)
// KEEP_WIDTH words per cycle if KEEP_ENABLE set
// Rounded up to nearest power of 2 cycles
parameter
FIFO_DEPTH
=
4096
,
// Command FIFO depth (each virtual FIFO)
// Rounded up to nearest power of 2
parameter
CMD_FIFO_DEPTH
=
32
,
// Speedup factor (internal data width scaling factor)
// Speedup of 0 scales internal width to provide maximum bandwidth
parameter
SPEEDUP
=
0
,
// Number of AXI stream inputs
parameter
S_COUNT
=
4
,
// Number of AXI stream outputs
parameter
M_COUNT
=
4
,
// Width of input AXI stream interfaces in bits
parameter
S_DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
S_KEEP_ENABLE
=
(
S_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
S_KEEP_WIDTH
=
(
S_DATA_WIDTH
/
8
),
// Width of output AXI stream interfaces in bits
parameter
M_DATA_WIDTH
=
8
,
// Propagate tkeep signal
parameter
M_KEEP_ENABLE
=
(
M_DATA_WIDTH
>
8
),
// tkeep signal width (words per cycle)
parameter
M_KEEP_WIDTH
=
(
M_DATA_WIDTH
/
8
),
// Propagate tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// tdest signal width
// must be wide enough to uniquely address outputs
parameter
DEST_WIDTH
=
$
clog2
(
M_COUNT
),
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// 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
parameter
DROP_BAD_FRAME
=
0
,
// Drop incoming frames when full
// When set, s_axis_tready is always asserted
parameter
DROP_WHEN_FULL
=
0
,
// Output interface routing base tdest selection
// Concatenate M_COUNT DEST_WIDTH sized constants
// Port selected if M_BASE <= tdest <= M_TOP
// set to zero for default routing with tdest MSBs as port index
parameter
M_BASE
=
0
,
// Output interface routing top tdest selection
// Concatenate M_COUNT DEST_WIDTH sized constants
// Port selected if M_BASE <= tdest <= M_TOP
// set to zero to inherit from M_BASE
parameter
M_TOP
=
0
,
// Interface connection control
// M_COUNT concatenated fields of S_COUNT bits
parameter
M_CONNECT
=
{
M_COUNT
{{
S_COUNT
{
1'b1
}}}}
,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
ARB_TYPE
=
"ROUND_ROBIN"
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"HIGH"
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI Stream inputs
*/
input
wire
[
S_COUNT
*
S_DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
S_COUNT
*
S_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 outputs
*/
output
wire
[
M_COUNT
*
M_DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
M_COUNT
*
M_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
,
/*
* Status
*/
output
wire
[
S_COUNT
-
1
:
0
]
status_overflow
,
output
wire
[
S_COUNT
-
1
:
0
]
status_bad_frame
,
output
wire
[
S_COUNT
-
1
:
0
]
status_good_frame
);
parameter
CL_S_COUNT
=
$
clog2
(
S_COUNT
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
// 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
;
// total data and keep widths
parameter
MIN_DATA_WIDTH
=
(
M_KEEP_WIDTH_INT
>
S_KEEP_WIDTH_INT
?
M_DATA_WIDTH
:
S_DATA_WIDTH
);
parameter
MIN_KEEP_WIDTH
=
(
M_KEEP_WIDTH_INT
>
S_KEEP_WIDTH_INT
?
M_KEEP_WIDTH_INT
:
S_KEEP_WIDTH_INT
);
// speedup factor
parameter
M_TOTAL_DATA_WIDTH
=
M_DATA_WIDTH
*
M_COUNT
;
parameter
S_TOTAL_DATA_WIDTH
=
S_DATA_WIDTH
*
S_COUNT
;
parameter
SPEEDUP_INT
=
SPEEDUP
>
0
?
SPEEDUP
:
(
M_TOTAL_DATA_WIDTH
>
S_TOTAL_DATA_WIDTH
?
(
M_TOTAL_DATA_WIDTH
/
MIN_DATA_WIDTH
)
:
(
S_TOTAL_DATA_WIDTH
/
MIN_DATA_WIDTH
));
parameter
DATA_WIDTH
=
MIN_DATA_WIDTH
*
SPEEDUP_INT
;
parameter
KEEP_WIDTH
=
MIN_KEEP_WIDTH
*
SPEEDUP_INT
;
parameter
ADDR_WIDTH
=
$
clog2
(
FIFO_DEPTH
/
KEEP_WIDTH
);
parameter
RAM_ADDR_WIDTH
=
$
clog2
(
S_COUNT
*
FIFO_DEPTH
/
KEEP_WIDTH
);
parameter
CMD_ADDR_WIDTH
=
$
clog2
(
CMD_FIFO_DEPTH
);
integer
i
,
j
;
// check configuration
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
if
(
DEST_WIDTH
<
CL_M_COUNT
)
begin
$
error
(
"Error: DEST_WIDTH too small for port count (instance %m)"
);
$
finish
;
end
if
(
M_BASE
==
0
)
begin
// M_BASE is zero, route with tdest as port index
end
else
if
(
M_TOP
==
0
)
begin
// M_TOP is zero, assume equal to M_BASE
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
for
(
j
=
i
+
1
;
j
<
M_COUNT
;
j
=
j
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
==
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
display
(
"%d: %08x"
,
i
,
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
display
(
"%d: %08x"
,
j
,
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
error
(
"Error: ranges overlap (instance %m)"
);
$
finish
;
end
end
end
end
else
begin
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
>
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
error
(
"Error: invalid range (instance %m)"
);
$
finish
;
end
end
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
for
(
j
=
i
+
1
;
j
<
M_COUNT
;
j
=
j
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
M_TOP
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
display
(
"%d: %08x-%08x"
,
i
,
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
],
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
display
(
"%d: %08x-%08x"
,
j
,
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
],
M_TOP
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
error
(
"Error: ranges overlap (instance %m)"
);
$
finish
;
end
end
end
end
end
// Shared RAM
reg
[
DATA_WIDTH
-
1
:
0
]
mem
[(
2
**
RAM_ADDR_WIDTH
)
-
1
:
0
];
reg
[
DATA_WIDTH
-
1
:
0
]
mem_read_data_reg
;
reg
[
M_COUNT
-
1
:
0
]
mem_read_data_valid_reg
;
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
port_ram_wr_data
;
wire
[
S_COUNT
*
RAM_ADDR_WIDTH
-
1
:
0
]
port_ram_wr_addr
;
wire
[
S_COUNT
-
1
:
0
]
port_ram_wr_en
;
wire
[
S_COUNT
-
1
:
0
]
port_ram_wr_ack
;
wire
[
M_COUNT
*
RAM_ADDR_WIDTH
-
1
:
0
]
port_ram_rd_addr
;
wire
[
M_COUNT
-
1
:
0
]
port_ram_rd_en
;
wire
[
M_COUNT
-
1
:
0
]
port_ram_rd_ack
;
wire
[
M_COUNT
*
DATA_WIDTH
-
1
:
0
]
port_ram_rd_data
;
wire
[
M_COUNT
-
1
:
0
]
port_ram_rd_data_valid
;
assign
port_ram_rd_data
=
{
M_COUNT
{
mem_read_data_reg
}}
;
assign
port_ram_rd_data_valid
=
mem_read_data_valid_reg
;
wire
[
CL_S_COUNT
-
1
:
0
]
ram_wr_sel
;
wire
ram_wr_en
;
wire
[
CL_M_COUNT
-
1
:
0
]
ram_rd_sel
;
wire
ram_rd_en
;
generate
if
(
S_COUNT
>
1
)
begin
arbiter
#(
.
PORTS
(
S_COUNT
),
.
TYPE
(
"ROUND_ROBIN"
),
.
BLOCK
(
"NONE"
),
.
LSB_PRIORITY
(
"HIGH"
)
)
ram_write_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
port_ram_wr_en
&
~
port_ram_wr_ack
),
.
acknowledge
(
{
S_COUNT
{
1'b0
}}
),
.
grant
(
port_ram_wr_ack
),
.
grant_valid
(
ram_wr_en
),
.
grant_encoded
(
ram_wr_sel
)
);
end
else
begin
assign
ram_wr_en
=
port_ram_wr_en
;
assign
port_ram_wr_ack
=
port_ram_wr_en
;
assign
ram_wr_sel
=
0
;
end
endgenerate
always
@
(
posedge
clk
)
begin
if
(
ram_wr_en
)
begin
mem
[
port_ram_wr_addr
[
ram_wr_sel
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
]]
<=
port_ram_wr_data
[
ram_wr_sel
*
DATA_WIDTH
+:
DATA_WIDTH
];
end
end
generate
if
(
M_COUNT
>
1
)
begin
arbiter
#(
.
PORTS
(
M_COUNT
),
.
TYPE
(
"ROUND_ROBIN"
),
.
BLOCK
(
"NONE"
),
.
LSB_PRIORITY
(
"HIGH"
)
)
ram_read_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
port_ram_rd_en
&
~
port_ram_rd_ack
),
.
acknowledge
(
{
M_COUNT
{
1'b0
}}
),
.
grant
(
port_ram_rd_ack
),
.
grant_valid
(
ram_rd_en
),
.
grant_encoded
(
ram_rd_sel
)
);
end
else
begin
assign
ram_rd_en
=
port_ram_rd_en
;
assign
port_ram_rd_ack
=
port_ram_rd_en
;
assign
ram_rd_sel
=
0
;
end
endgenerate
always
@
(
posedge
clk
)
begin
mem_read_data_valid_reg
<=
0
;
if
(
ram_rd_en
)
begin
mem_read_data_reg
<=
mem
[
port_ram_rd_addr
[
ram_rd_sel
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
]];
mem_read_data_valid_reg
<=
1
<<
ram_rd_sel
;
end
if
(
rst
)
begin
mem_read_data_valid_reg
<=
0
;
end
end
// Interconnect
wire
[
S_COUNT
*
RAM_ADDR_WIDTH
-
1
:
0
]
int_cmd_addr
;
wire
[
S_COUNT
*
ADDR_WIDTH
-
1
:
0
]
int_cmd_len
;
wire
[
S_COUNT
*
CMD_ADDR_WIDTH
-
1
:
0
]
int_cmd_id
;
wire
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
int_cmd_tkeep
;
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
int_cmd_tid
;
wire
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
int_cmd_tdest
;
wire
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
int_cmd_tuser
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_cmd_valid
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_cmd_ready
;
wire
[
M_COUNT
*
CMD_ADDR_WIDTH
-
1
:
0
]
int_cmd_status_id
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_cmd_status_valid
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_cmd_status_ready
;
generate
genvar
m
,
n
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
:
s_ifaces
wire
[
DATA_WIDTH
-
1
:
0
]
port_axis_tdata
;
wire
[
KEEP_WIDTH
-
1
:
0
]
port_axis_tkeep
;
wire
port_axis_tvalid
;
wire
port_axis_tready
;
wire
port_axis_tlast
;
wire
[
ID_WIDTH
-
1
:
0
]
port_axis_tid
;
wire
[
DEST_WIDTH
-
1
:
0
]
port_axis_tdest
;
wire
[
USER_WIDTH
-
1
:
0
]
port_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
(
DATA_WIDTH
),
.
M_KEEP_ENABLE
(
1
),
.
M_KEEP_WIDTH
(
KEEP_WIDTH
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
1
),
.
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_DATA_WIDTH
*
m
+:
S_DATA_WIDTH
]),
.
s_axis_tkeep
(
s_axis_tkeep
[
S_KEEP_WIDTH
*
m
+:
S_KEEP_WIDTH
]),
.
s_axis_tvalid
(
s_axis_tvalid
[
m
]),
.
s_axis_tready
(
s_axis_tready
[
m
]),
.
s_axis_tlast
(
s_axis_tlast
[
m
]),
.
s_axis_tid
(
s_axis_tid
[
ID_WIDTH
*
m
+:
ID_WIDTH
]),
.
s_axis_tdest
(
s_axis_tdest
[
DEST_WIDTH
*
m
+:
DEST_WIDTH
]),
.
s_axis_tuser
(
s_axis_tuser
[
USER_WIDTH
*
m
+:
USER_WIDTH
]),
// AXI output
.
m_axis_tdata
(
port_axis_tdata
),
.
m_axis_tkeep
(
port_axis_tkeep
),
.
m_axis_tvalid
(
port_axis_tvalid
),
.
m_axis_tready
(
port_axis_tready
),
.
m_axis_tlast
(
port_axis_tlast
),
.
m_axis_tid
(
port_axis_tid
),
.
m_axis_tdest
(
port_axis_tdest
),
.
m_axis_tuser
(
port_axis_tuser
)
);
// decoding
reg
[
CL_M_COUNT
-
1
:
0
]
select_reg
=
0
,
select_next
;
reg
drop_reg
=
1'b0
,
drop_next
;
reg
select_valid_reg
=
1'b0
,
select_valid_next
;
integer
k
;
always
@*
begin
select_next
=
select_reg
;
drop_next
=
drop_reg
&&
!
(
port_axis_tvalid
&&
port_axis_tready
&&
port_axis_tlast
);
select_valid_next
=
select_valid_reg
&&
!
(
port_axis_tvalid
&&
port_axis_tready
&&
port_axis_tlast
);
if
(
port_axis_tvalid
&&
!
select_valid_reg
&&
!
drop_reg
)
begin
select_next
=
1'b0
;
select_valid_next
=
1'b0
;
drop_next
=
1'b1
;
for
(
k
=
0
;
k
<
M_COUNT
;
k
=
k
+
1
)
begin
if
(
M_BASE
==
0
)
begin
// M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index
if
(
port_axis_tdest
[
DEST_WIDTH
-
CL_M_COUNT
+:
CL_M_COUNT
]
==
k
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
else
if
(
M_TOP
==
0
)
begin
// M_TOP is zero, assume equal to M_BASE
if
(
port_axis_tdest
==
M_BASE
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
else
begin
if
(
port_axis_tdest
>=
M_BASE
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
port_axis_tdest
<=
M_TOP
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
end
end
end
always
@
(
posedge
clk
)
begin
select_reg
<=
select_next
;
drop_reg
<=
drop_next
;
select_valid_reg
<=
select_valid_next
;
if
(
rst
)
begin
select_valid_reg
<=
1'b0
;
end
end
// status arbitration
wire
[
M_COUNT
-
1
:
0
]
request
;
wire
[
M_COUNT
-
1
:
0
]
acknowledge
;
wire
[
M_COUNT
-
1
:
0
]
grant
;
wire
grant_valid
;
wire
[
CL_M_COUNT
-
1
:
0
]
grant_encoded
;
arbiter
#(
.
PORTS
(
M_COUNT
),
.
TYPE
(
ARB_TYPE
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
cmd_status_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
request
),
.
acknowledge
(
acknowledge
),
.
grant
(
grant
),
.
grant_valid
(
grant_valid
),
.
grant_encoded
(
grant_encoded
)
);
// mux
wire
[
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_status_id_mux
=
int_cmd_status_id
[
grant_encoded
*
CMD_ADDR_WIDTH
+:
CMD_ADDR_WIDTH
];
wire
cmd_status_valid_mux
=
int_cmd_status_valid
[
grant_encoded
*
S_COUNT
+
m
]
&&
grant_valid
;
wire
cmd_status_ready_mux
;
assign
int_cmd_status_ready
[
m
*
M_COUNT
+:
M_COUNT
]
=
(
grant_valid
&&
cmd_status_ready_mux
)
<<
grant_encoded
;
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
assign
request
[
n
]
=
int_cmd_status_valid
[
m
+
n
*
S_COUNT
]
&&
!
grant
[
n
];
assign
acknowledge
[
n
]
=
grant
[
n
]
&&
int_cmd_status_valid
[
m
+
n
*
S_COUNT
]
&&
cmd_status_ready_mux
;
end
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
]
rd_ptr_reg
=
{
ADDR_WIDTH
+
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
len_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
len_next
;
// full when first MSB different but rest same
wire
full
=
wr_ptr_cur_reg
==
(
rd_ptr_reg
^
{
1'b1
,
{
ADDR_WIDTH
{
1'b0
}}}
);
// empty when pointers match exactly
wire
empty
=
wr_ptr_reg
==
rd_ptr_reg
;
// overflow within packet
wire
full_wr
=
wr_ptr_cur_reg
==
(
wr_ptr_reg
^
{
1'b1
,
{
ADDR_WIDTH
{
1'b0
}}}
);
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
[
DATA_WIDTH
-
1
:
0
]
ram_wr_data_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
ram_wr_data_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
ram_wr_addr_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
ram_wr_addr_next
;
reg
ram_wr_en_reg
=
1'b0
,
ram_wr_en_next
;
wire
ram_wr_ack
;
reg
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_table_active
=
0
;
reg
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_table_commit
=
0
;
reg
[
RAM_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_addr_start
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
RAM_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_addr_end
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
ADDR_WIDTH
-
1
:
0
]
cmd_table_len
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
CL_M_COUNT
-
1
:
0
]
cmd_table_select
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
KEEP_WIDTH
-
1
:
0
]
cmd_table_tkeep
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
ID_WIDTH
-
1
:
0
]
cmd_table_tid
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
DEST_WIDTH
-
1
:
0
]
cmd_table_tdest
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
USER_WIDTH
-
1
:
0
]
cmd_table_tuser
[
2
**
CMD_ADDR_WIDTH
-
1
:
0
];
reg
[
CMD_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_start_ptr_reg
=
0
;
reg
[
RAM_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_start_addr_start
;
reg
[
RAM_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_start_addr_end
;
reg
[
ADDR_WIDTH
-
1
:
0
]
cmd_table_start_len
;
reg
[
CL_M_COUNT
-
1
:
0
]
cmd_table_start_select
;
reg
[
KEEP_WIDTH
-
1
:
0
]
cmd_table_start_tkeep
;
reg
[
ID_WIDTH
-
1
:
0
]
cmd_table_start_tid
;
reg
[
DEST_WIDTH
-
1
:
0
]
cmd_table_start_tdest
;
reg
[
USER_WIDTH
-
1
:
0
]
cmd_table_start_tuser
;
reg
cmd_table_start_en
;
reg
[
CMD_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_read_ptr_reg
=
0
;
reg
cmd_table_read_en
;
reg
[
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_table_commit_ptr
;
reg
cmd_table_commit_en
;
reg
[
CMD_ADDR_WIDTH
+
1
-
1
:
0
]
cmd_table_finish_ptr_reg
=
0
;
reg
cmd_table_finish_en
;
reg
[
RAM_ADDR_WIDTH
-
1
:
0
]
cmd_addr_reg
=
{
RAM_ADDR_WIDTH
{
1'b0
}}
,
cmd_addr_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
cmd_len_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
cmd_len_next
;
reg
[
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_id_reg
=
{
CMD_ADDR_WIDTH
{
1'b0
}}
,
cmd_id_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
cmd_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
cmd_tkeep_next
;
reg
[
ID_WIDTH
-
1
:
0
]
cmd_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
cmd_tid_next
;
reg
[
DEST_WIDTH
-
1
:
0
]
cmd_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
,
cmd_tdest_next
;
reg
[
USER_WIDTH
-
1
:
0
]
cmd_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
,
cmd_tuser_next
;
reg
[
M_COUNT
-
1
:
0
]
cmd_valid_reg
=
0
,
cmd_valid_next
;
reg
cmd_status_ready_reg
=
1'b0
,
cmd_status_ready_next
;
wire
[
M_COUNT
-
1
:
0
]
port_cmd_ready
;
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
assign
port_cmd_ready
[
n
]
=
int_cmd_ready
[
m
+
n
*
S_COUNT
];
end
assign
port_axis_tready
=
(
select_valid_reg
&&
(
!
ram_wr_en_reg
||
ram_wr_ack
)
&&
(
!
full
||
full_wr
||
DROP_WHEN_FULL
)
&&
($
unsigned
(
cmd_table_start_ptr_reg
-
cmd_table_finish_ptr_reg
)
<
2
**
CMD_ADDR_WIDTH
))
||
drop_reg
;
assign
port_ram_wr_data
[
m
*
DATA_WIDTH
+:
DATA_WIDTH
]
=
ram_wr_data_reg
;
assign
port_ram_wr_addr
[
m
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
]
=
ram_wr_addr_reg
[
ADDR_WIDTH
-
1
:
0
]
|
(
m
<<
ADDR_WIDTH
);
assign
port_ram_wr_en
[
m
]
=
ram_wr_en_reg
;
assign
ram_wr_ack
=
port_ram_wr_ack
[
m
];
assign
int_cmd_addr
[
m
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
]
=
cmd_addr_reg
[
ADDR_WIDTH
-
1
:
0
]
|
(
m
<<
ADDR_WIDTH
);
assign
int_cmd_len
[
m
*
ADDR_WIDTH
+:
ADDR_WIDTH
]
=
cmd_len_reg
;
assign
int_cmd_id
[
m
*
CMD_ADDR_WIDTH
+:
CMD_ADDR_WIDTH
]
=
cmd_id_reg
;
assign
int_cmd_tkeep
[
m
*
KEEP_WIDTH
+:
KEEP_WIDTH
]
=
cmd_tkeep_reg
;
assign
int_cmd_tid
[
m
*
ID_WIDTH
+:
ID_WIDTH
]
=
cmd_tid_reg
;
assign
int_cmd_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]
=
cmd_tdest_reg
;
assign
int_cmd_tuser
[
m
*
USER_WIDTH
+:
USER_WIDTH
]
=
cmd_tuser_reg
;
assign
int_cmd_valid
[
m
*
M_COUNT
+:
M_COUNT
]
=
cmd_valid_reg
;
assign
cmd_status_ready_mux
=
cmd_status_ready_reg
;
assign
status_overflow
[
m
]
=
overflow_reg
;
assign
status_bad_frame
[
m
]
=
bad_frame_reg
;
assign
status_good_frame
[
m
]
=
good_frame_reg
;
always
@*
begin
wr_ptr_next
=
wr_ptr_reg
;
wr_ptr_cur_next
=
wr_ptr_cur_reg
;
rd_ptr_next
=
rd_ptr_reg
;
len_next
=
len_reg
;
drop_frame_next
=
drop_frame_reg
;
overflow_next
=
1'b0
;
bad_frame_next
=
1'b0
;
good_frame_next
=
1'b0
;
ram_wr_data_next
=
ram_wr_data_reg
;
ram_wr_addr_next
=
ram_wr_addr_reg
;
ram_wr_en_next
=
ram_wr_en_reg
&&
!
ram_wr_ack
;
cmd_table_start_addr_start
=
wr_ptr_reg
;
cmd_table_start_addr_end
=
wr_ptr_cur_reg
+
1
;
cmd_table_start_len
=
len_reg
;
cmd_table_start_select
=
select_reg
;
cmd_table_start_tkeep
=
S_KEEP_ENABLE
?
port_axis_tkeep
:
1'b1
;
cmd_table_start_tid
=
port_axis_tid
;
cmd_table_start_tdest
=
port_axis_tdest
;
cmd_table_start_tuser
=
port_axis_tuser
;
cmd_table_start_en
=
1'b0
;
cmd_table_read_en
=
1'b0
;
cmd_table_commit_ptr
=
0
;
cmd_table_commit_en
=
1'b0
;
cmd_table_finish_en
=
1'b0
;
cmd_addr_next
=
cmd_addr_reg
;
cmd_len_next
=
cmd_len_reg
;
cmd_id_next
=
cmd_id_reg
;
cmd_tkeep_next
=
cmd_tkeep_reg
;
cmd_tid_next
=
cmd_tid_reg
;
cmd_tdest_next
=
cmd_tdest_reg
;
cmd_tuser_next
=
cmd_tuser_reg
;
cmd_valid_next
=
cmd_valid_reg
;
cmd_status_ready_next
=
1'b0
;
// issue memory writes and commands
if
(
port_axis_tready
&&
port_axis_tvalid
&&
select_valid_reg
&&
!
drop_reg
)
begin
if
(
full
||
full_wr
||
drop_frame_reg
)
begin
// full, packet overflow, or currently dropping frame
// drop frame
drop_frame_next
=
1'b1
;
if
(
port_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
wr_ptr_cur_next
=
wr_ptr_cur_reg
+
1
;
len_next
=
len_reg
+
1
;
// issue write operation
ram_wr_data_next
=
port_axis_tdata
;
ram_wr_addr_next
=
wr_ptr_cur_reg
;
ram_wr_en_next
=
1'b1
;
if
(
port_axis_tlast
)
begin
// end of frame
len_next
=
0
;
if
(
DROP_BAD_FRAME
&&
USER_BAD_FRAME_MASK
&
~
(
port_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
;
cmd_table_start_addr_start
=
wr_ptr_reg
;
cmd_table_start_addr_end
=
wr_ptr_cur_reg
+
1
;
cmd_table_start_len
=
len_reg
;
cmd_table_start_select
=
select_reg
;
cmd_table_start_tkeep
=
S_KEEP_ENABLE
?
port_axis_tkeep
:
1'b1
;
cmd_table_start_tid
=
port_axis_tid
;
cmd_table_start_tdest
=
port_axis_tdest
;
cmd_table_start_tuser
=
port_axis_tuser
;
cmd_table_start_en
=
1'b1
;
end
end
end
end
// read
cmd_valid_next
=
cmd_valid_reg
&
~
port_cmd_ready
;
if
(
!
cmd_valid_reg
&&
cmd_table_active
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
&&
cmd_table_read_ptr_reg
!=
cmd_table_start_ptr_reg
)
begin
cmd_table_read_en
=
1'b1
;
cmd_addr_next
=
cmd_table_addr_start
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_len_next
=
cmd_table_len
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_id_next
=
cmd_table_read_ptr_reg
;
cmd_tkeep_next
=
cmd_table_tkeep
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_tid_next
=
cmd_table_tid
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_tdest_next
=
cmd_table_tdest
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_tuser_next
=
cmd_table_tuser
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_valid_next
=
1
<<
cmd_table_select
[
cmd_table_read_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
end
// commit
if
(
cmd_status_valid_mux
)
begin
cmd_status_ready_next
=
1'b1
;
cmd_table_commit_ptr
=
cmd_status_id_mux
;
cmd_table_commit_en
=
1'b1
;
end
// clean-up
if
(
cmd_table_active
[
cmd_table_finish_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
&&
cmd_table_commit
[
cmd_table_finish_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
&&
cmd_table_finish_ptr_reg
!=
cmd_table_start_ptr_reg
)
begin
// update read pointer
rd_ptr_next
=
cmd_table_addr_end
[
cmd_table_finish_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]];
cmd_table_finish_en
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
wr_ptr_reg
<=
wr_ptr_next
;
wr_ptr_cur_reg
<=
wr_ptr_cur_next
;
rd_ptr_reg
<=
rd_ptr_next
;
len_reg
<=
len_next
;
drop_frame_reg
<=
drop_frame_next
;
overflow_reg
<=
overflow_next
;
bad_frame_reg
<=
bad_frame_next
;
good_frame_reg
<=
good_frame_next
;
ram_wr_data_reg
<=
ram_wr_data_next
;
ram_wr_addr_reg
<=
ram_wr_addr_next
;
ram_wr_en_reg
<=
ram_wr_en_next
;
cmd_addr_reg
<=
cmd_addr_next
;
cmd_len_reg
<=
cmd_len_next
;
cmd_id_reg
<=
cmd_id_next
;
cmd_tkeep_reg
<=
cmd_tkeep_next
;
cmd_tid_reg
<=
cmd_tid_next
;
cmd_tdest_reg
<=
cmd_tdest_next
;
cmd_tuser_reg
<=
cmd_tuser_next
;
cmd_valid_reg
<=
cmd_valid_next
;
cmd_status_ready_reg
<=
cmd_status_ready_next
;
if
(
cmd_table_start_en
)
begin
cmd_table_start_ptr_reg
<=
cmd_table_start_ptr_reg
+
1
;
cmd_table_active
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
1'b1
;
cmd_table_commit
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
1'b0
;
cmd_table_addr_start
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_addr_start
;
cmd_table_addr_end
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_addr_end
;
cmd_table_len
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_len
;
cmd_table_select
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_select
;
cmd_table_tkeep
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_tkeep
;
cmd_table_tid
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_tid
;
cmd_table_tdest
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_tdest
;
cmd_table_tuser
[
cmd_table_start_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
cmd_table_start_tuser
;
end
if
(
cmd_table_read_en
)
begin
cmd_table_read_ptr_reg
<=
cmd_table_read_ptr_reg
+
1
;
end
if
(
cmd_table_commit_en
)
begin
cmd_table_commit
[
cmd_table_commit_ptr
]
<=
1'b1
;
end
if
(
cmd_table_finish_en
)
begin
cmd_table_finish_ptr_reg
<=
cmd_table_finish_ptr_reg
+
1
;
cmd_table_active
[
cmd_table_finish_ptr_reg
[
CMD_ADDR_WIDTH
-
1
:
0
]]
<=
1'b1
;
end
if
(
rst
)
begin
wr_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
wr_ptr_cur_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
rd_ptr_reg
<=
{
ADDR_WIDTH
+
1
{
1'b0
}}
;
len_reg
<=
{
ADDR_WIDTH
{
1'b0
}}
;
drop_frame_reg
<=
1'b0
;
overflow_reg
<=
1'b0
;
bad_frame_reg
<=
1'b0
;
good_frame_reg
<=
1'b0
;
ram_wr_en_reg
<=
1'b0
;
cmd_valid_reg
<=
1'b0
;
cmd_status_ready_reg
<=
1'b0
;
cmd_table_start_ptr_reg
<=
0
;
cmd_table_read_ptr_reg
<=
0
;
cmd_table_finish_ptr_reg
<=
0
;
end
end
end
// s_ifaces
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
:
m_ifaces
// command arbitration
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
;
arbiter
#(
.
PORTS
(
S_COUNT
),
.
TYPE
(
ARB_TYPE
),
.
BLOCK
(
"ACKNOWLEDGE"
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
cmd_arb_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
.
request
(
request
),
.
acknowledge
(
acknowledge
),
.
grant
(
grant
),
.
grant_valid
(
grant_valid
),
.
grant_encoded
(
grant_encoded
)
);
// mux
wire
[
RAM_ADDR_WIDTH
-
1
:
0
]
cmd_addr_mux
=
int_cmd_addr
[
grant_encoded
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
];
wire
[
ADDR_WIDTH
-
1
:
0
]
cmd_len_mux
=
int_cmd_len
[
grant_encoded
*
ADDR_WIDTH
+:
ADDR_WIDTH
];
wire
[
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_id_mux
=
int_cmd_id
[
grant_encoded
*
CMD_ADDR_WIDTH
+:
CMD_ADDR_WIDTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
cmd_tkeep_mux
=
int_cmd_tkeep
[
grant_encoded
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
wire
[
ID_WIDTH
-
1
:
0
]
cmd_tid_mux
=
int_cmd_tid
[
grant_encoded
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
cmd_tdest_mux
=
int_cmd_tdest
[
grant_encoded
*
DEST_WIDTH
+:
DEST_WIDTH
];
wire
[
USER_WIDTH
-
1
:
0
]
cmd_tuser_mux
=
int_cmd_tuser
[
grant_encoded
*
USER_WIDTH
+:
USER_WIDTH
];
wire
cmd_valid_mux
=
int_cmd_valid
[
grant_encoded
*
M_COUNT
+
n
]
&&
grant_valid
;
wire
cmd_ready_mux
;
assign
int_cmd_ready
[
n
*
S_COUNT
+:
S_COUNT
]
=
(
grant_valid
&&
cmd_ready_mux
)
<<
grant_encoded
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
assign
request
[
m
]
=
int_cmd_valid
[
m
*
M_COUNT
+
n
]
&&
!
grant
[
m
];
assign
acknowledge
[
m
]
=
grant
[
m
]
&&
int_cmd_valid
[
m
*
M_COUNT
+
n
]
&&
cmd_ready_mux
;
end
reg
[
RAM_ADDR_WIDTH
-
1
:
0
]
rd_ptr_reg
=
{
RAM_ADDR_WIDTH
-
1
{
1'b0
}}
,
rd_ptr_next
;
reg
[
ADDR_WIDTH
-
1
:
0
]
len_reg
=
{
ADDR_WIDTH
{
1'b0
}}
,
len_next
;
reg
[
CL_S_COUNT
-
1
:
0
]
src_reg
=
0
,
src_next
;
reg
[
CMD_ADDR_WIDTH
-
1
:
0
]
id_reg
=
0
,
id_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
last_cycle_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
last_cycle_tkeep_next
;
reg
[
ID_WIDTH
-
1
:
0
]
tid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
tid_next
;
reg
[
DEST_WIDTH
-
1
:
0
]
tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
,
tdest_next
;
reg
[
USER_WIDTH
-
1
:
0
]
tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
,
tuser_next
;
reg
[
DATA_WIDTH
-
1
:
0
]
out_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
,
out_axis_tdata_next
;
reg
[
KEEP_WIDTH
-
1
:
0
]
out_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
,
out_axis_tkeep_next
;
reg
out_axis_tvalid_reg
=
1'b0
,
out_axis_tvalid_next
;
wire
out_axis_tready
;
reg
out_axis_tlast_reg
=
1'b0
,
out_axis_tlast_next
;
reg
[
ID_WIDTH
-
1
:
0
]
out_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
,
out_axis_tid_next
;
reg
[
DEST_WIDTH
-
1
:
0
]
out_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
,
out_axis_tdest_next
;
reg
[
USER_WIDTH
-
1
:
0
]
out_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
,
out_axis_tuser_next
;
reg
[
RAM_ADDR_WIDTH
-
1
:
0
]
ram_rd_addr_reg
=
{
RAM_ADDR_WIDTH
{
1'b0
}}
,
ram_rd_addr_next
;
reg
ram_rd_en_reg
=
1'b0
,
ram_rd_en_next
;
wire
ram_rd_ack
;
wire
[
DATA_WIDTH
-
1
:
0
]
ram_rd_data
;
wire
ram_rd_data_valid
;
reg
cmd_valid_reg
=
1'b0
,
cmd_valid_next
;
reg
[
CMD_ADDR_WIDTH
-
1
:
0
]
cmd_status_id_reg
=
{
CMD_ADDR_WIDTH
{
1'b0
}}
,
cmd_status_id_next
;
reg
[
S_COUNT
-
1
:
0
]
cmd_status_valid_reg
=
0
,
cmd_status_valid_next
;
wire
[
S_COUNT
-
1
:
0
]
port_cmd_status_ready
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
assign
port_cmd_status_ready
[
m
]
=
int_cmd_status_ready
[
m
*
M_COUNT
+
n
];
end
reg
[
DATA_WIDTH
-
1
:
0
]
out_fifo_tdata
[
31
:
0
];
reg
[
KEEP_WIDTH
-
1
:
0
]
out_fifo_tkeep
[
31
:
0
];
reg
out_fifo_tlast
[
31
:
0
];
reg
[
ID_WIDTH
-
1
:
0
]
out_fifo_tid
[
31
:
0
];
reg
[
DEST_WIDTH
-
1
:
0
]
out_fifo_tdest
[
31
:
0
];
reg
[
USER_WIDTH
-
1
:
0
]
out_fifo_tuser
[
31
:
0
];
reg
[
5
:
0
]
out_fifo_data_wr_ptr_reg
=
0
;
reg
[
DATA_WIDTH
-
1
:
0
]
out_fifo_data_wr_tdata
;
reg
out_fifo_data_wr_en
;
reg
[
5
:
0
]
out_fifo_ctrl_wr_ptr_reg
=
0
;
reg
[
KEEP_WIDTH
-
1
:
0
]
out_fifo_ctrl_wr_tkeep
;
reg
out_fifo_ctrl_wr_tlast
;
reg
[
ID_WIDTH
-
1
:
0
]
out_fifo_ctrl_wr_tid
;
reg
[
DEST_WIDTH
-
1
:
0
]
out_fifo_ctrl_wr_tdest
;
reg
[
USER_WIDTH
-
1
:
0
]
out_fifo_ctrl_wr_tuser
;
reg
out_fifo_ctrl_wr_en
;
reg
[
5
:
0
]
out_fifo_rd_ptr_reg
=
0
;
reg
out_fifo_rd_en
;
assign
port_ram_rd_addr
[
n
*
RAM_ADDR_WIDTH
+:
RAM_ADDR_WIDTH
]
=
ram_rd_addr_reg
;
assign
port_ram_rd_en
[
n
]
=
ram_rd_en_reg
;
assign
ram_rd_ack
=
port_ram_rd_ack
[
n
];
assign
ram_rd_data
=
port_ram_rd_data
[
n
*
DATA_WIDTH
+:
DATA_WIDTH
];
assign
ram_rd_data_valid
=
port_ram_rd_data_valid
[
n
];
assign
cmd_ready_mux
=
!
cmd_valid_reg
;
assign
int_cmd_status_id
[
n
*
CMD_ADDR_WIDTH
+:
CMD_ADDR_WIDTH
]
=
cmd_status_id_reg
;
assign
int_cmd_status_valid
[
n
*
S_COUNT
+:
S_COUNT
]
=
cmd_status_valid_reg
;
always
@*
begin
rd_ptr_next
=
rd_ptr_reg
;
len_next
=
len_reg
;
src_next
=
src_reg
;
id_next
=
id_reg
;
last_cycle_tkeep_next
=
last_cycle_tkeep_reg
;
tid_next
=
tid_reg
;
tdest_next
=
tdest_reg
;
tuser_next
=
tuser_reg
;
out_axis_tdata_next
=
out_axis_tdata_reg
;
out_axis_tkeep_next
=
out_axis_tkeep_reg
;
out_axis_tvalid_next
=
out_axis_tvalid_reg
&&
!
out_axis_tready
;
out_axis_tlast_next
=
out_axis_tlast_reg
;
out_axis_tid_next
=
out_axis_tid_reg
;
out_axis_tdest_next
=
out_axis_tdest_reg
;
out_axis_tuser_next
=
out_axis_tuser_reg
;
ram_rd_addr_next
=
ram_rd_addr_reg
;
ram_rd_en_next
=
ram_rd_en_reg
&&
!
ram_rd_ack
;
cmd_valid_next
=
cmd_valid_reg
;
cmd_status_id_next
=
cmd_status_id_reg
;
cmd_status_valid_next
=
cmd_status_valid_reg
&
~
port_cmd_status_ready
;
out_fifo_data_wr_tdata
=
ram_rd_data
;
out_fifo_data_wr_en
=
1'b0
;
out_fifo_ctrl_wr_tkeep
=
len_reg
==
0
?
last_cycle_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
out_fifo_ctrl_wr_tlast
=
len_reg
==
0
;
out_fifo_ctrl_wr_tid
=
tid_reg
;
out_fifo_ctrl_wr_tdest
=
tdest_reg
;
out_fifo_ctrl_wr_tuser
=
tuser_reg
;
out_fifo_ctrl_wr_en
=
1'b0
;
out_fifo_rd_en
=
1'b0
;
// receive commands
if
(
!
cmd_valid_reg
&&
cmd_valid_mux
)
begin
cmd_valid_next
=
1'b1
;
rd_ptr_next
=
cmd_addr_mux
;
len_next
=
cmd_len_mux
;
last_cycle_tkeep_next
=
cmd_tkeep_mux
;
id_next
=
cmd_id_mux
;
tid_next
=
cmd_tid_mux
;
tdest_next
=
cmd_tdest_mux
;
tuser_next
=
cmd_tuser_mux
;
src_next
=
grant_encoded
;
end
// process commands and issue memory reads
if
(
cmd_valid_reg
&&
(
!
ram_rd_en_reg
||
ram_rd_ack
)
&&
($
unsigned
(
out_fifo_ctrl_wr_ptr_reg
-
out_fifo_rd_ptr_reg
)
<
32
))
begin
// update counters
rd_ptr_next
[
ADDR_WIDTH
-
1
:
0
]
=
rd_ptr_reg
[
ADDR_WIDTH
-
1
:
0
]
+
1
;
len_next
=
len_reg
-
1
;
// issue memory read
ram_rd_addr_next
=
rd_ptr_reg
;
ram_rd_en_next
=
1'b1
;
// write output control FIFO
out_fifo_ctrl_wr_tkeep
=
len_reg
==
0
?
last_cycle_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
out_fifo_ctrl_wr_tlast
=
len_reg
==
0
;
out_fifo_ctrl_wr_tid
=
tid_reg
;
out_fifo_ctrl_wr_tdest
=
tdest_reg
;
out_fifo_ctrl_wr_tuser
=
tuser_reg
;
out_fifo_ctrl_wr_en
=
1'b1
;
if
(
len_reg
==
0
)
begin
// indicate operation complete
cmd_status_id_next
=
id_reg
;
cmd_status_valid_next
=
1
<<
src_reg
;
cmd_valid_next
=
1'b0
;
end
end
// write RAM read data to output data FIFO
if
(
ram_rd_data_valid
)
begin
out_fifo_data_wr_tdata
=
ram_rd_data
;
out_fifo_data_wr_en
=
1'b1
;
end
// generate output AXI stream data from control and data FIFOs
if
((
out_axis_tready
||
!
out_axis_tvalid_reg
)
&&
(
out_fifo_rd_ptr_reg
!=
out_fifo_ctrl_wr_ptr_reg
)
&&
(
out_fifo_rd_ptr_reg
!=
out_fifo_data_wr_ptr_reg
))
begin
out_fifo_rd_en
=
1'b1
;
out_axis_tdata_next
=
out_fifo_tdata
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
out_axis_tkeep_next
=
out_fifo_tkeep
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
out_axis_tvalid_next
=
1'b1
;
out_axis_tlast_next
=
out_fifo_tlast
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
out_axis_tid_next
=
out_fifo_tid
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
out_axis_tdest_next
=
out_fifo_tdest
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
out_axis_tuser_next
=
out_fifo_tuser
[
out_fifo_rd_ptr_reg
[
4
:
0
]];
end
end
always
@
(
posedge
clk
)
begin
rd_ptr_reg
<=
rd_ptr_next
;
len_reg
<=
len_next
;
src_reg
<=
src_next
;
id_reg
<=
id_next
;
last_cycle_tkeep_reg
<=
last_cycle_tkeep_next
;
tid_reg
<=
tid_next
;
tdest_reg
<=
tdest_next
;
tuser_reg
<=
tuser_next
;
out_axis_tdata_reg
<=
out_axis_tdata_next
;
out_axis_tkeep_reg
<=
out_axis_tkeep_next
;
out_axis_tvalid_reg
<=
out_axis_tvalid_next
;
out_axis_tlast_reg
<=
out_axis_tlast_next
;
out_axis_tid_reg
<=
out_axis_tid_next
;
out_axis_tdest_reg
<=
out_axis_tdest_next
;
out_axis_tuser_reg
<=
out_axis_tuser_next
;
ram_rd_addr_reg
<=
ram_rd_addr_next
;
ram_rd_en_reg
<=
ram_rd_en_next
;
cmd_valid_reg
<=
cmd_valid_next
;
cmd_status_id_reg
<=
cmd_status_id_next
;
cmd_status_valid_reg
<=
cmd_status_valid_next
;
if
(
out_fifo_data_wr_en
)
begin
out_fifo_data_wr_ptr_reg
<=
out_fifo_data_wr_ptr_reg
+
1
;
out_fifo_tdata
[
out_fifo_data_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_data_wr_tdata
;
end
if
(
out_fifo_ctrl_wr_en
)
begin
out_fifo_ctrl_wr_ptr_reg
<=
out_fifo_ctrl_wr_ptr_reg
+
1
;
out_fifo_tkeep
[
out_fifo_ctrl_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_ctrl_wr_tkeep
;
out_fifo_tlast
[
out_fifo_ctrl_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_ctrl_wr_tlast
;
out_fifo_tid
[
out_fifo_ctrl_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_ctrl_wr_tid
;
out_fifo_tdest
[
out_fifo_ctrl_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_ctrl_wr_tdest
;
out_fifo_tuser
[
out_fifo_ctrl_wr_ptr_reg
[
4
:
0
]]
<=
out_fifo_ctrl_wr_tuser
;
end
if
(
out_fifo_rd_en
)
begin
out_fifo_rd_ptr_reg
<=
out_fifo_rd_ptr_reg
+
1
;
end
if
(
rst
)
begin
len_reg
<=
0
;
out_axis_tvalid_reg
<=
1'b0
;
ram_rd_en_reg
<=
1'b0
;
cmd_valid_reg
<=
1'b0
;
cmd_status_valid_reg
<=
0
;
out_fifo_data_wr_ptr_reg
<=
0
;
out_fifo_ctrl_wr_ptr_reg
<=
0
;
out_fifo_rd_ptr_reg
<=
0
;
end
end
axis_adapter
#(
.
S_DATA_WIDTH
(
DATA_WIDTH
),
.
S_KEEP_ENABLE
(
1
),
.
S_KEEP_WIDTH
(
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
(
1
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
)
)
adapter_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
out_axis_tdata_reg
),
.
s_axis_tkeep
(
out_axis_tkeep_reg
),
.
s_axis_tvalid
(
out_axis_tvalid_reg
),
.
s_axis_tready
(
out_axis_tready
),
.
s_axis_tlast
(
out_axis_tlast_reg
),
.
s_axis_tid
(
out_axis_tid_reg
),
.
s_axis_tdest
(
out_axis_tdest_reg
),
.
s_axis_tuser
(
out_axis_tuser_reg
),
// AXI output
.
m_axis_tdata
(
m_axis_tdata
[
M_DATA_WIDTH
*
n
+:
M_DATA_WIDTH
]),
.
m_axis_tkeep
(
m_axis_tkeep
[
M_KEEP_WIDTH
*
n
+:
M_KEEP_WIDTH
]),
.
m_axis_tvalid
(
m_axis_tvalid
[
n
]),
.
m_axis_tready
(
m_axis_tready
[
n
]),
.
m_axis_tlast
(
m_axis_tlast
[
n
]),
.
m_axis_tid
(
m_axis_tid
[
ID_WIDTH
*
n
+:
ID_WIDTH
]),
.
m_axis_tdest
(
m_axis_tdest
[
DEST_WIDTH
*
n
+:
DEST_WIDTH
]),
.
m_axis_tuser
(
m_axis_tuser
[
USER_WIDTH
*
n
+:
USER_WIDTH
])
);
end
// m_ifaces
endgenerate
endmodule
corundum/lib/eth/lib/axis/rtl/axis_rate_limit.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 rate limiter
*/
module
axis_rate_limit
#
(
// 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
)
(
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
,
/*
* Configuration
*/
input
wire
[
7
:
0
]
rate_num
,
input
wire
[
7
:
0
]
rate_denom
,
input
wire
rate_by_frame
);
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_int
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_int
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
reg
[
23
:
0
]
acc_reg
=
24'd0
,
acc_next
;
reg
pause
;
reg
frame_reg
=
1'b0
,
frame_next
;
reg
s_axis_tready_reg
=
1'b0
,
s_axis_tready_next
;
assign
s_axis_tready
=
s_axis_tready_reg
;
always
@*
begin
acc_next
=
acc_reg
;
pause
=
1'b0
;
frame_next
=
frame_reg
;
if
(
acc_reg
>=
rate_num
)
begin
acc_next
=
acc_reg
-
rate_num
;
end
if
(
s_axis_tready
&&
s_axis_tvalid
)
begin
// read input
frame_next
=
!
s_axis_tlast
;
acc_next
=
acc_reg
+
(
rate_denom
-
rate_num
);
end
if
(
acc_next
>=
rate_num
)
begin
if
(
LAST_ENABLE
&&
rate_by_frame
)
begin
pause
=
!
frame_next
;
end
else
begin
pause
=
1'b1
;
end
end
s_axis_tready_next
=
m_axis_tready_int_early
&&
!
pause
;
m_axis_tdata_int
=
s_axis_tdata
;
m_axis_tkeep_int
=
s_axis_tkeep
;
m_axis_tvalid_int
=
s_axis_tvalid
&&
s_axis_tready
;
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
acc_reg
<=
24'd0
;
frame_reg
<=
1'b0
;
s_axis_tready_reg
<=
1'b0
;
end
else
begin
acc_reg
<=
acc_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_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
=
LAST_ENABLE
?
m_axis_tlast_reg
:
1'b1
;
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_register.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 register
*/
module
axis_register
#
(
// 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
,
// Register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
REG_TYPE
=
2
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI Stream input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata
,
input
wire
[
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep
,
input
wire
s_axis_tvalid
,
output
wire
s_axis_tready
,
input
wire
s_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser
,
/*
* AXI Stream output
*/
output
wire
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata
,
output
wire
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep
,
output
wire
m_axis_tvalid
,
input
wire
m_axis_tready
,
output
wire
m_axis_tlast
,
output
wire
[
ID_WIDTH
-
1
:
0
]
m_axis_tid
,
output
wire
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest
,
output
wire
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser
);
generate
if
(
REG_TYPE
>
1
)
begin
// skid buffer, no bubble cycles
// datapath registers
reg
s_axis_tready_reg
=
1'b0
;
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_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_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
=
LAST_ENABLE
?
m_axis_tlast_reg
:
1'b1
;
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)
wire
s_axis_tready_early
=
m_axis_tready
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid_reg
||
!
s_axis_tvalid
));
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_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_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
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
)
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
s_axis_tready_reg
<=
1'b0
;
m_axis_tvalid_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
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
end
else
if
(
REG_TYPE
==
1
)
begin
// simple register, inserts bubble cycles
// datapath registers
reg
s_axis_tready_reg
=
1'b0
;
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
}}
;
// datapath control
reg
store_axis_input_to_output
;
assign
s_axis_tready
=
s_axis_tready_reg
;
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
=
LAST_ENABLE
?
m_axis_tlast_reg
:
1'b1
;
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 buffer will be empty
wire
s_axis_tready_early
=
!
m_axis_tvalid_next
;
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
store_axis_input_to_output
=
1'b0
;
if
(
s_axis_tready_reg
)
begin
m_axis_tvalid_next
=
s_axis_tvalid
;
store_axis_input_to_output
=
1'b1
;
end
else
if
(
m_axis_tready
)
begin
m_axis_tvalid_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
s_axis_tready_reg
<=
1'b0
;
m_axis_tvalid_reg
<=
1'b0
;
end
else
begin
s_axis_tready_reg
<=
s_axis_tready_early
;
m_axis_tvalid_reg
<=
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
end
end
else
begin
// bypass
assign
m_axis_tdata
=
s_axis_tdata
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
s_axis_tkeep
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
s_axis_tvalid
;
assign
m_axis_tlast
=
LAST_ENABLE
?
s_axis_tlast
:
1'b1
;
assign
m_axis_tid
=
ID_ENABLE
?
s_axis_tid
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
s_axis_tdest
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
s_axis_tuser
:
{
USER_WIDTH
{
1'b0
}}
;
assign
s_axis_tready
=
m_axis_tready
;
end
endgenerate
endmodule
corundum/lib/eth/lib/axis/rtl/axis_srl_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 SRL-based FIFO
*/
module
axis_srl_fifo
#
(
// 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
,
// FIFO depth in cycles
parameter
DEPTH
=
16
)
(
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
[$
clog2
(
DEPTH
+
1
)
-
1
:
0
]
count
);
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
[
WIDTH
-
1
:
0
]
data_reg
[
DEPTH
-
1
:
0
];
reg
[$
clog2
(
DEPTH
+
1
)
-
1
:
0
]
ptr_reg
=
0
;
reg
full_reg
=
1'b0
,
full_next
;
reg
empty_reg
=
1'b1
,
empty_next
;
wire
[
WIDTH
-
1
:
0
]
s_axis
;
wire
[
WIDTH
-
1
:
0
]
m_axis
=
data_reg
[
ptr_reg
-
1
];
assign
s_axis_tready
=
!
full_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
=
!
empty_reg
;
assign
m_axis_tdata
=
m_axis
[
DATA_WIDTH
-
1
:
0
];
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tlast
=
LAST_ENABLE
?
m_axis
[
LAST_OFFSET
]
:
1'b1
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis
[
ID_OFFSET
+:
ID_WIDTH
]
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis
[
DEST_OFFSET
+:
DEST_WIDTH
]
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis
[
USER_OFFSET
+:
USER_WIDTH
]
:
{
USER_WIDTH
{
1'b0
}}
;
assign
count
=
ptr_reg
;
wire
ptr_empty
=
ptr_reg
==
0
;
wire
ptr_empty1
=
ptr_reg
==
1
;
wire
ptr_full
=
ptr_reg
==
DEPTH
;
wire
ptr_full1
=
ptr_reg
==
DEPTH
-
1
;
reg
shift
;
reg
inc
;
reg
dec
;
integer
i
;
initial
begin
for
(
i
=
0
;
i
<
DEPTH
;
i
=
i
+
1
)
begin
data_reg
[
i
]
<=
0
;
end
end
always
@*
begin
shift
=
1'b0
;
inc
=
1'b0
;
dec
=
1'b0
;
full_next
=
full_reg
;
empty_next
=
empty_reg
;
if
(
m_axis_tready
&&
s_axis_tvalid
&&
s_axis_tready
)
begin
shift
=
1'b1
;
inc
=
ptr_empty
;
empty_next
=
1'b0
;
end
else
if
(
m_axis_tready
&&
m_axis_tvalid
)
begin
dec
=
1'b1
;
full_next
=
1'b0
;
empty_next
=
ptr_empty1
;
end
else
if
(
s_axis_tvalid
&&
s_axis_tready
)
begin
shift
=
1'b1
;
inc
=
1'b1
;
full_next
=
ptr_full1
;
empty_next
=
1'b0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
ptr_reg
<=
0
;
full_reg
<=
1'b0
;
empty_reg
<=
1'b1
;
end
else
begin
if
(
inc
)
begin
ptr_reg
<=
ptr_reg
+
1
;
end
else
if
(
dec
)
begin
ptr_reg
<=
ptr_reg
-
1
;
end
else
begin
ptr_reg
<=
ptr_reg
;
end
full_reg
<=
full_next
;
empty_reg
<=
empty_next
;
end
if
(
shift
)
begin
data_reg
[
0
]
<=
s_axis
;
for
(
i
=
0
;
i
<
DEPTH
-
1
;
i
=
i
+
1
)
begin
data_reg
[
i
+
1
]
<=
data_reg
[
i
];
end
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_srl_register.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 SRL-based FIFO register
*/
module
axis_srl_register
#
(
// 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 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
);
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
[
WIDTH
-
1
:
0
]
data_reg
[
1
:
0
];
reg
valid_reg
[
1
:
0
];
reg
ptr_reg
=
0
;
reg
full_reg
=
0
;
wire
[
WIDTH
-
1
:
0
]
s_axis
;
wire
[
WIDTH
-
1
:
0
]
m_axis
=
data_reg
[
ptr_reg
];
assign
s_axis_tready
=
!
full_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
=
valid_reg
[
ptr_reg
];
assign
m_axis_tdata
=
m_axis
[
DATA_WIDTH
-
1
:
0
];
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis
[
KEEP_OFFSET
+:
KEEP_WIDTH
]
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tlast
=
LAST_ENABLE
?
m_axis
[
LAST_OFFSET
]
:
1'b1
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis
[
ID_OFFSET
+:
ID_WIDTH
]
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis
[
DEST_OFFSET
+:
DEST_WIDTH
]
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis
[
USER_OFFSET
+:
USER_WIDTH
]
:
{
USER_WIDTH
{
1'b0
}}
;
integer
i
;
initial
begin
for
(
i
=
0
;
i
<
2
;
i
=
i
+
1
)
begin
data_reg
[
i
]
<=
0
;
valid_reg
[
i
]
<=
0
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
ptr_reg
<=
0
;
full_reg
<=
0
;
end
else
begin
// transfer empty to full
full_reg
<=
!
m_axis_tready
&&
m_axis_tvalid
;
// transfer in if not full
if
(
s_axis_tready
)
begin
data_reg
[
0
]
<=
s_axis
;
valid_reg
[
0
]
<=
s_axis_tvalid
;
for
(
i
=
0
;
i
<
1
;
i
=
i
+
1
)
begin
data_reg
[
i
+
1
]
<=
data_reg
[
i
];
valid_reg
[
i
+
1
]
<=
valid_reg
[
i
];
end
ptr_reg
<=
valid_reg
[
0
];
end
if
(
m_axis_tready
)
begin
ptr_reg
<=
0
;
end
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_stat_counter.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 statistics counter
*/
module
axis_stat_counter
#
(
// Width of AXI stream interfaces in bits
parameter
DATA_WIDTH
=
64
,
// 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
),
// Prepend data with tag
parameter
TAG_ENABLE
=
1
,
// Tag field width
parameter
TAG_WIDTH
=
16
,
// Count cycles
parameter
TICK_COUNT_ENABLE
=
1
,
// Cycle counter width
parameter
TICK_COUNT_WIDTH
=
32
,
// Count bytes
parameter
BYTE_COUNT_ENABLE
=
1
,
// Byte counter width
parameter
BYTE_COUNT_WIDTH
=
32
,
// Count frames
parameter
FRAME_COUNT_ENABLE
=
1
,
// Frame counter width
parameter
FRAME_COUNT_WIDTH
=
32
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI monitor
*/
input
wire
[
KEEP_WIDTH
-
1
:
0
]
monitor_axis_tkeep
,
input
wire
monitor_axis_tvalid
,
input
wire
monitor_axis_tready
,
input
wire
monitor_axis_tlast
,
/*
* AXI status data 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
,
/*
* Configuration
*/
input
wire
[
TAG_WIDTH
-
1
:
0
]
tag
,
input
wire
trigger
,
/*
* Status
*/
output
wire
busy
);
localparam
TAG_BYTE_WIDTH
=
(
TAG_WIDTH
+
7
)
/
8
;
localparam
TICK_COUNT_BYTE_WIDTH
=
(
TICK_COUNT_WIDTH
+
7
)
/
8
;
localparam
BYTE_COUNT_BYTE_WIDTH
=
(
BYTE_COUNT_WIDTH
+
7
)
/
8
;
localparam
FRAME_COUNT_BYTE_WIDTH
=
(
FRAME_COUNT_WIDTH
+
7
)
/
8
;
localparam
TOTAL_LENGTH
=
TAG_BYTE_WIDTH
+
TICK_COUNT_BYTE_WIDTH
+
BYTE_COUNT_BYTE_WIDTH
+
FRAME_COUNT_BYTE_WIDTH
;
// state register
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_OUTPUT_DATA
=
2'd1
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
[
TICK_COUNT_WIDTH
-
1
:
0
]
tick_count_reg
=
0
,
tick_count_next
;
reg
[
BYTE_COUNT_WIDTH
-
1
:
0
]
byte_count_reg
=
0
,
byte_count_next
;
reg
[
FRAME_COUNT_WIDTH
-
1
:
0
]
frame_count_reg
=
0
,
frame_count_next
;
reg
frame_reg
=
1'b0
,
frame_next
;
reg
store_output
;
reg
[$
clog2
(
TOTAL_LENGTH
)
-
1
:
0
]
frame_ptr_reg
=
0
,
frame_ptr_next
;
reg
[
TICK_COUNT_WIDTH
-
1
:
0
]
tick_count_output_reg
=
0
;
reg
[
BYTE_COUNT_WIDTH
-
1
:
0
]
byte_count_output_reg
=
0
;
reg
[
FRAME_COUNT_WIDTH
-
1
:
0
]
frame_count_output_reg
=
0
;
reg
busy_reg
=
1'b0
;
// internal datapath
reg
[
7
:
0
]
m_axis_tdata_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
m_axis_tuser_int
;
wire
m_axis_tready_int_early
;
assign
busy
=
busy_reg
;
integer
offset
,
i
,
bit_cnt
;
always
@*
begin
state_next
=
STATE_IDLE
;
tick_count_next
=
tick_count_reg
;
byte_count_next
=
byte_count_reg
;
frame_count_next
=
frame_count_reg
;
frame_next
=
frame_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
;
store_output
=
1'b0
;
frame_ptr_next
=
frame_ptr_reg
;
// data readout
case
(
state_reg
)
STATE_IDLE:
begin
if
(
trigger
)
begin
store_output
=
1'b1
;
tick_count_next
=
0
;
byte_count_next
=
0
;
frame_count_next
=
0
;
frame_ptr_next
=
0
;
if
(
m_axis_tready_int_reg
)
begin
frame_ptr_next
=
1
;
if
(
TAG_ENABLE
)
begin
m_axis_tdata_int
=
tag
[(
TAG_BYTE_WIDTH
-
1
)
*
8
+:
8
];
end
else
if
(
TICK_COUNT_ENABLE
)
begin
m_axis_tdata_int
=
tick_count_reg
[(
TICK_COUNT_BYTE_WIDTH
-
1
)
*
8
+:
8
];
end
else
if
(
BYTE_COUNT_ENABLE
)
begin
m_axis_tdata_int
=
byte_count_reg
[(
BYTE_COUNT_BYTE_WIDTH
-
1
)
*
8
+:
8
];
end
else
if
(
FRAME_COUNT_ENABLE
)
begin
m_axis_tdata_int
=
frame_count_reg
[(
FRAME_COUNT_BYTE_WIDTH
-
1
)
*
8
+:
8
];
end
m_axis_tvalid_int
=
1'b1
;
end
state_next
=
STATE_OUTPUT_DATA
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_OUTPUT_DATA:
begin
if
(
m_axis_tready_int_reg
)
begin
state_next
=
STATE_OUTPUT_DATA
;
frame_ptr_next
=
frame_ptr_reg
+
1
;
m_axis_tvalid_int
=
1'b1
;
offset
=
0
;
if
(
TAG_ENABLE
)
begin
for
(
i
=
TAG_BYTE_WIDTH
-
1
;
i
>=
0
;
i
=
i
-
1
)
begin
if
(
frame_ptr_reg
==
offset
)
begin
m_axis_tdata_int
=
tag
[
i
*
8
+:
8
];
end
offset
=
offset
+
1
;
end
end
if
(
TICK_COUNT_ENABLE
)
begin
for
(
i
=
TICK_COUNT_BYTE_WIDTH
-
1
;
i
>=
0
;
i
=
i
-
1
)
begin
if
(
frame_ptr_reg
==
offset
)
begin
m_axis_tdata_int
=
tick_count_output_reg
[
i
*
8
+:
8
];
end
offset
=
offset
+
1
;
end
end
if
(
BYTE_COUNT_ENABLE
)
begin
for
(
i
=
BYTE_COUNT_BYTE_WIDTH
-
1
;
i
>=
0
;
i
=
i
-
1
)
begin
if
(
frame_ptr_reg
==
offset
)
begin
m_axis_tdata_int
=
byte_count_output_reg
[
i
*
8
+:
8
];
end
offset
=
offset
+
1
;
end
end
if
(
FRAME_COUNT_ENABLE
)
begin
for
(
i
=
FRAME_COUNT_BYTE_WIDTH
-
1
;
i
>=
0
;
i
=
i
-
1
)
begin
if
(
frame_ptr_reg
==
offset
)
begin
m_axis_tdata_int
=
frame_count_output_reg
[
i
*
8
+:
8
];
end
offset
=
offset
+
1
;
end
end
if
(
frame_ptr_reg
==
offset
-
1
)
begin
m_axis_tlast_int
=
1'b1
;
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_OUTPUT_DATA
;
end
end
endcase
// stats collection
// increment tick count by number of words that can be transferred per cycle
tick_count_next
=
tick_count_next
+
(
KEEP_ENABLE
?
KEEP_WIDTH
:
1
);
if
(
monitor_axis_tready
&&
monitor_axis_tvalid
)
begin
// valid transfer cycle
// increment byte count by number of words transferred
if
(
KEEP_ENABLE
)
begin
bit_cnt
=
0
;
for
(
i
=
0
;
i
<=
KEEP_WIDTH
;
i
=
i
+
1
)
begin
//bit_cnt = bit_cnt + monitor_axis_tkeep[i];
if
(
monitor_axis_tkeep
==
(
{
KEEP_WIDTH
{
1'b1
}}
)
>>
(
KEEP_WIDTH
-
i
))
bit_cnt
=
i
;
end
byte_count_next
=
byte_count_next
+
bit_cnt
;
end
else
begin
byte_count_next
=
byte_count_next
+
1
;
end
// count frames
if
(
monitor_axis_tlast
)
begin
// end of frame
frame_next
=
1'b0
;
end
else
if
(
!
frame_reg
)
begin
// first word after end of frame
frame_count_next
=
frame_count_next
+
1
;
frame_next
=
1'b1
;
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
tick_count_reg
<=
0
;
byte_count_reg
<=
0
;
frame_count_reg
<=
0
;
frame_reg
<=
1'b0
;
frame_ptr_reg
<=
0
;
busy_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
tick_count_reg
<=
tick_count_next
;
byte_count_reg
<=
byte_count_next
;
frame_count_reg
<=
frame_count_next
;
frame_reg
<=
frame_next
;
frame_ptr_reg
<=
frame_ptr_next
;
busy_reg
<=
state_next
!=
STATE_IDLE
;
end
if
(
store_output
)
begin
tick_count_output_reg
<=
tick_count_reg
;
byte_count_output_reg
<=
byte_count_reg
;
frame_count_output_reg
<=
frame_count_reg
;
end
end
// output datapath logic
reg
[
7
:
0
]
m_axis_tdata_reg
=
8'd0
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
m_axis_tuser_reg
=
1'b0
;
reg
[
7
:
0
]
temp_m_axis_tdata_reg
=
8'd0
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
temp_m_axis_tuser_reg
=
1'b0
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
m_axis_tlast_reg
;
assign
m_axis_tuser
=
m_axis_tuser_reg
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_tready_int_early
=
m_axis_tready
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid_reg
||
!
m_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
// input is ready
if
(
m_axis_tready
||
!
m_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_tready
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
m_axis_tvalid_reg
<=
1'b0
;
m_axis_tready_int_reg
<=
1'b0
;
temp_m_axis_tvalid_reg
<=
1'b0
;
end
else
begin
m_axis_tvalid_reg
<=
m_axis_tvalid_next
;
m_axis_tready_int_reg
<=
m_axis_tready_int_early
;
temp_m_axis_tvalid_reg
<=
temp_m_axis_tvalid_next
;
end
// datapath
if
(
store_axis_int_to_output
)
begin
m_axis_tdata_reg
<=
m_axis_tdata_int
;
m_axis_tlast_reg
<=
m_axis_tlast_int
;
m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
else
if
(
store_axis_temp_to_output
)
begin
m_axis_tdata_reg
<=
temp_m_axis_tdata_reg
;
m_axis_tlast_reg
<=
temp_m_axis_tlast_reg
;
m_axis_tuser_reg
<=
temp_m_axis_tuser_reg
;
end
if
(
store_axis_int_to_temp
)
begin
temp_m_axis_tdata_reg
<=
m_axis_tdata_int
;
temp_m_axis_tlast_reg
<=
m_axis_tlast_int
;
temp_m_axis_tuser_reg
<=
m_axis_tuser_int
;
end
end
endmodule
corundum/lib/eth/lib/axis/rtl/axis_switch.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 switch
*/
module
axis_switch
#
(
// 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 tid signal
parameter
ID_ENABLE
=
0
,
// tid signal width
parameter
ID_WIDTH
=
8
,
// tdest signal width
// must be wide enough to uniquely address outputs
parameter
DEST_WIDTH
=
$
clog2
(
M_COUNT
),
// Propagate tuser signal
parameter
USER_ENABLE
=
1
,
// tuser signal width
parameter
USER_WIDTH
=
1
,
// Output interface routing base tdest selection
// Concatenate M_COUNT DEST_WIDTH sized constants
// Port selected if M_BASE <= tdest <= M_TOP
// set to zero for default routing with tdest MSBs as port index
parameter
M_BASE
=
0
,
// Output interface routing top tdest selection
// Concatenate M_COUNT DEST_WIDTH sized constants
// Port selected if M_BASE <= tdest <= M_TOP
// set to zero to inherit from M_BASE
parameter
M_TOP
=
0
,
// Interface connection control
// M_COUNT concatenated fields of S_COUNT bits
parameter
M_CONNECT
=
{
M_COUNT
{{
S_COUNT
{
1'b1
}}}}
,
// Input interface register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
S_REG_TYPE
=
0
,
// Output interface register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter
M_REG_TYPE
=
2
,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter
ARB_TYPE
=
"ROUND_ROBIN"
,
// 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 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_S_COUNT
=
$
clog2
(
S_COUNT
);
parameter
CL_M_COUNT
=
$
clog2
(
M_COUNT
);
integer
i
,
j
;
// check configuration
initial
begin
if
(
DEST_WIDTH
<
CL_M_COUNT
)
begin
$
error
(
"Error: DEST_WIDTH too small for port count (instance %m)"
);
$
finish
;
end
if
(
M_BASE
==
0
)
begin
// M_BASE is zero, route with tdest as port index
end
else
if
(
M_TOP
==
0
)
begin
// M_TOP is zero, assume equal to M_BASE
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
for
(
j
=
i
+
1
;
j
<
M_COUNT
;
j
=
j
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
==
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
display
(
"%d: %08x"
,
i
,
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
display
(
"%d: %08x"
,
j
,
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
error
(
"Error: ranges overlap (instance %m)"
);
$
finish
;
end
end
end
end
else
begin
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
>
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
error
(
"Error: invalid range (instance %m)"
);
$
finish
;
end
end
for
(
i
=
0
;
i
<
M_COUNT
;
i
=
i
+
1
)
begin
for
(
j
=
i
+
1
;
j
<
M_COUNT
;
j
=
j
+
1
)
begin
if
(
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
M_TOP
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
])
begin
$
display
(
"%d: %08x-%08x"
,
i
,
M_BASE
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
],
M_TOP
[
i
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
display
(
"%d: %08x-%08x"
,
j
,
M_BASE
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
],
M_TOP
[
j
*
DEST_WIDTH
+:
DEST_WIDTH
]);
$
error
(
"Error: ranges overlap (instance %m)"
);
$
finish
;
end
end
end
end
end
wire
[
S_COUNT
*
DATA_WIDTH
-
1
:
0
]
int_s_axis_tdata
;
wire
[
S_COUNT
*
KEEP_WIDTH
-
1
:
0
]
int_s_axis_tkeep
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axis_tvalid
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axis_tready
;
wire
[
S_COUNT
-
1
:
0
]
int_s_axis_tlast
;
wire
[
S_COUNT
*
ID_WIDTH
-
1
:
0
]
int_s_axis_tid
;
wire
[
S_COUNT
*
DEST_WIDTH
-
1
:
0
]
int_s_axis_tdest
;
wire
[
S_COUNT
*
USER_WIDTH
-
1
:
0
]
int_s_axis_tuser
;
wire
[
S_COUNT
*
M_COUNT
-
1
:
0
]
int_axis_tvalid
;
wire
[
M_COUNT
*
S_COUNT
-
1
:
0
]
int_axis_tready
;
generate
genvar
m
,
n
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
:
s_ifaces
// decoding
reg
[
CL_M_COUNT
-
1
:
0
]
select_reg
=
0
,
select_next
;
reg
drop_reg
=
1'b0
,
drop_next
;
reg
select_valid_reg
=
1'b0
,
select_valid_next
;
integer
k
;
always
@*
begin
select_next
=
select_reg
;
drop_next
=
drop_reg
&&
!
(
int_s_axis_tvalid
[
m
]
&&
int_s_axis_tready
[
m
]
&&
int_s_axis_tlast
[
m
]);
select_valid_next
=
select_valid_reg
&&
!
(
int_s_axis_tvalid
[
m
]
&&
int_s_axis_tready
[
m
]
&&
int_s_axis_tlast
[
m
]);
if
(
int_s_axis_tvalid
[
m
]
&&
!
select_valid_reg
)
begin
select_next
=
1'b0
;
select_valid_next
=
1'b0
;
drop_next
=
1'b1
;
for
(
k
=
0
;
k
<
M_COUNT
;
k
=
k
+
1
)
begin
if
(
M_BASE
==
0
)
begin
// M_BASE is zero, route with $clog2(M_COUNT) MSBs of tdest as port index
if
(
int_s_axis_tdest
[
m
*
DEST_WIDTH
+
(
DEST_WIDTH
-
CL_M_COUNT
)
+:
CL_M_COUNT
]
==
k
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
else
if
(
M_TOP
==
0
)
begin
// M_TOP is zero, assume equal to M_BASE
if
(
int_s_axis_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]
==
M_BASE
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
else
begin
if
(
int_s_axis_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]
>=
M_BASE
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
int_s_axis_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]
<=
M_TOP
[
k
*
DEST_WIDTH
+:
DEST_WIDTH
]
&&
(
M_CONNECT
&
(
1
<<
(
m
+
k
*
S_COUNT
))))
begin
select_next
=
k
;
select_valid_next
=
1'b1
;
drop_next
=
1'b0
;
end
end
end
end
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
select_valid_reg
<=
1'b0
;
end
else
begin
select_valid_reg
<=
select_valid_next
;
end
select_reg
<=
select_next
;
drop_reg
<=
drop_next
;
end
// forwarding
assign
int_axis_tvalid
[
m
*
M_COUNT
+:
M_COUNT
]
=
(
int_s_axis_tvalid
[
m
]
&&
select_valid_reg
&&
!
drop_reg
)
<<
select_reg
;
assign
int_s_axis_tready
[
m
]
=
int_axis_tready
[
select_reg
*
S_COUNT
+
m
]
||
drop_reg
;
// S side register
axis_register
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
1
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
),
.
REG_TYPE
(
S_REG_TYPE
)
)
reg_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
s_axis_tdata
[
m
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
s_axis_tkeep
(
s_axis_tkeep
[
m
*
KEEP_WIDTH
+:
KEEP_WIDTH
]),
.
s_axis_tvalid
(
s_axis_tvalid
[
m
]),
.
s_axis_tready
(
s_axis_tready
[
m
]),
.
s_axis_tlast
(
s_axis_tlast
[
m
]),
.
s_axis_tid
(
s_axis_tid
[
m
*
ID_WIDTH
+:
ID_WIDTH
]),
.
s_axis_tdest
(
s_axis_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]),
.
s_axis_tuser
(
s_axis_tuser
[
m
*
USER_WIDTH
+:
USER_WIDTH
]),
// AXI output
.
m_axis_tdata
(
int_s_axis_tdata
[
m
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
m_axis_tkeep
(
int_s_axis_tkeep
[
m
*
KEEP_WIDTH
+:
KEEP_WIDTH
]),
.
m_axis_tvalid
(
int_s_axis_tvalid
[
m
]),
.
m_axis_tready
(
int_s_axis_tready
[
m
]),
.
m_axis_tlast
(
int_s_axis_tlast
[
m
]),
.
m_axis_tid
(
int_s_axis_tid
[
m
*
ID_WIDTH
+:
ID_WIDTH
]),
.
m_axis_tdest
(
int_s_axis_tdest
[
m
*
DEST_WIDTH
+:
DEST_WIDTH
]),
.
m_axis_tuser
(
int_s_axis_tuser
[
m
*
USER_WIDTH
+:
USER_WIDTH
])
);
end
// s_ifaces
for
(
n
=
0
;
n
<
M_COUNT
;
n
=
n
+
1
)
begin
:
m_ifaces
// arbitration
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
;
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
)
);
// mux
wire
[
DATA_WIDTH
-
1
:
0
]
s_axis_tdata_mux
=
int_s_axis_tdata
[
grant_encoded
*
DATA_WIDTH
+:
DATA_WIDTH
];
wire
[
KEEP_WIDTH
-
1
:
0
]
s_axis_tkeep_mux
=
int_s_axis_tkeep
[
grant_encoded
*
KEEP_WIDTH
+:
KEEP_WIDTH
];
wire
s_axis_tvalid_mux
=
int_axis_tvalid
[
grant_encoded
*
M_COUNT
+
n
]
&&
grant_valid
;
wire
s_axis_tready_mux
;
wire
s_axis_tlast_mux
=
int_s_axis_tlast
[
grant_encoded
];
wire
[
ID_WIDTH
-
1
:
0
]
s_axis_tid_mux
=
int_s_axis_tid
[
grant_encoded
*
ID_WIDTH
+:
ID_WIDTH
];
wire
[
DEST_WIDTH
-
1
:
0
]
s_axis_tdest_mux
=
int_s_axis_tdest
[
grant_encoded
*
DEST_WIDTH
+:
DEST_WIDTH
];
wire
[
USER_WIDTH
-
1
:
0
]
s_axis_tuser_mux
=
int_s_axis_tuser
[
grant_encoded
*
USER_WIDTH
+:
USER_WIDTH
];
assign
int_axis_tready
[
n
*
S_COUNT
+:
S_COUNT
]
=
(
grant_valid
&&
s_axis_tready_mux
)
<<
grant_encoded
;
for
(
m
=
0
;
m
<
S_COUNT
;
m
=
m
+
1
)
begin
assign
request
[
m
]
=
int_axis_tvalid
[
m
*
M_COUNT
+
n
]
&&
!
grant
[
m
];
assign
acknowledge
[
m
]
=
grant
[
m
]
&&
int_axis_tvalid
[
m
*
M_COUNT
+
n
]
&&
s_axis_tlast_mux
&&
s_axis_tready_mux
;
end
// M side register
axis_register
#(
.
DATA_WIDTH
(
DATA_WIDTH
),
.
KEEP_ENABLE
(
KEEP_ENABLE
),
.
KEEP_WIDTH
(
KEEP_WIDTH
),
.
LAST_ENABLE
(
1
),
.
ID_ENABLE
(
ID_ENABLE
),
.
ID_WIDTH
(
ID_WIDTH
),
.
DEST_ENABLE
(
1
),
.
DEST_WIDTH
(
DEST_WIDTH
),
.
USER_ENABLE
(
USER_ENABLE
),
.
USER_WIDTH
(
USER_WIDTH
),
.
REG_TYPE
(
M_REG_TYPE
)
)
reg_inst
(
.
clk
(
clk
),
.
rst
(
rst
),
// AXI input
.
s_axis_tdata
(
s_axis_tdata_mux
),
.
s_axis_tkeep
(
s_axis_tkeep_mux
),
.
s_axis_tvalid
(
s_axis_tvalid_mux
),
.
s_axis_tready
(
s_axis_tready_mux
),
.
s_axis_tlast
(
s_axis_tlast_mux
),
.
s_axis_tid
(
s_axis_tid_mux
),
.
s_axis_tdest
(
s_axis_tdest_mux
),
.
s_axis_tuser
(
s_axis_tuser_mux
),
// AXI output
.
m_axis_tdata
(
m_axis_tdata
[
n
*
DATA_WIDTH
+:
DATA_WIDTH
]),
.
m_axis_tkeep
(
m_axis_tkeep
[
n
*
KEEP_WIDTH
+:
KEEP_WIDTH
]),
.
m_axis_tvalid
(
m_axis_tvalid
[
n
]),
.
m_axis_tready
(
m_axis_tready
[
n
]),
.
m_axis_tlast
(
m_axis_tlast
[
n
]),
.
m_axis_tid
(
m_axis_tid
[
n
*
ID_WIDTH
+:
ID_WIDTH
]),
.
m_axis_tdest
(
m_axis_tdest
[
n
*
DEST_WIDTH
+:
DEST_WIDTH
]),
.
m_axis_tuser
(
m_axis_tuser
[
n
*
USER_WIDTH
+:
USER_WIDTH
])
);
end
// m_ifaces
endgenerate
endmodule
corundum/lib/eth/lib/axis/rtl/axis_switch_wrap.py
0 → 100755
View file @
738c1fef
#!/usr/bin/env python
"""
Generates an AXI Stream switch 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_switch_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 switch 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}} switch (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,
// tdest signal width
// must be wide enough to uniquely address outputs
parameter DEST_WIDTH = {{cm}},
// Propagate tuser signal
parameter USER_ENABLE = 1,
// tuser signal width
parameter USER_WIDTH = 1,
{%- for p in range(n) %}
// Output interface routing base tdest selection
// Port selected if M_BASE <= tdest <= M_TOP
parameter M{{'%02d'%p}}_BASE = {{p}},
// Output interface routing top tdest selection
// Port selected if M_BASE <= tdest <= M_TOP
parameter M{{'%02d'%p}}_TOP = {{p}},
// Interface connection control
parameter M{{'%02d'%p}}_CONNECT = {{m}}'b{% for p in range(m) %}1{% endfor %},
{%- endfor %}
// Input interface register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter S_REG_TYPE = 0,
// Output interface register type
// 0 to bypass, 1 for simple buffer, 2 for skid buffer
parameter M_REG_TYPE = 2,
// arbitration type: "PRIORITY" or "ROUND_ROBIN"
parameter ARB_TYPE = "ROUND_ROBIN",
// LSB priority: "LOW", "HIGH"
parameter LSB_PRIORITY = "HIGH"
)
(
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,
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 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{% if not loop.last %},{% endif %}
{% endfor -%}
);
// parameter sizing helpers
function [31:0] w_32(input [31:0] val);
w_32 = val;
endfunction
function [S_COUNT-1:0] w_s(input [S_COUNT-1:0] val);
w_s = val;
endfunction
axis_switch #(
.S_COUNT({{m}}),
.M_COUNT({{n}}),
.DATA_WIDTH(DATA_WIDTH),
.KEEP_ENABLE(KEEP_ENABLE),
.KEEP_WIDTH(KEEP_WIDTH),
.ID_ENABLE(ID_ENABLE),
.ID_WIDTH(ID_WIDTH),
.DEST_WIDTH(DEST_WIDTH),
.USER_ENABLE(USER_ENABLE),
.USER_WIDTH(USER_WIDTH),
.M_BASE({ {% for p in range(n-1,-1,-1) %}w_32(M{{'%02d'%p}}_BASE){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_TOP({ {% for p in range(n-1,-1,-1) %}w_32(M{{'%02d'%p}}_TOP){% if not loop.last %}, {% endif %}{% endfor %} }),
.M_CONNECT({ {% for p in range(n-1,-1,-1) %}w_s(M{{'%02d'%p}}_CONNECT){% if not loop.last %}, {% endif %}{% endfor %} }),
.S_REG_TYPE(S_REG_TYPE),
.M_REG_TYPE(M_REG_TYPE),
.ARB_TYPE(ARB_TYPE),
.LSB_PRIORITY(LSB_PRIORITY)
)
axis_switch_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_tready({ {% for p in range(m-1,-1,-1) %}s{{'%02d'%p}}_axis_tready{% 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 outputs
.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 %} })
);
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_tap.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2015-2018 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog 2001
`timescale
1
ns
/
1
ps
/*
* AXI4-Stream tap
*/
module
axis_tap
#
(
// 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
,
// 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
)
(
input
wire
clk
,
input
wire
rst
,
/*
* AXI tap
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
tap_axis_tdata
,
input
wire
[
KEEP_WIDTH
-
1
:
0
]
tap_axis_tkeep
,
input
wire
tap_axis_tvalid
,
input
wire
tap_axis_tready
,
input
wire
tap_axis_tlast
,
input
wire
[
ID_WIDTH
-
1
:
0
]
tap_axis_tid
,
input
wire
[
DEST_WIDTH
-
1
:
0
]
tap_axis_tdest
,
input
wire
[
USER_WIDTH
-
1
:
0
]
tap_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
);
// datapath control signals
reg
store_last_word
;
reg
[
ID_WIDTH
-
1
:
0
]
last_word_id_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
last_word_dest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
last_word_user_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// internal datapath
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_int
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_int
;
reg
m_axis_tvalid_int
;
reg
m_axis_tready_int_reg
=
1'b0
;
reg
m_axis_tlast_int
;
reg
[
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
;
localparam
[
1
:
0
]
STATE_IDLE
=
2'd0
,
STATE_TRANSFER
=
2'd1
,
STATE_TRUNCATE
=
2'd2
,
STATE_WAIT
=
2'd3
;
reg
[
1
:
0
]
state_reg
=
STATE_IDLE
,
state_next
;
reg
frame_reg
=
1'b0
,
frame_next
;
always
@*
begin
state_next
=
STATE_IDLE
;
store_last_word
=
1'b0
;
frame_next
=
frame_reg
;
m_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_int
=
{
KEEP_WIDTH
{
1'b0
}}
;
m_axis_tvalid_int
=
1'b0
;
m_axis_tlast_int
=
1'b0
;
m_axis_tid_int
=
{
ID_WIDTH
{
1'b0
}}
;
m_axis_tdest_int
=
{
DEST_WIDTH
{
1'b0
}}
;
m_axis_tuser_int
=
{
USER_WIDTH
{
1'b0
}}
;
if
(
tap_axis_tready
&&
tap_axis_tvalid
)
begin
frame_next
=
!
tap_axis_tlast
;
end
case
(
state_reg
)
STATE_IDLE:
begin
if
(
tap_axis_tready
&&
tap_axis_tvalid
)
begin
// start of frame
if
(
m_axis_tready_int_reg
)
begin
m_axis_tdata_int
=
tap_axis_tdata
;
m_axis_tkeep_int
=
tap_axis_tkeep
;
m_axis_tvalid_int
=
tap_axis_tvalid
&&
tap_axis_tready
;
m_axis_tlast_int
=
tap_axis_tlast
;
m_axis_tid_int
=
tap_axis_tid
;
m_axis_tdest_int
=
tap_axis_tdest
;
m_axis_tuser_int
=
tap_axis_tuser
;
if
(
tap_axis_tlast
)
begin
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
else
begin
state_next
=
STATE_WAIT
;
end
end
else
begin
state_next
=
STATE_IDLE
;
end
end
STATE_TRANSFER:
begin
if
(
tap_axis_tready
&&
tap_axis_tvalid
)
begin
// transfer data
if
(
m_axis_tready_int_reg
)
begin
m_axis_tdata_int
=
tap_axis_tdata
;
m_axis_tkeep_int
=
tap_axis_tkeep
;
m_axis_tvalid_int
=
tap_axis_tvalid
&&
tap_axis_tready
;
m_axis_tlast_int
=
tap_axis_tlast
;
m_axis_tid_int
=
tap_axis_tid
;
m_axis_tdest_int
=
tap_axis_tdest
;
m_axis_tuser_int
=
tap_axis_tuser
;
if
(
tap_axis_tlast
)
begin
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
else
begin
store_last_word
=
1'b1
;
state_next
=
STATE_TRUNCATE
;
end
end
else
begin
state_next
=
STATE_TRANSFER
;
end
end
STATE_TRUNCATE:
begin
if
(
m_axis_tready_int_reg
)
begin
m_axis_tdata_int
=
{
DATA_WIDTH
{
1'b0
}}
;
m_axis_tkeep_int
=
{{
KEEP_WIDTH
-
1
{
1'b0
}}
,
1'b1
}
;
m_axis_tvalid_int
=
1'b1
;
m_axis_tlast_int
=
1'b1
;
m_axis_tid_int
=
last_word_id_reg
;
m_axis_tdest_int
=
last_word_dest_reg
;
m_axis_tuser_int
=
(
last_word_user_reg
&
~
USER_BAD_FRAME_MASK
)
|
(
USER_BAD_FRAME_VALUE
&
USER_BAD_FRAME_MASK
);
if
(
frame_next
)
begin
state_next
=
STATE_WAIT
;
end
else
begin
state_next
=
STATE_IDLE
;
end
end
else
begin
state_next
=
STATE_TRUNCATE
;
end
end
STATE_WAIT:
begin
if
(
tap_axis_tready
&&
tap_axis_tvalid
)
begin
if
(
tap_axis_tlast
)
begin
state_next
=
STATE_IDLE
;
end
else
begin
state_next
=
STATE_WAIT
;
end
end
else
begin
state_next
=
STATE_WAIT
;
end
end
endcase
end
always
@
(
posedge
clk
)
begin
if
(
rst
)
begin
state_reg
<=
STATE_IDLE
;
frame_reg
<=
1'b0
;
end
else
begin
state_reg
<=
state_next
;
frame_reg
<=
frame_next
;
end
if
(
store_last_word
)
begin
last_word_id_reg
<=
tap_axis_tid
;
last_word_dest_reg
<=
tap_axis_tdest
;
last_word_user_reg
<=
tap_axis_tuser
;
end
end
// output datapath logic
reg
[
DATA_WIDTH
-
1
:
0
]
m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
m_axis_tvalid_reg
=
1'b0
,
m_axis_tvalid_next
;
reg
m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
reg
[
DATA_WIDTH
-
1
:
0
]
temp_m_axis_tdata_reg
=
{
DATA_WIDTH
{
1'b0
}}
;
reg
[
KEEP_WIDTH
-
1
:
0
]
temp_m_axis_tkeep_reg
=
{
KEEP_WIDTH
{
1'b0
}}
;
reg
temp_m_axis_tvalid_reg
=
1'b0
,
temp_m_axis_tvalid_next
;
reg
temp_m_axis_tlast_reg
=
1'b0
;
reg
[
ID_WIDTH
-
1
:
0
]
temp_m_axis_tid_reg
=
{
ID_WIDTH
{
1'b0
}}
;
reg
[
DEST_WIDTH
-
1
:
0
]
temp_m_axis_tdest_reg
=
{
DEST_WIDTH
{
1'b0
}}
;
reg
[
USER_WIDTH
-
1
:
0
]
temp_m_axis_tuser_reg
=
{
USER_WIDTH
{
1'b0
}}
;
// datapath control
reg
store_axis_int_to_output
;
reg
store_axis_int_to_temp
;
reg
store_axis_temp_to_output
;
assign
m_axis_tdata
=
m_axis_tdata_reg
;
assign
m_axis_tkeep
=
KEEP_ENABLE
?
m_axis_tkeep_reg
:
{
KEEP_WIDTH
{
1'b1
}}
;
assign
m_axis_tvalid
=
m_axis_tvalid_reg
;
assign
m_axis_tlast
=
m_axis_tlast_reg
;
assign
m_axis_tid
=
ID_ENABLE
?
m_axis_tid_reg
:
{
ID_WIDTH
{
1'b0
}}
;
assign
m_axis_tdest
=
DEST_ENABLE
?
m_axis_tdest_reg
:
{
DEST_WIDTH
{
1'b0
}}
;
assign
m_axis_tuser
=
USER_ENABLE
?
m_axis_tuser_reg
:
{
USER_WIDTH
{
1'b0
}}
;
// enable ready input next cycle if output is ready or the temp reg will not be filled on the next cycle (output reg empty or no input)
assign
m_axis_tready_int_early
=
m_axis_tready
||
(
!
temp_m_axis_tvalid_reg
&&
(
!
m_axis_tvalid_reg
||
!
m_axis_tvalid_int
));
always
@*
begin
// transfer sink ready state to source
m_axis_tvalid_next
=
m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
store_axis_int_to_output
=
1'b0
;
store_axis_int_to_temp
=
1'b0
;
store_axis_temp_to_output
=
1'b0
;
if
(
m_axis_tready_int_reg
)
begin
// input is ready
if
(
m_axis_tready
||
!
m_axis_tvalid_reg
)
begin
// output is ready or currently not valid, transfer data to output
m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_output
=
1'b1
;
end
else
begin
// output is not ready, store input in temp
temp_m_axis_tvalid_next
=
m_axis_tvalid_int
;
store_axis_int_to_temp
=
1'b1
;
end
end
else
if
(
m_axis_tready
)
begin
// input is not ready, but output is ready
m_axis_tvalid_next
=
temp_m_axis_tvalid_reg
;
temp_m_axis_tvalid_next
=
1'b0
;
store_axis_temp_to_output
=
1'b1
;
end
end
always
@
(
posedge
clk
)
begin
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/ll_axis_bridge.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
/*
* LocalLink to AXI4-Stream bridge
*/
module
ll_axis_bridge
#
(
parameter
DATA_WIDTH
=
8
)
(
input
wire
clk
,
input
wire
rst
,
/*
* LocalLink input
*/
input
wire
[
DATA_WIDTH
-
1
:
0
]
ll_data_in
,
input
wire
ll_sof_in_n
,
input
wire
ll_eof_in_n
,
input
wire
ll_src_rdy_in_n
,
output
wire
ll_dst_rdy_out_n
,
/*
* 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
);
assign
m_axis_tdata
=
ll_data_in
;
assign
m_axis_tvalid
=
!
ll_src_rdy_in_n
;
assign
m_axis_tlast
=
!
ll_eof_in_n
;
assign
ll_dst_rdy_out_n
=
!
m_axis_tready
;
endmodule
corundum/lib/eth/lib/axis/rtl/priority_encoder.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
/*
* Priority encoder module
*/
module
priority_encoder
#
(
parameter
WIDTH
=
4
,
// LSB priority: "LOW", "HIGH"
parameter
LSB_PRIORITY
=
"LOW"
)
(
input
wire
[
WIDTH
-
1
:
0
]
input_unencoded
,
output
wire
output_valid
,
output
wire
[$
clog2
(
WIDTH
)
-
1
:
0
]
output_encoded
,
output
wire
[
WIDTH
-
1
:
0
]
output_unencoded
);
// power-of-two width
parameter
W1
=
2
**
$
clog2
(
WIDTH
);
parameter
W2
=
W1
/
2
;
generate
if
(
WIDTH
==
1
)
begin
// one input
assign
output_valid
=
input_unencoded
;
assign
output_encoded
=
0
;
end
else
if
(
WIDTH
==
2
)
begin
// two inputs - just an OR gate
assign
output_valid
=
|
input_unencoded
;
if
(
LSB_PRIORITY
==
"LOW"
)
begin
assign
output_encoded
=
input_unencoded
[
1
];
end
else
begin
assign
output_encoded
=
~
input_unencoded
[
0
];
end
end
else
begin
// more than two inputs - split into two parts and recurse
// also pad input to correct power-of-two width
wire
[$
clog2
(
W2
)
-
1
:
0
]
out1
,
out2
;
wire
valid1
,
valid2
;
priority_encoder
#(
.
WIDTH
(
W2
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
priority_encoder_inst1
(
.
input_unencoded
(
input_unencoded
[
W2
-
1
:
0
]),
.
output_valid
(
valid1
),
.
output_encoded
(
out1
)
);
priority_encoder
#(
.
WIDTH
(
W2
),
.
LSB_PRIORITY
(
LSB_PRIORITY
)
)
priority_encoder_inst2
(
.
input_unencoded
(
{{
W1
-
WIDTH
{
1'b0
}}
,
input_unencoded
[
WIDTH
-
1
:
W2
]
}
),
.
output_valid
(
valid2
),
.
output_encoded
(
out2
)
);
// multiplexer to select part
assign
output_valid
=
valid1
|
valid2
;
if
(
LSB_PRIORITY
==
"LOW"
)
begin
assign
output_encoded
=
valid2
?
{
1'b1
,
out2
}
:
{
1'b0
,
out1
}
;
end
else
begin
assign
output_encoded
=
valid1
?
{
1'b0
,
out1
}
:
{
1'b1
,
out2
}
;
end
end
endgenerate
// unencoded output
assign
output_unencoded
=
1
<<
output_encoded
;
endmodule
corundum/lib/eth/lib/axis/rtl/sync_reset.v
0 → 100644
View file @
738c1fef
/*
Copyright (c) 2014-2020 Alex Forencich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
// Language: Verilog-2001
`timescale
1
ns
/
1
ps
/*
* Synchronizes an active-high asynchronous reset signal to a given clock by
* using a pipeline of N registers.
*/
module
sync_reset
#
(
// depth of synchronizer
parameter
N
=
2
)
(
input
wire
clk
,
input
wire
rst
,
output
wire
out
);
(
*
srl_style
=
"register"
*
)
reg
[
N
-
1
:
0
]
sync_reg
=
{
N
{
1'b1
}}
;
assign
out
=
sync_reg
[
N
-
1
];
always
@
(
posedge
clk
or
posedge
rst
)
begin
if
(
rst
)
begin
sync_reg
<=
{
N
{
1'b1
}}
;
end
else
begin
sync_reg
<=
{
sync_reg
[
N
-
2
:
0
],
1'b0
}
;
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