Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
H
HDL
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Jira
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
RTSD
HDL
Commits
f8da1e48
Commit
f8da1e48
authored
4 years ago
by
Reinier van der Walle
Browse files
Options
Downloads
Patches
Plain Diff
Initial commit of sdp_beamformer_output.vhd
parent
b409a565
No related branches found
No related tags found
2 merge requests
!100
Removed text for XSub that is now written in Confluence Subband correlator...
,
!56
Resolve L2SDP-169
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
applications/lofar2/libraries/sdp/hdllib.cfg
+2
-1
2 additions, 1 deletion
applications/lofar2/libraries/sdp/hdllib.cfg
applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
+338
-0
338 additions, 0 deletions
...s/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
with
340 additions
and
1 deletion
applications/lofar2/libraries/sdp/hdllib.cfg
+
2
−
1
View file @
f8da1e48
hdl_lib_name
=
lofar2_sdp
hdl_library_clause_name
=
lofar2_sdp_lib
hdl_lib_uses_synth
=
common dp wpfb rTwoSDF filter si st technology mm dp diag aduh tech_jesd204b
hdl_lib_uses_synth
=
common dp wpfb rTwoSDF filter si st technology mm dp diag aduh tech_jesd204b
tr_10GbE
hdl_lib_uses_sim
=
hdl_lib_technology =
...
...
@@ -10,6 +10,7 @@ synth_files =
src/vhdl/sdp_subband_equalizer.vhd
src/vhdl/sdp_bf_weights.vhd
src/vhdl/sdp_beamformer_local.vhd
src/vhdl/sdp_beamformer_output.vhd
src/vhdl/node_sdp_adc_input_and_timing.vhd
src/vhdl/node_sdp_filterbank.vhd
test_bench_files
=
...
...
This diff is collapsed.
Click to expand it.
applications/lofar2/libraries/sdp/src/vhdl/sdp_beamformer_output.vhd
0 → 100644
+
338
−
0
View file @
f8da1e48
-------------------------------------------------------------------------------
--
-- Copyright 2020
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
--
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
--
-- Author: R. van der Walle
-- Purpose:
-- The beamformer output (BDO) packetizes the beamlet data into UDP/IP packets.
-- Description:
-- Remark:
--
-------------------------------------------------------------------------------
LIBRARY
IEEE
,
common_lib
,
dp_lib
,
tr_10GbE_lib
;
USE
IEEE
.
STD_LOGIC_1164
.
ALL
;
USE
IEEE
.
NUMERIC_STD
.
ALL
;
USE
common_lib
.
common_pkg
.
ALL
;
USE
common_lib
.
common_field_pkg
.
ALL
;
USE
common_lib
.
common_mem_pkg
.
ALL
;
USE
dp_lib
.
dp_stream_pkg
.
ALL
;
USE
work
.
sdp_pkg
.
ALL
;
ENTITY
sdp_beamformer_output
IS
GENERIC
(
g_beamset_id
:
NATURAL
:
=
0
);
PORT
(
dp_clk
:
IN
STD_LOGIC
;
dp_rst
:
IN
STD_LOGIC
;
mm_clk
:
IN
STD_LOGIC
;
mm_rst
:
IN
STD_LOGIC
;
reg_hdr_dat_mosi
:
IN
t_mem_mosi
:
=
c_mem_mosi_rst
;
reg_hdr_dat_miso
:
OUT
t_mem_miso
;
reg_dp_xonoff_mosi
:
IN
t_mem_mosi
:
=
c_mem_mosi_rst
;
reg_dp_xonoff_miso
:
OUT
t_mem_miso
;
in_sosi
:
IN
t_dp_sosi
;
out_sosi
:
OUT
t_dp_sosi
;
src_in
:
IN
t_dp_siso
;
sdp_info
:
IN
t_sdp_info
;
gn_id
:
IN
STD_LOGIC_VECTOR
(
4
DOWNTO
0
);
eth_src_mac
:
IN
STD_LOGIC_VECTOR
(
47
DOWNTO
0
);
ip_src_addr
:
IN
STD_LOGIC_VECTOR
(
31
DOWNTO
0
);
udp_src_port
:
IN
STD_LOGIC_VECTOR
(
15
DOWNTO
0
);
hdr_fields_out
:
OUT
STD_LOGIC_VECTOR
(
1023
DOWNTO
0
)
);
END
sdp_beamformer_output
;
ARCHITECTURE
str
OF
sdp_beamformer_output
IS
CONSTANT
c_data_w
:
NATURAL
:
=
c_nof_complex
*
c_sdp_W_beamlet
;
--16b
CONSTANT
c_marker
:
STD_LOGIC_VECTOR
:
=
x"62"
;
CONSTANT
c_version
:
NATURAL
:
=
5
;
CONSTANT
c_nof_blocks_per_packet
:
NATURAL
:
=
4
;
CONSTANT
c_nof_beamlets_per_block
:
NATURAL
:
=
c_sdp_N_pol
*
c_sdp_S_sub_bf
;
CONSTANT
c_beamlet_id
:
NATURAL
:
=
g_beamset_id
*
c_sdp_S_sub_bf
;
CONSTANT
c_fifo_fill
:
NATURAL
:
=
c_nof_blocks_per_packet
*
c_nof_beamlets_per_block
/
4
;
-- 4 beamlets fit in 1 64bit longword
CONSTANT
c_fifo_size
:
NATURAL
:
=
c_fifo_fill
+
11
;
-- Make fifo size large enough for adding header.
SIGNAL
snk_in_concat
:
t_dp_sosi
;
SIGNAL
dp_packet_merge_src_out
:
t_dp_sosi
;
SIGNAL
dp_repack_data_src_out
:
t_dp_sosi
;
SIGNAL
dp_fifo_sc_src_out
:
t_dp_sosi
;
SIGNAL
dp_fifo_sc_src_in
:
t_dp_siso
;
SIGNAL
dp_offload_tx_src_out
:
t_dp_sosi
;
SIGNAL
dp_offload_tx_src_in
:
t_dp_siso
;
SIGNAL
ip_checksum_src_out
:
t_dp_sosi
;
SIGNAL
ip_checksum_src_in
:
t_dp_siso
;
SIGNAL
common_fifo_rd_req
:
STD_LOGIC
;
SIGNAL
payload_err
:
STD_LOGIC_VECTOR
(
0
DOWNTO
0
);
SIGNAL
dp_offload_tx_hdr_fields
:
STD_LOGIC_VECTOR
(
1023
DOWNTO
0
);
-------------------------------------------------------------------------------
-- dp_offload_tx
-------------------------------------------------------------------------------
CONSTANT
c_nof_hdr_fields
:
NATURAL
:
=
3
+
12
+
4
+
18
+
1
;
-- 592b; 9.25 64b words
CONSTANT
c_hdr_field_sel
:
STD_LOGIC_VECTOR
(
c_nof_hdr_fields
-1
DOWNTO
0
)
:
=
"101"
&
"111111111001"
&
"0111"
&
"110000000010001110"
&
"0"
;
CONSTANT
c_hdr_field_arr
:
t_common_field_arr
(
c_nof_hdr_fields
-1
DOWNTO
0
)
:
=
(
(
field_name_pad
(
"eth_dst_mac"
),
"RW"
,
48
,
field_default
(
x"00074306C700"
)
),
-- 00074306C700=DOP36-eth0
(
field_name_pad
(
"eth_src_mac"
),
"RW"
,
48
,
field_default
(
0
)
),
(
field_name_pad
(
"eth_type"
),
"RO"
,
16
,
field_default
(
x"0800"
)
),
(
field_name_pad
(
"ip_version"
),
"RO"
,
4
,
field_default
(
4
)
),
(
field_name_pad
(
"ip_header_length"
),
"RO"
,
4
,
field_default
(
5
)
),
(
field_name_pad
(
"ip_services"
),
"RO"
,
8
,
field_default
(
0
)
),
(
field_name_pad
(
"ip_total_length"
),
"RO"
,
16
,
field_default
(
7868
)
),
(
field_name_pad
(
"ip_identification"
),
"RO"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"ip_flags"
),
"RO"
,
3
,
field_default
(
2
)
),
(
field_name_pad
(
"ip_fragment_offset"
),
"RO"
,
13
,
field_default
(
0
)
),
(
field_name_pad
(
"ip_time_to_live"
),
"RO"
,
8
,
field_default
(
127
)
),
(
field_name_pad
(
"ip_protocol"
),
"RO"
,
8
,
field_default
(
17
)
),
(
field_name_pad
(
"ip_header_checksum"
),
"RW"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"ip_src_addr"
),
"RW"
,
32
,
field_default
(
0
)
),
(
field_name_pad
(
"ip_dst_addr"
),
"RW"
,
32
,
field_default
(
x"C0A80001"
)
),
-- C0A80001=DOP36-eth0 '192.168.0.1'
(
field_name_pad
(
"udp_src_port"
),
"RW"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"udp_dst_port"
),
"RW"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"udp_total_length"
),
"RO"
,
16
,
field_default
(
7848
)
),
(
field_name_pad
(
"udp_checksum"
),
"RO"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_marker"
),
"RO"
,
8
,
field_default
(
c_marker
)
),
(
field_name_pad
(
"sdp_version_id"
),
"RO"
,
8
,
field_default
(
c_version
)
),
(
field_name_pad
(
"sdp_observation_id"
),
"RW"
,
32
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_station_id"
),
"RW"
,
16
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_antenna_band_id"
),
"RW"
,
1
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_nyquist_zone_id"
),
"RW"
,
2
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_f_adc"
),
"RW"
,
1
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_fsub_type"
),
"RW"
,
1
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_payload_error"
),
"RW"
,
1
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_repositioning_flag"
),
"RW"
,
1
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_source_info_beamlet_width"
),
"RO"
,
4
,
field_default
(
c_sdp_W_beamlet
)
),
(
field_name_pad
(
"sdp_source_info_gn_id"
),
"RW"
,
5
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_reserved"
),
"RW"
,
40
,
field_default
(
0
)
),
(
field_name_pad
(
"sdp_beamlet_scale"
),
"RW"
,
16
,
field_default
(
2
**
15
)
),
(
field_name_pad
(
"sdp_beamlet_id"
),
"RO"
,
16
,
field_default
(
c_beamlet_id
)
),
(
field_name_pad
(
"sdp_nof_blocks_per_packet"
),
"RO"
,
8
,
field_default
(
c_nof_blocks_per_packet
)
),
(
field_name_pad
(
"sdp_nof_beamlets_per_block"
),
"RO"
,
16
,
field_default
(
c_nof_beamlets_per_block
)
),
(
field_name_pad
(
"sdp_block_period"
),
"RW"
,
16
,
field_default
(
5120
)
),
(
field_name_pad
(
"dp_bsn"
),
"RW"
,
64
,
field_default
(
0
)
)
);
BEGIN
-------------------------------------------------------------------------------
-- Input rewiring: concatenate input complex fields to data field
-- . dp_repack_data works with data fields only
-------------------------------------------------------------------------------
p_snk_in_arr
:
PROCESS
(
in_sosi
)
BEGIN
snk_in_concat
<=
in_sosi
;
snk_in_concat
.
data
(
c_data_w
-1
DOWNTO
0
)
<=
in_sosi
.
im
(
c_sdp_W_beamlet
-1
DOWNTO
0
)
&
in_sosi
.
re
(
c_sdp_W_beamlet
-1
DOWNTO
0
);
END
PROCESS
;
-------------------------------------------------------------------------------
-- dp_repack_data
-- . 16b -> 64b
-- . We don't need to flow control the source beacause we're going from 16b->64b
-------------------------------------------------------------------------------
u_dp_repack_data
:
ENTITY
dp_lib
.
dp_repack_data
GENERIC
MAP
(
g_in_dat_w
=>
c_data_w
,
g_in_nof_words
=>
4
,
g_out_dat_w
=>
c_longword_w
,
g_out_nof_words
=>
1
)
PORT
MAP
(
clk
=>
dp_clk
,
rst
=>
dp_rst
,
snk_in
=>
snk_in_concat
,
snk_out
=>
OPEN
,
src_out
=>
dp_repack_data_src_out
,
src_in
=>
c_dp_siso_rdy
);
-------------------------------------------------------------------------------
-- dp_packet_merge
-------------------------------------------------------------------------------
u_dp_packet_merge
:
ENTITY
dp_lib
.
dp_packet_merge
GENERIC
MAP
(
g_nof_pkt
=>
c_nof_blocks_per_packet
)
PORT
MAP
(
rst
=>
dp_rst
,
clk
=>
dp_clk
,
snk_out
=>
OPEN
,
snk_in
=>
dp_repack_data_src_out
,
src_in
=>
c_dp_siso_rdy
,
src_out
=>
dp_packet_merge_src_out
);
-------------------------------------------------------------------------------
-- FIFO
-- . We're inserting headers, so dp_offload_tx needs a flow controllable
-- source.
-- . Also, we need a fill FIFO here because 16b->64b will introduce gaps in our
-- TX stream (not allowed by 10G TX MAC).
-------------------------------------------------------------------------------
u_dp_fifo_fill_sc
:
ENTITY
dp_lib
.
dp_fifo_fill_sc
GENERIC
MAP
(
g_data_w
=>
c_longword_w
,
g_empty_w
=>
c_byte_w
,
g_use_empty
=>
TRUE
,
g_use_bsn
=>
TRUE
,
g_bsn_w
=>
64
,
g_use_sync
=>
TRUE
,
g_fifo_size
=>
c_fifo_size
,
g_fifo_fill
=>
c_fifo_fill
)
PORT
MAP
(
clk
=>
dp_clk
,
rst
=>
dp_rst
,
snk_in
=>
dp_packet_merge_src_out
,
src_out
=>
dp_fifo_sc_src_out
,
src_in
=>
dp_fifo_sc_src_in
);
-- Simple fifo to store the payload error at eop.
common_fifo_rd_req
<=
dp_fifo_sc_src_out
.
sop
AND
dp_fifo_sc_src_out
.
valid
;
u_common_fifo_sc
:
ENTITY
common_lib
.
common_fifo_sc
GENERIC
MAP
(
g_dat_w
=>
1
,
g_nof_words
=>
2
)
PORT
MAP
(
rst
=>
dp_rst
,
clk
=>
dp_clk
,
wr_dat
=>
dp_packet_merge_src_out
.
err
(
0
DOWNTO
0
),
wr_req
=>
dp_packet_merge_src_out
.
eop
,
rd_dat
=>
payload_err
,
rd_req
=>
common_fifo_rd_req
);
-------------------------------------------------------------------------------
-- Assemble offload info
-------------------------------------------------------------------------------
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"eth_src_mac"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"eth_src_mac"
))
<=
eth_src_mac
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"udp_src_port"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"udp_src_port"
))
<=
udp_src_port
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"ip_src_addr"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"ip_src_addr"
))
<=
ip_src_addr
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_observation_id"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_observation_id"
))
<=
sdp_info
.
observation_id
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_station_id"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_station_id"
))
<=
sdp_info
.
station_id
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_antenna_band_id"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_antenna_band_id"
))
<=
SLV
(
sdp_info
.
antenna_band_index
);
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_nyquist_zone_id"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_nyquist_zone_id"
))
<=
sdp_info
.
nyquist_zone_index
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_f_adc"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_f_adc"
))
<=
SLV
(
sdp_info
.
f_adc
);
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_fsub_type"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_fsub_type"
))
<=
SLV
(
sdp_info
.
fsub_type
);
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_payload_error"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_payload_error"
))
<=
payload_err
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_repositioning_flag"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_repositioning_flag"
))
<=
SLV
(
sdp_info
.
beam_repositioning_flag
);
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_source_info_gn_id"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_source_info_gn_id"
))
<=
gn_id
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_reserved"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_reserved"
))
<=
(
OTHERS
=>
'0'
);
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_beamlet_scale"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_beamlet_scale"
))
<=
sdp_info
.
beamlet_scale
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"sdp_block_period"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"sdp_block_period"
))
<=
sdp_info
.
block_period
;
dp_offload_tx_hdr_fields
(
field_hi
(
c_hdr_field_arr
,
"dp_bsn"
)
DOWNTO
field_lo
(
c_hdr_field_arr
,
"dp_bsn"
))
<=
dp_fifo_sc_src_out
.
bsn
(
63
DOWNTO
0
);
-------------------------------------------------------------------------------
-- dp_offload_tx_v3
-------------------------------------------------------------------------------
u_dp_offload_tx_v3
:
ENTITY
dp_lib
.
dp_offload_tx_v3
GENERIC
MAP
(
g_nof_streams
=>
1
,
g_data_w
=>
c_longword_w
,
g_symbol_w
=>
c_byte_w
,
g_hdr_field_arr
=>
c_hdr_field_arr
,
g_hdr_field_sel
=>
c_hdr_field_sel
)
PORT
MAP
(
mm_rst
=>
mm_rst
,
mm_clk
=>
mm_clk
,
dp_rst
=>
dp_rst
,
dp_clk
=>
dp_clk
,
reg_hdr_dat_mosi
=>
reg_hdr_dat_mosi
,
reg_hdr_dat_miso
=>
reg_hdr_dat_miso
,
snk_in_arr
(
0
)
=>
dp_fifo_sc_src_out
,
snk_out_arr
(
0
)
=>
dp_fifo_sc_src_in
,
src_out_arr
(
0
)
=>
dp_offload_tx_src_out
,
src_in_arr
(
0
)
=>
dp_offload_tx_src_in
,
hdr_fields_in_arr
(
0
)
=>
dp_offload_tx_hdr_fields
,
hdr_fields_out_arr
(
0
)
=>
hdr_fields_out
);
-------------------------------------------------------------------------------
-- tr_10GbE_ip_checksum
-------------------------------------------------------------------------------
u_tr_10GbE_ip_checksum
:
ENTITY
tr_10GbE_lib
.
tr_10GbE_ip_checksum
PORT
MAP
(
rst
=>
dp_rst
,
clk
=>
dp_clk
,
snk_in
=>
dp_offload_tx_src_out
,
snk_out
=>
dp_offload_tx_src_in
,
src_out
=>
ip_checksum_src_out
,
src_in
=>
ip_checksum_src_in
);
-------------------------------------------------------------------------------
-- mms_dp_xonoff
-------------------------------------------------------------------------------
u_mms_dp_xonoff
:
ENTITY
dp_lib
.
mms_dp_xonoff
GENERIC
MAP
(
g_default_value
=>
'0'
)
PORT
MAP
(
-- Memory-mapped clock domain
mm_rst
=>
mm_rst
,
mm_clk
=>
mm_clk
,
reg_mosi
=>
reg_dp_xonoff_mosi
,
reg_miso
=>
reg_dp_xonoff_miso
,
-- Streaming clock domain
dp_rst
=>
dp_rst
,
dp_clk
=>
dp_clk
,
-- ST sinks
snk_out_arr
(
0
)
=>
ip_checksum_src_in
,
snk_in_arr
(
0
)
=>
ip_checksum_src_out
,
-- ST source
src_in_arr
(
0
)
=>
src_in
,
src_out_arr
(
0
)
=>
out_sosi
);
END
str
;
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment