Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Rimfaxe
vme_core
Commits
d1978ac0
Commit
d1978ac0
authored
Aug 13, 2020
by
Michael Munch
Browse files
Reverted cli_arb
parent
556d894a
Changes
1
Hide whitespace changes
Inline
Side-by-side
src/vme_cli_arb.vhd
View file @
d1978ac0
...
...
@@ -64,46 +64,24 @@ entity vme_cli_arb is
-- Signals to/from the VME core.
-- Directions inverted relative to the core.
-- Core 1
signal
vc1_busy
:
in
std_logic
:
=
'0'
;
signal
vc_busy
:
in
std_logic
:
=
'0'
;
signal
vc
1
_int_data_o
:
in
vme_vec_64_t
;
signal
vc
1
_int_data_strobe
:
in
std_logic
:
=
c_DATA_CLEAR
;
signal
vc
1
_int_go_consumed_strobe
:
in
std_logic
:
=
'0'
;
signal
vc
1
_int_blt_decision_strobe
:
in
std_logic
:
=
'0'
;
signal
vc
1
_int_err_code
:
in
err_vec_t
:
=
C_ERR_OK
;
signal
vc_int_data_o
:
in
vme_vec_64_t
;
signal
vc_int_data_strobe
:
in
std_logic
:
=
c_DATA_CLEAR
;
signal
vc_int_go_consumed_strobe
:
in
std_logic
:
=
'0'
;
signal
vc_int_blt_decision_strobe
:
in
std_logic
:
=
'0'
;
signal
vc_int_err_code
:
in
err_vec_t
:
=
C_ERR_OK
;
signal
vc
1
_int_addr
:
out
vme_addr_t
;
signal
vc
1
_int_data_i
:
out
vme_vec_64_t
;
signal
vc
1
_int_am_i
:
out
am_vec_t
;
signal
vc
1
_int_vme_rw
:
out
std_logic
;
signal
vc
1
_int_vme_go
:
out
std_logic
;
signal
vc_int_addr
:
out
vme_addr_t
;
signal
vc_int_data_i
:
out
vme_vec_64_t
;
signal
vc_int_am_i
:
out
am_vec_t
;
signal
vc_int_vme_rw
:
out
std_logic
;
signal
vc_int_vme_go
:
out
std_logic
;
signal
vc
1
_int_blt_decided
:
out
std_logic
;
signal
vc
1
_int_blt_continue
:
out
std_logic
;
signal
vc_int_blt_decided
:
out
std_logic
;
signal
vc_int_blt_continue
:
out
std_logic
;
signal
vc1_int_berr_ok
:
out
std_logic
;
-- Core 2
signal
vc2_busy
:
in
std_logic
:
=
'0'
;
signal
vc2_int_data_o
:
in
vme_vec_64_t
;
signal
vc2_int_data_strobe
:
in
std_logic
:
=
c_DATA_CLEAR
;
signal
vc2_int_go_consumed_strobe
:
in
std_logic
:
=
'0'
;
signal
vc2_int_blt_decision_strobe
:
in
std_logic
:
=
'0'
;
signal
vc2_int_err_code
:
in
err_vec_t
:
=
C_ERR_OK
;
signal
vc2_int_addr
:
out
vme_addr_t
;
signal
vc2_int_data_i
:
out
vme_vec_64_t
;
signal
vc2_int_am_i
:
out
am_vec_t
;
signal
vc2_int_vme_rw
:
out
std_logic
;
signal
vc2_int_vme_go
:
out
std_logic
;
signal
vc2_int_blt_decided
:
out
std_logic
;
signal
vc2_int_blt_continue
:
out
std_logic
;
signal
vc2_int_berr_ok
:
out
std_logic
signal
vc_int_berr_ok
:
out
std_logic
-- -- Dropped signals (since they cannot be multiplexed /
-- -- span multiple access cycles).
...
...
@@ -134,6 +112,7 @@ architecture rtl of vme_cli_arb is
-- In case we are not busy, which client would we like to
-- make active (if any).
signal
cnt
:
integer
range
0
to
256
:
=
0
;
signal
want_1
:
boolean
;
signal
want_2
:
boolean
;
...
...
@@ -149,10 +128,6 @@ architecture rtl of vme_cli_arb is
signal
active_1
:
boolean
:
=
false
;
signal
active_2
:
boolean
:
=
false
;
-- Which core is active
signal
core_1
:
boolean
:
=
true
;
-- Who will we prefer when we can take the next client, i.e. are
-- no longer busy?
signal
prefer_1
:
boolean
:
=
false
;
...
...
@@ -162,52 +137,32 @@ architecture rtl of vme_cli_arb is
signal
p1_int_err_code_latched
:
err_vec_t
:
=
C_ERR_OK
;
signal
p2_int_err_code_latched
:
err_vec_t
:
=
C_ERR_OK
;
signal
r_busy
:
std_logic
:
=
'0'
;
signal
r_data_o
:
vme_vec_64_t
;
signal
r_data_strobe
:
std_logic
:
=
c_DATA_CLEAR
;
signal
r_go_consumed_strobe
:
std_logic
:
=
'0'
;
signal
r_blt_decision_strobe
:
std_logic
:
=
'0'
;
signal
r_err_code
:
err_vec_t
:
=
C_ERR_OK
;
signal
r_vme_go
:
std_logic
:
=
'0'
;
begin
-- Muxed version of all inputs from VME cores
r_busy
<=
vc1_busy
when
core_1
else
vc2_busy
;
r_data_o
<=
vc1_int_data_o
when
core_1
else
vc2_int_data_o
;
r_data_strobe
<=
vc1_int_data_strobe
when
core_1
else
vc2_int_data_strobe
;
r_go_consumed_strobe
<=
vc1_int_go_consumed_strobe
when
core_1
else
vc2_int_go_consumed_strobe
;
r_blt_decision_strobe
<=
vc1_int_blt_decision_strobe
when
core_1
else
vc2_int_blt_decision_strobe
;
r_err_code
<=
vc1_int_err_code
when
core_1
else
vc2_int_err_code
;
want_1
<=
(
p1_int_vme_go
=
'1'
and
p2_int_vme_go
=
'0'
)
or
(
p1_int_vme_go
=
'1'
and
prefer_1
);
want_2
<=
(
p2_int_vme_go
=
'1'
and
p1_int_vme_go
=
'0'
)
or
(
p2_int_vme_go
=
'1'
and
not
prefer_1
);
-- start_1 <= r_busy = '0' and want_1;
-- start_2 <= r_busy = '0' and want_2;
start_1
<=
vc1_busy
=
'0'
and
vc2_busy
=
'0'
and
want_1
;
start_2
<=
vc1_busy
=
'0'
and
vc2_busy
=
'0'
and
want_2
;
start_1
<=
vc_busy
=
'0'
and
want_1
;
start_2
<=
vc_busy
=
'0'
and
want_2
;
-- We kill the live assignment as soon as busy is removed.
-- (Not really needed.)
live_1
<=
(
active_1
and
r
_busy
=
'1'
)
or
start_1
;
live_2
<=
(
active_2
and
r
_busy
=
'1'
)
or
start_2
;
live_1
<=
(
active_1
and
vc
_busy
=
'1'
)
or
start_1
;
live_2
<=
(
active_2
and
vc
_busy
=
'1'
)
or
start_2
;
-- Only AM=0x19 are passed to core 2.
core_1
<=
p1_int_am_i
/=
c_AM_TRLOII
when
live_1
else
p2_int_am_i
/=
c_AM_TRLOII
;
process
(
clk
)
begin
if
(
rising_edge
(
clk
))
then
if
(
r_busy
=
'0'
)
then
cnt
<=
cnt
+
1
;
if
(
vc_busy
=
'0'
)
then
-- Latch error code when busy pulled
if
(
active_1
)
then
p1_int_err_code_latched
<=
r
_err_code
;
p1_int_err_code_latched
<=
vc_int
_err_code
;
end
if
;
if
(
active_2
)
then
p2_int_err_code_latched
<=
r
_err_code
;
p2_int_err_code_latched
<=
vc_int
_err_code
;
end
if
;
active_1
<=
false
;
active_2
<=
false
;
...
...
@@ -216,7 +171,7 @@ begin
-- client directly.
if
(
start_1
)
then
active_1
<=
true
;
prefer_1
<=
false
;
prefer_1
<=
false
;
end
if
;
if
(
start_2
)
then
active_2
<=
true
;
...
...
@@ -225,12 +180,12 @@ begin
-- We select on active instead of live, since active is cheaper (comes
-- directly from a flip-flop, instead of logic), and
-- vc
1
_int_data_strobe will not come on the first cycle.
if
(
active_1
and
r
_data_strobe
=
'1'
)
then
p1_int_data_o_latched
<=
r
_data_o
;
-- vc_int_data_strobe will not come on the first cycle.
if
(
active_1
and
vc_int
_data_strobe
=
'1'
)
then
p1_int_data_o_latched
<=
vc_int
_data_o
;
end
if
;
if
(
active_2
and
r
_data_strobe
=
'1'
)
then
p2_int_data_o_latched
<=
r
_data_o
;
if
(
active_2
and
vc_int
_data_strobe
=
'1'
)
then
p2_int_data_o_latched
<=
vc_int
_data_o
;
end
if
;
end
if
;
...
...
@@ -243,28 +198,14 @@ begin
-- client 2. This does not matter, since the VME core will
-- only react to anything if the 'go' signal is given.
-- We send all signals, except go, to both cores.
vc1_int_addr
<=
p1_int_addr
when
live_1
else
p2_int_addr
;
vc1_int_data_i
<=
p1_int_data_i
when
live_1
else
p2_int_data_i
;
vc1_int_am_i
<=
p1_int_am_i
when
live_1
else
p2_int_am_i
;
vc1_int_vme_rw
<=
p1_int_vme_rw
when
live_1
else
p2_int_vme_rw
;
vc1_int_blt_decided
<=
p1_int_blt_decided
when
live_1
else
p2_int_blt_decided
;
vc1_int_blt_continue
<=
p1_int_blt_continue
when
live_1
else
p2_int_blt_continue
;
vc1_int_berr_ok
<=
p1_int_berr_ok
when
live_1
else
p2_int_berr_ok
;
vc2_int_addr
<=
p1_int_addr
when
live_1
else
p2_int_addr
;
vc2_int_data_i
<=
p1_int_data_i
when
live_1
else
p2_int_data_i
;
vc2_int_am_i
<=
p1_int_am_i
when
live_1
else
p2_int_am_i
;
vc2_int_vme_rw
<=
p1_int_vme_rw
when
live_1
else
p2_int_vme_rw
;
vc2_int_blt_decided
<=
p1_int_blt_decided
when
live_1
else
p2_int_blt_decided
;
vc2_int_blt_continue
<=
p1_int_blt_continue
when
live_1
else
p2_int_blt_continue
;
vc2_int_berr_ok
<=
p1_int_berr_ok
when
live_1
else
p2_int_berr_ok
;
-- Go handling.
r_vme_go
<=
p1_int_vme_go
when
live_1
else
p2_int_vme_go
;
vc1_int_vme_go
<=
r_vme_go
when
core_1
else
'0'
;
vc2_int_vme_go
<=
r_vme_go
when
not
core_1
else
'0'
;
vc_int_addr
<=
p1_int_addr
when
live_1
else
p2_int_addr
;
vc_int_data_i
<=
p1_int_data_i
when
live_1
else
p2_int_data_i
;
vc_int_am_i
<=
p1_int_am_i
when
live_1
else
p2_int_am_i
;
vc_int_vme_rw
<=
p1_int_vme_rw
when
live_1
else
p2_int_vme_rw
;
vc_int_vme_go
<=
p1_int_vme_go
when
live_1
else
p2_int_vme_go
;
vc_int_blt_decided
<=
p1_int_blt_decided
when
live_1
else
p2_int_blt_decided
;
vc_int_blt_continue
<=
p1_int_blt_continue
when
live_1
else
p2_int_blt_continue
;
vc_int_berr_ok
<=
p1_int_berr_ok
when
live_1
else
p2_int_berr_ok
;
-- Signals to the clients from the VME core:
...
...
@@ -274,25 +215,25 @@ begin
-- Data is passed directly through on the cycle they have been latched.
-- Otherwise, take the latched value:
p1_int_data_o
<=
r
_data_o
when
(
live_1
and
r
_data_strobe
=
'1'
)
else
p1_int_data_o
<=
vc_int
_data_o
when
(
live_1
and
vc_int
_data_strobe
=
'1'
)
else
p1_int_data_o_latched
;
p2_int_data_o
<=
r
_data_o
when
(
live_2
and
r
_data_strobe
=
'1'
)
else
p2_int_data_o
<=
vc_int
_data_o
when
(
live_2
and
vc_int
_data_strobe
=
'1'
)
else
p2_int_data_o_latched
;
-- The error code follows the data.
p1_int_err_code
<=
r
_err_code
when
(
live_1
and
r
_data_strobe
=
'1'
)
else
p1_int_err_code
<=
vc_int
_err_code
when
(
live_1
and
vc_int
_data_strobe
=
'1'
)
else
p1_int_err_code_latched
;
p2_int_err_code
<=
r
_err_code
when
(
live_2
and
r
_data_strobe
=
'1'
)
else
p2_int_err_code
<=
vc_int
_err_code
when
(
live_2
and
vc_int
_data_strobe
=
'1'
)
else
p2_int_err_code_latched
;
-- The strobes always go to the live client.
p1_int_data_strobe
<=
r
_data_strobe
when
live_1
else
'0'
;
p2_int_data_strobe
<=
r
_data_strobe
when
live_2
else
'0'
;
p1_int_data_strobe
<=
vc_int
_data_strobe
when
live_1
else
'0'
;
p2_int_data_strobe
<=
vc_int
_data_strobe
when
live_2
else
'0'
;
p1_int_go_consumed_strobe
<=
r
_go_consumed_strobe
when
live_1
else
'0'
;
p2_int_go_consumed_strobe
<=
r
_go_consumed_strobe
when
live_2
else
'0'
;
p1_int_go_consumed_strobe
<=
vc_int
_go_consumed_strobe
when
live_1
else
'0'
;
p2_int_go_consumed_strobe
<=
vc_int
_go_consumed_strobe
when
live_2
else
'0'
;
p1_int_blt_decision_strobe
<=
r
_blt_decision_strobe
when
live_1
else
'0'
;
p2_int_blt_decision_strobe
<=
r
_blt_decision_strobe
when
live_2
else
'0'
;
p1_int_blt_decision_strobe
<=
vc_int
_blt_decision_strobe
when
live_1
else
'0'
;
p2_int_blt_decision_strobe
<=
vc_int
_blt_decision_strobe
when
live_2
else
'0'
;
-- The busy of a client is simply while it is live.
-- This actually means that we will report busy some cycles
...
...
@@ -317,8 +258,8 @@ begin
process
(
clk
)
begin
if
(
rising_edge
(
clk
))
then
l_data
<=
vc
1
_int_data_o
;
l_err_code
<=
vc
1
_int_err_code
;
l_data
<=
vc_int_data_o
;
l_err_code
<=
vc_int_err_code
;
end
if
;
end
process
;
...
...
@@ -331,8 +272,8 @@ begin
-- psl not_two_busy: assert not (p1_busy and p2_busy);
-- -- Don't start clients when VME core is busy
-- psl busy_dont_start_1: assert always {vc
1
_busy = '1'} |-> not start_1 until vc
1
_busy = '0';
-- psl busy_dont_start_2: assert always {vc
1
_busy = '1'} |-> not start_1 until vc
1
_busy = '0';
-- psl busy_dont_start_1: assert always {vc_busy = '1'} |-> not start_1 until vc_busy = '0';
-- psl busy_dont_start_2: assert always {vc_busy = '1'} |-> not start_1 until vc_busy = '0';
-- -- When we have started client 1 then prefer 2 until it runs
-- psl if_start_1_pref_2: assert always {start_1} |=> not prefer_1 until start_2;
...
...
@@ -341,102 +282,102 @@ begin
-- -- If both clients request access then we pick our favourite
-- psl pick_pref_client_1: assert always
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and not prefer_1 and vc
1
_busy = '0'}
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and not prefer_1 and vc_busy = '0'}
-- |=> start_2 until active_2;
-- psl pick_pref_client_2: assert always
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and prefer_1 and vc
1
_busy = '0'}
-- {p1_int_vme_go = '1' and p2_int_vme_go = '1' and prefer_1 and vc_busy = '0'}
-- |=> start_1 until active_1;
-- -- While client is live it data output tracks live data
-- psl live_track_1:
-- assert always {active_1; vc
1
_int_data_strobe = '1'}
-- |=> p1_int_data_o = vc
1
_int_data_o
-- until vc
1
_int_data_strobe = '0' or not live_1;
-- assert always {active_1; vc_int_data_strobe = '1'}
-- |=> p1_int_data_o = vc_int_data_o
-- until vc_int_data_strobe = '0' or not live_1;
-- psl live_track_2:
-- assert always {active_2; vc
1
_int_data_strobe = '1'}
-- |=> p2_int_data_o = vc
1
_int_data_o
-- until vc
1
_int_data_strobe = '0' or not live_2;
-- assert always {active_2; vc_int_data_strobe = '1'}
-- |=> p2_int_data_o = vc_int_data_o
-- until vc_int_data_strobe = '0' or not live_2;
-- -- If we sent p1_int_vme_go then the VME core will eventually receive it
-- psl p1_vme_addr: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_addr = p1_int_addr ;
-- |=> eventually! vc_int_addr = p1_int_addr ;
-- psl p1_vme_data_i: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_data_i = p1_int_data_i ;
-- |=> eventually! vc_int_data_i = p1_int_data_i ;
-- psl p1_vme_am_i: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_am_i = p1_int_am_i ;
-- |=> eventually! vc_int_am_i = p1_int_am_i ;
-- psl p1_vme_rw: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_vme_rw = p1_int_vme_rw ;
-- |=> eventually! vc_int_vme_rw = p1_int_vme_rw ;
-- psl p1_vme_go: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_vme_go = p1_int_vme_go ;
-- |=> eventually! vc_int_vme_go = p1_int_vme_go ;
-- psl p1_vme_blt_deci: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_blt_decided = p1_int_blt_decided ;
-- |=> eventually! vc_int_blt_decided = p1_int_blt_decided ;
-- psl p1_vme_blt_cont: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_blt_continue = p1_int_blt_continue ;
-- |=> eventually! vc_int_blt_continue = p1_int_blt_continue ;
-- psl p1_vme_berr_ok: assert always {p1_int_vme_go}
-- |=> eventually! vc
1
_int_berr_ok = p1_int_berr_ok ;
-- |=> eventually! vc_int_berr_ok = p1_int_berr_ok ;
-- -- If we sent p2_int_vme_go then the VME core will eventually receive it
-- psl p2_vme_addr: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_addr = p2_int_addr ;
-- |=> eventually! vc_int_addr = p2_int_addr ;
-- psl p2_vme_data_i: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_data_i = p2_int_data_i ;
-- |=> eventually! vc_int_data_i = p2_int_data_i ;
-- psl p2_vme_am_i: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_am_i = p2_int_am_i ;
-- |=> eventually! vc_int_am_i = p2_int_am_i ;
-- psl p2_vme_rw: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_vme_rw = p2_int_vme_rw ;
-- |=> eventually! vc_int_vme_rw = p2_int_vme_rw ;
-- psl p2_vme_go: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_vme_go = p2_int_vme_go ;
-- |=> eventually! vc_int_vme_go = p2_int_vme_go ;
-- psl p2_vme_blt_deci: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_blt_decided = p2_int_blt_decided ;
-- |=> eventually! vc_int_blt_decided = p2_int_blt_decided ;
-- psl p2_vme_blt_cont: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_blt_continue = p2_int_blt_continue ;
-- |=> eventually! vc_int_blt_continue = p2_int_blt_continue ;
-- psl p2_vme_berr_ok: assert always {p2_int_vme_go}
-- |=> eventually! vc
1
_int_berr_ok = p2_int_berr_ok ;
-- |=> eventually! vc_int_berr_ok = p2_int_berr_ok ;
-- -- Data strobes are routed to live client
-- psl p1_get_d_strobe: assert always {live_1}
-- |=> p1_int_data_strobe = vc
1
_int_data_strobe until not live_1;
-- |=> p1_int_data_strobe = vc_int_data_strobe until not live_1;
-- psl p2_get_d_strobe: assert always {live_2}
-- |=> p2_int_data_strobe = vc
1
_int_data_strobe until not live_2;
-- |=> p2_int_data_strobe = vc_int_data_strobe until not live_2;
-- -- Go strobes are routed to live client
-- psl p1_get_go_strobe: assert always {live_1}
-- |=> p1_int_go_consumed_strobe = vc
1
_int_go_consumed_strobe until not live_1;
-- |=> p1_int_go_consumed_strobe = vc_int_go_consumed_strobe until not live_1;
-- psl p2_get_go_strobe: assert always {live_2}
-- |=> p2_int_go_consumed_strobe = vc
1
_int_go_consumed_strobe until not live_2;
-- |=> p2_int_go_consumed_strobe = vc_int_go_consumed_strobe until not live_2;
-- -- BLT decision strobes are routed to live client
-- psl p1_get_blt_strobe: assert always {live_1}
-- |=> p1_int_blt_decision_strobe = vc
1
_int_blt_decision_strobe until not live_1;
-- |=> p1_int_blt_decision_strobe = vc_int_blt_decision_strobe until not live_1;
-- psl p2_get_blt_strobe: assert always {live_2}
-- |=> p2_int_blt_decision_strobe = vc
1
_int_blt_decision_strobe until not live_2;
-- |=> p2_int_blt_decision_strobe = vc_int_blt_decision_strobe until not live_2;
-- -- Latched data tracks input while active and strobed
-- psl p1_tracks_data: assert always
-- {active_1 and vc
1
_busy = '1' and vc
1
_int_data_strobe = '1'}
-- {active_1 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- |=> p1_int_data_o_latched = l_data
-- until vc
1
_int_data_strobe = '0' or not active_1;
-- until vc_int_data_strobe = '0' or not active_1;
-- psl p2_tracks_data: assert always
-- {active_2 and vc
1
_busy = '1' and vc
1
_int_data_strobe = '1'}
-- {active_2 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- |=> p2_int_data_o_latched = l_data
-- until vc
1
_int_data_strobe = '0' or not active_2;
-- until vc_int_data_strobe = '0' or not active_2;
-- -- Latched error tracks input while active and strobed
-- psl p1_tracks_err: assert always
-- {active_1 and vc
1
_busy = '1' and vc
1
_int_data_strobe = '1'}
-- {active_1 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- |=> p1_int_err_code_latched = l_err_code
-- until vc
1
_int_data_strobe = '0' or not active_1;
-- until vc_int_data_strobe = '0' or not active_1;
-- psl p2_tracks_err: assert always
-- {active_2 and vc
1
_busy = '1' and vc
1
_int_data_strobe = '1'}
-- {active_2 and vc_busy = '1' and vc_int_data_strobe = '1'}
-- |=> p2_int_err_code_latched = l_err_code
-- until vc
1
_int_data_strobe = '0' or not active_2;
-- until vc_int_data_strobe = '0' or not active_2;
end
generate
FormalG
;
end
architecture
;
...
...
Write
Preview
Supports
Markdown
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