Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
P
Platform-independent core collection
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
18
Issues
18
List
Board
Labels
Milestones
Merge Requests
5
Merge Requests
5
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Platform-independent core collection
Commits
2c67ec27
Commit
2c67ec27
authored
Jun 19, 2019
by
Tristan Gingold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move gc_ds182x_readout.vhd to a subdirectory.
parent
9027e98a
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
601 additions
and
0 deletions
+601
-0
gc_ds182x_readout.vhd
modules/common/gc_ds182x_readout/gc_ds182x_readout.vhd
+601
-0
No files found.
modules/common/gc_ds182x_readout/gc_ds182x_readout.vhd
0 → 100644
View file @
2c67ec27
--------------------------------------------------------------------------------
-- CERN BE-CO-HT
-- General Cores Library
-- https://www.ohwr.org/projects/general-cores
--------------------------------------------------------------------------------
--
-- unit name: gc_ds182x_readout
--
-- description: one wire temperature & unique id interface for
-- DS1822 and DS1820.
--
--------------------------------------------------------------------------------
-- Copyright CERN 2013-2018
--------------------------------------------------------------------------------
-- Copyright and related rights are licensed under the Solderpad Hardware
-- 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://solderpad.org/licenses/SHL-2.0.
-- Unless required by applicable law or agreed to in writing, software,
-- hardware and materials distributed under this 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.
--------------------------------------------------------------------------------
--=================================================================================================
-- Libraries & Packages
--=================================================================================================
library
IEEE
;
use
IEEE
.
std_logic_1164
.
all
;
use
IEEE
.
NUMERIC_STD
.
all
;
--=================================================================================================
-- Entity declaration for fmc_masterFIP_core
--=================================================================================================
entity
gc_ds182x_readout
is
generic
(
g_CLOCK_FREQ_KHZ
:
integer
:
=
40000
;
-- clk_i frequency in KHz
g_USE_INTERNAL_PPS
:
boolean
:
=
false
);
port
(
clk_i
:
in
std_logic
;
rst_n_i
:
in
std_logic
;
pps_p_i
:
in
std_logic
;
-- pulse per second (for temperature read)
onewire_b
:
inout
std_logic
;
-- IO to be connected to the chip(DS1820/DS1822)
id_o
:
out
std_logic_vector
(
63
downto
0
);
-- id_o value
temper_o
:
out
std_logic_vector
(
15
downto
0
);
-- temperature value (refreshed every second)
id_read_o
:
out
std_logic
;
-- id_o value is valid_o
id_ok_o
:
out
std_logic
);
-- Same as id_read_o, but not reset with rst_n_i
end
gc_ds182x_readout
;
--=================================================================================================
-- architecture declaration
--=================================================================================================
architecture
arch
of
gc_ds182x_readout
is
-- time slot constants according to specs https://www.maximintegrated.com/en/app-notes/index.mvp/id/162
constant
SLOT_CNT_START
:
unsigned
(
15
downto
0
)
:
=
to_unsigned
(
0
*
g_CLOCK_FREQ_KHZ
/
40000
,
16
);
constant
SLOT_CNT_START_PLUSONE
:
unsigned
(
15
downto
0
)
:
=
SLOT_CNT_START
+
1
;
constant
SLOT_CNT_SET
:
unsigned
(
15
downto
0
)
:
=
to_unsigned
(
60
*
g_CLOCK_FREQ_KHZ
/
40000
,
16
);
constant
SLOT_CNT_RD
:
unsigned
(
15
downto
0
)
:
=
to_unsigned
(
600
*
g_CLOCK_FREQ_KHZ
/
40000
,
16
);
constant
SLOT_CNT_STOP
:
unsigned
(
15
downto
0
)
:
=
to_unsigned
(
3600
*
g_CLOCK_FREQ_KHZ
/
40000
,
16
);
constant
SLOT_CNT_PRESTOP
:
unsigned
(
15
downto
0
)
:
=
to_unsigned
((
3600-60
)
*
g_CLOCK_FREQ_KHZ
/
40000
,
16
);
constant
READ_ID_HEADER
:
std_logic_vector
(
7
downto
0
)
:
=
X"33"
;
constant
CONVERT_HEADER
:
std_logic_vector
(
7
downto
0
)
:
=
X"44"
;
constant
READ_TEMPER_HEADER
:
std_logic_vector
(
7
downto
0
)
:
=
X"BE"
;
constant
SKIPHEADER
:
std_logic_vector
(
7
downto
0
)
:
=
X"CC"
;
constant
ID_LEFT
:
integer
:
=
71
;
constant
ID_RIGHT
:
integer
:
=
8
;
constant
TEMPER_LEFT
:
integer
:
=
15
;
constant
TEMPER_RIGHT
:
integer
:
=
0
;
constant
TEMPER_DONE_BIT
:
std_logic
:
=
'0'
;
-- The serial line is asserted to this value by the
-- DS1820/DS1822 when the temperature conversion is ready
constant
TEMPER_LGTH
:
unsigned
(
7
downto
0
)
:
=
to_unsigned
(
72
,
8
);
constant
ID_LGTH
:
unsigned
(
7
downto
0
)
:
=
to_unsigned
(
64
,
8
);
type
op_fsm_t
is
(
READ_ID_OP
,
SKIP_ROM_OP1
,
CONV_OP1
,
CONV_OP2
,
SKIP_ROM_OP2
,
READ_TEMP_OP
);
type
cm_fsm_t
is
(
RST_CM
,
PREP_WR_CM
,
WR_CM
,
PREP_RD_CM
,
RD_CM
,
IDLE_CM
);
signal
bit_top
,
bit_cnt
:
unsigned
(
7
downto
0
);
signal
slot_cnt
:
unsigned
(
15
downto
0
);
signal
start_p
,
end_p
,
set_value
,
read_value
,
init_pulse
:
std_logic
;
signal
state_op
,
nxt_state_op
:
op_fsm_t
;
signal
state_cm
,
nxt_state_cm
:
cm_fsm_t
;
signal
crc_vec
,
header
:
std_logic_vector
(
7
downto
0
);
signal
crc_ok
,
init
,
pre_read_p
,
i_id_read
:
std_logic
;
signal
load_temper
,
load_id
,
cm_only
,
pps_p_d
:
std_logic
;
signal
serial_id_out
,
nx_serial_id_out
,
nx_serial_id_oe
:
std_logic
;
signal
i_serial_id_oe
,
serial_idr
:
std_logic
;
signal
end_wr_cm
,
end_rd_cm
,
inc_bit_cnt
,
rst_bit_cnt
:
std_logic
;
signal
shift_header
,
id_cm_reg
:
std_logic
;
signal
cm_reg
:
std_logic_vector
(
71
downto
0
);
signal
shifted_header
:
std_logic_vector
(
7
downto
0
);
signal
pre_init_p
:
std_logic
;
signal
pps_counter
:
unsigned
(
31
downto
0
);
signal
pps
:
std_logic
;
--=================================================================================================
-- architecture begin
--=================================================================================================
begin
gen_external_pps
:
if
not
g_USE_INTERNAL_PPS
generate
pps
<=
pps_p_i
;
end
generate
gen_external_pps
;
gen_internal_pps
:
if
g_USE_INTERNAL_PPS
generate
p_pps_gen
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
pps
<=
'0'
;
pps_counter
<=
(
others
=>
'0'
);
else
if
pps_counter
=
g_CLOCK_FREQ_KHZ
*
1000-1
then
pps
<=
'1'
;
pps_counter
<=
(
others
=>
'0'
);
else
pps
<=
'0'
;
pps_counter
<=
pps_counter
+
1
;
end
if
;
end
if
;
end
if
;
end
process
;
end
generate
gen_internal_pps
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Serial data line in tri-state, when not writing data out
onewire_b
<=
serial_id_out
when
i_serial_id_oe
=
'1'
else
'Z'
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- pps_p_i 1 clock tick delay
pps_p_iDelay
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
pps_p_d
<=
pps
;
end
if
;
end
process
;
---------------------------------------------------------------------------------------------------
-- operations FSM --
---------------------------------------------------------------------------------------------------
op_fsm_transitions
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
state_op
<=
READ_ID_OP
;
else
state_op
<=
nxt_state_op
;
end
if
;
end
if
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
op_fsm_states
:
process
(
state_op
,
pps
,
crc_ok
)
begin
nxt_state_op
<=
READ_ID_OP
;
case
state_op
is
when
READ_ID_OP
=>
if
pps
=
'1'
and
crc_ok
=
'1'
then
nxt_state_op
<=
CONV_OP1
;
else
nxt_state_op
<=
state_op
;
end
if
;
when
CONV_OP1
=>
if
pps
=
'1'
then
nxt_state_op
<=
SKIP_ROM_OP1
;
else
nxt_state_op
<=
state_op
;
end
if
;
when
SKIP_ROM_OP1
=>
if
pps
=
'1'
then
nxt_state_op
<=
READ_TEMP_OP
;
else
nxt_state_op
<=
state_op
;
end
if
;
when
READ_TEMP_OP
=>
if
pps
=
'1'
then
nxt_state_op
<=
SKIP_ROM_OP2
;
else
nxt_state_op
<=
state_op
;
end
if
;
when
SKIP_ROM_OP2
=>
if
pps
=
'1'
then
nxt_state_op
<=
CONV_OP2
;
else
nxt_state_op
<=
state_op
;
end
if
;
when
CONV_OP2
=>
if
pps
=
'1'
then
nxt_state_op
<=
SKIP_ROM_OP1
;
else
nxt_state_op
<=
state_op
;
end
if
;
end
case
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
op_fsm_outputs
:
process
(
state_op
,
state_cm
,
crc_ok
,
pps
,
cm_only
)
begin
header
<=
READ_ID_HEADER
;
bit_top
<=
ID_LGTH
;
load_temper
<=
'0'
;
load_id
<=
'0'
;
cm_only
<=
'0'
;
case
state_op
is
when
READ_ID_OP
=>
header
<=
READ_ID_HEADER
;
bit_top
<=
ID_LGTH
;
if
state_cm
=
IDLE_CM
then
load_id
<=
crc_ok
;
end
if
;
when
CONV_OP1
=>
header
<=
CONVERT_HEADER
;
cm_only
<=
'1'
;
when
SKIP_ROM_OP1
=>
header
<=
SKIPHEADER
;
cm_only
<=
'1'
;
when
READ_TEMP_OP
=>
header
<=
READ_TEMPER_HEADER
;
bit_top
<=
TEMPER_LGTH
;
if
state_cm
=
IDLE_CM
then
load_temper
<=
crc_ok
and
pps
;
end
if
;
when
SKIP_ROM_OP2
=>
header
<=
SKIPHEADER
;
cm_only
<=
'1'
;
when
CONV_OP2
=>
header
<=
CONVERT_HEADER
;
cm_only
<=
'1'
;
when
others
=>
null
;
end
case
;
end
process
;
---------------------------------------------------------------------------------------------------
-- commands FSM --
---------------------------------------------------------------------------------------------------
cm_fsm_transitions
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
state_cm
<=
RST_CM
;
else
state_cm
<=
nxt_state_cm
;
end
if
;
end
if
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
cm_fsm_states
:
process
(
state_cm
,
start_p
,
end_wr_cm
,
end_rd_cm
,
crc_ok
,
state_op
,
cm_only
,
pps_p_d
)
begin
nxt_state_cm
<=
RST_CM
;
case
state_cm
is
when
RST_CM
=>
if
start_p
=
'1'
then
nxt_state_cm
<=
PREP_WR_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
when
PREP_WR_CM
=>
if
start_p
=
'1'
then
nxt_state_cm
<=
WR_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
when
WR_CM
=>
if
end_wr_cm
=
'1'
then
if
cm_only
=
'0'
then
nxt_state_cm
<=
PREP_RD_CM
;
else
nxt_state_cm
<=
IDLE_CM
;
end
if
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
when
PREP_RD_CM
=>
if
start_p
=
'1'
then
nxt_state_cm
<=
RD_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
when
RD_CM
=>
if
end_rd_cm
=
'1'
then
nxt_state_cm
<=
IDLE_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
when
IDLE_CM
=>
if
state_op
=
READ_ID_OP
then
if
crc_ok
=
'0'
then
nxt_state_cm
<=
RST_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
elsif
state_op
=
READ_TEMP_OP
then
-- At this moment I will send a Conv temper_o command
if
pps_p_d
=
'1'
then
nxt_state_cm
<=
PREP_WR_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
elsif
(
state_op
=
CONV_OP1
)
or
(
state_op
=
CONV_OP2
)
then
-- At this moment I will restart a temper_o read
if
pps_p_d
=
'1'
then
nxt_state_cm
<=
PREP_WR_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
elsif
(
state_op
=
SKIP_ROM_OP1
)
or
(
state_op
=
SKIP_ROM_OP2
)
then
-- At this moment I will restart
if
pps_p_d
=
'1'
then
nxt_state_cm
<=
RST_CM
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
else
nxt_state_cm
<=
state_cm
;
end
if
;
end
case
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
cm_fsm_outputs
:
process
(
state_cm
,
bit_cnt
,
pre_read_p
,
crc_vec
,
start_p
,
shifted_header
,
init_pulse
,
read_value
,
pre_init_p
)
begin
inc_bit_cnt
<=
'0'
;
nx_serial_id_out
<=
'0'
;
shift_header
<=
'0'
;
id_cm_reg
<=
'0'
;
nx_serial_id_oe
<=
'0'
;
rst_bit_cnt
<=
'0'
;
init
<=
'0'
;
crc_ok
<=
'0'
;
case
state_cm
is
when
RST_CM
=>
rst_bit_cnt
<=
'1'
;
nx_serial_id_out
<=
'0'
;
nx_serial_id_oe
<=
'1'
;
init
<=
start_p
;
when
PREP_WR_CM
=>
rst_bit_cnt
<=
start_p
;
nx_serial_id_oe
<=
'0'
;
nx_serial_id_out
<=
'0'
;
when
WR_CM
=>
shift_header
<=
start_p
;
inc_bit_cnt
<=
start_p
;
rst_bit_cnt
<=
'0'
;
nx_serial_id_out
<=
shifted_header
(
0
)
and
(
not
init_pulse
);
if
bit_cnt
<
to_unsigned
(
7
,
bit_cnt
'length
)
then
nx_serial_id_oe
<=
not
pre_init_p
;
else
nx_serial_id_oe
<=
not
pre_read_p
;
end
if
;
when
PREP_RD_CM
=>
rst_bit_cnt
<=
start_p
;
nx_serial_id_oe
<=
'0'
;
nx_serial_id_out
<=
'0'
;
when
RD_CM
=>
inc_bit_cnt
<=
start_p
;
rst_bit_cnt
<=
'0'
;
nx_serial_id_out
<=
not
init_pulse
;
id_cm_reg
<=
read_value
;
nx_serial_id_oe
<=
init_pulse
;
when
IDLE_CM
=>
if
crc_vec
=
x"00"
then
crc_ok
<=
'1'
;
else
crc_ok
<=
'0'
;
end
if
;
init
<=
'1'
;
end
case
;
end
process
;
---------------------------------------------------------------------------------------------------
-- time slots --
---------------------------------------------------------------------------------------------------
-- Generates time slots
-- Reset pulse
-- Read time slot
-- Write time slots
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
slot_cnt
(
slot_cnt
'left
)
<=
'1'
;
slot_cnt
(
slot_cnt
'left
-1
downto
0
)
<=
(
others
=>
'0'
);
start_p
<=
'0'
;
end_p
<=
'0'
;
set_value
<=
'0'
;
read_value
<=
'0'
;
init_pulse
<=
'0'
;
pre_init_p
<=
'0'
;
pre_read_p
<=
'0'
;
else
-- Slot counter
if
init
=
'1'
then
slot_cnt
(
slot_cnt
'left
)
<=
'1'
;
slot_cnt
(
slot_cnt
'left
-
1
downto
0
)
<=
(
others
=>
'0'
);
elsif
slot_cnt
=
SLOT_CNT_STOP
then
slot_cnt
<=
(
others
=>
'0'
);
else
slot_cnt
<=
slot_cnt
+
1
;
end
if
;
-- Time slot start pulse
if
slot_cnt
=
SLOT_CNT_START
then
start_p
<=
'1'
;
else
start_p
<=
'0'
;
end
if
;
if
((
slot_cnt
>
SLOT_CNT_START
)
and
(
slot_cnt
<
SLOT_CNT_SET
))
then
init_pulse
<=
'1'
;
else
init_pulse
<=
'0'
;
end
if
;
if
((
slot_cnt
>
SLOT_CNT_PRESTOP
)
and
(
slot_cnt
<
SLOT_CNT_STOP
))
then
pre_init_p
<=
'1'
;
else
pre_init_p
<=
'0'
;
end
if
;
if
(((
slot_cnt
>
SLOT_CNT_PRESTOP
)
and
(
slot_cnt
<=
SLOT_CNT_STOP
))
or
(
slot_cnt
<=
SLOT_CNT_START_PLUSONE
))
then
pre_read_p
<=
'1'
;
else
pre_read_p
<=
'0'
;
end
if
;
-- End of time slot pulse
if
slot_cnt
=
SLOT_CNT_START
then
end_p
<=
'1'
;
else
end_p
<=
'0'
;
end
if
;
-- Pulse to write value on serial link
if
slot_cnt
=
SLOT_CNT_SET
then
set_value
<=
'1'
;
else
set_value
<=
'0'
;
end
if
;
-- Pulse to read value on serial link
if
slot_cnt
=
SLOT_CNT_RD
then
read_value
<=
'1'
;
else
read_value
<=
'0'
;
end
if
;
end
if
;
end
if
;
end
process
;
---------------------------------------------------------------------------------------------------
-- serdes --
---------------------------------------------------------------------------------------------------
-- Data serializer bit counter
BitCnt_p
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
bit_cnt
<=
(
others
=>
'0'
);
else
if
rst_bit_cnt
=
'1'
then
bit_cnt
<=
(
others
=>
'0'
);
elsif
inc_bit_cnt
=
'1'
then
bit_cnt
<=
bit_cnt
+
1
;
end
if
;
end
if
;
end
if
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Data serializer shift register
ShiftReg_p
:
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
shifted_header
<=
READ_ID_HEADER
;
cm_reg
<=
(
others
=>
'0'
);
serial_idr
<=
'0'
;
serial_id_out
<=
'0'
;
i_serial_id_oe
<=
'0'
;
id_o
<=
(
others
=>
'0'
);
i_id_read
<=
'0'
;
id_read_o
<=
'0'
;
crc_vec
<=
(
others
=>
'0'
);
temper_o
<=
(
others
=>
'0'
);
else
-- Samples serial input
serial_idr
<=
onewire_b
;
-- Shifts command out
if
init
=
'1'
then
shifted_header
<=
header
;
elsif
shift_header
=
'1'
then
shifted_header
(
shifted_header
'left
-1
downto
0
)
<=
shifted_header
(
shifted_header
'left
downto
1
);
shifted_header
(
shifted_header
'left
)
<=
'0'
;
end
if
;
-- Computes CRC on read data (include the received CRC itself, if no errror crc_vec = X"00")
if
init
=
'1'
then
crc_vec
<=
(
others
=>
'0'
);
elsif
id_cm_reg
=
'1'
then
crc_vec
(
0
)
<=
serial_idr
xor
crc_vec
(
7
);
crc_vec
(
3
downto
1
)
<=
crc_vec
(
2
downto
0
);
crc_vec
(
4
)
<=
(
serial_idr
xor
crc_vec
(
7
))
xor
crc_vec
(
3
);
crc_vec
(
5
)
<=
(
serial_idr
xor
crc_vec
(
7
))
xor
crc_vec
(
4
);
crc_vec
(
7
downto
6
)
<=
crc_vec
(
6
downto
5
);
end
if
;
-- Stores incoming data
if
(
id_cm_reg
=
'1'
)
then
cm_reg
(
cm_reg
'left
-
1
downto
0
)
<=
cm_reg
(
cm_reg
'left
downto
1
);
cm_reg
(
cm_reg
'left
)
<=
serial_idr
;
end
if
;
-- Updates serial output data
serial_id_out
<=
nx_serial_id_out
;
-- Updates serial output enable
i_serial_id_oe
<=
nx_serial_id_oe
;
-- Stores id_o in register
if
(
load_id
=
'1'
)
then
i_id_read
<=
'1'
;
id_o
<=
cm_reg
(
ID_LEFT
downto
ID_RIGHT
);
end
if
;
-- Stores temperature in register
if
(
load_temper
=
'1'
)
then
temper_o
<=
cm_reg
(
TEMPER_LEFT
downto
TEMPER_RIGHT
);
end
if
;
-- Delays id_o read
id_read_o
<=
i_id_read
;
end
if
;
end
if
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Value on id_o port is valid_o
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
state_cm
=
IDLE_CM
then
id_ok_o
<=
crc_ok
;
end
if
;
end
if
;
end
process
;
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
-- Detects end of read or end of write command
end_wr_cm
<=
'1'
when
(
bit_cnt
=
to_unsigned
(
7
,
bit_cnt
'length
))
and
(
inc_bit_cnt
=
'1'
)
else
'0'
;
end_rd_cm
<=
'1'
when
(
bit_cnt
=
bit_top
)
else
'0'
;
end
arch
;
--=================================================================================================
-- architecture end
--=================================================================================================
---------------------------------------------------------------------------------------------------
-- E N D O F F I L E
---------------------------------------------------------------------------------------------------
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