Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
DIOT WIC Gateware
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
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
DIOT WIC Gateware
Commits
cc8ba521
Commit
cc8ba521
authored
Feb 26, 2020
by
Tristan Gingold
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rework plc urv memory map to improve speed.
TODO: add byte selects for data memory
parent
bb956743
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
428 additions
and
341 deletions
+428
-341
plc_urv.vhd
hdl/rtl/urv_wic/plc_urv.vhd
+18
-119
plc_urv_regs.cheby
hdl/rtl/urv_wic/plc_urv_regs.cheby
+10
-0
plc_urv_regs.vhd
hdl/rtl/urv_wic/plc_urv_regs.vhd
+220
-160
top_sim.vhdl
hdl/syn/diot_urv_demo/top_sim.vhdl
+13
-10
diot_urv_top.vhd
hdl/top/diot_urv_demo/diot_urv_top.vhd
+116
-19
Makefile
sw/plc_urv/Makefile
+1
-1
plc.ld
sw/plc_urv/plc.ld
+1
-1
plc_demo.c
sw/plc_urv/plc_demo.c
+4
-2
plc_urv_regs.h
sw/plc_urv/plc_urv_regs.h
+45
-29
No files found.
hdl/rtl/urv_wic/plc_urv.vhd
View file @
cc8ba521
...
...
@@ -34,8 +34,7 @@ use work.urv_pkg.all;
entity
plc_urv
is
generic
(
g_IRAM_LOG_SIZE
:
natural
:
=
10
;
g_DRAM_LOG_SIZE
:
natural
:
=
12
);
g_IRAM_LOG_SIZE
:
natural
:
=
10
);
port
(
clk_sys_i
:
in
std_logic
;
rst_n_i
:
in
std_logic
;
...
...
@@ -61,16 +60,6 @@ architecture arch of plc_urv is
signal
dm_data_select
:
std_logic_vector
(
3
downto
0
);
signal
dm_load
,
dm_store
,
dm_load_done
,
dm_store_done
:
std_logic
;
signal
reg_dm_addr
,
reg_dm_data_s
:
std_logic_vector
(
31
downto
0
);
signal
reg_dm_data_select
:
std_logic_vector
(
3
downto
0
);
signal
reg_dm_load
,
reg_dm_store
:
std_logic
;
signal
dm_cycle_in_progress
,
reg_dm_is_wishbone
:
std_logic
;
signal
dm_mem_rdata
,
dm_wb_rdata
:
std_logic_vector
(
31
downto
0
);
signal
dm_wb_write
,
dm_select_wb
:
std_logic
;
signal
reg_dm_data_write
:
std_logic
;
signal
dwb_out
:
t_wishbone_master_out
;
begin
...
...
@@ -111,18 +100,28 @@ begin
begin
if
rising_edge
(
clk_sys_i
)
then
if
rst_n_i
=
'0'
then
reg_dm_load
<=
'0'
;
reg_dm_store
<=
'0'
;
dwb_out
.
cyc
<=
'0'
;
dwb_out
.
stb
<=
'0'
;
else
reg_dm_load
<=
dm_load
;
reg_dm_store
<=
dm_store
;
reg_dm_addr
<=
dm_addr
;
reg_dm_data_s
<=
dm_data_s
;
reg_dm_data_select
<=
dm_data_select
;
if
dm_load
=
'1'
or
dm_store
=
'1'
then
dwb_out
.
cyc
<=
'1'
;
dwb_out
.
stb
<=
'1'
;
dwb_out
.
adr
<=
dm_addr
;
dwb_out
.
sel
<=
dm_data_select
;
dwb_out
.
we
<=
dm_store
;
dwb_out
.
dat
<=
dm_data_s
;
elsif
dwb_i
.
ack
=
'1'
then
dwb_out
.
cyc
<=
'0'
;
dwb_out
.
stb
<=
'0'
;
end
if
;
end
if
;
end
if
;
end
process
;
dm_data_l
<=
dwb_i
.
dat
;
dm_store_done
<=
dwb_i
.
ack
and
dwb_out
.
we
;
dm_load_done
<=
dwb_i
.
ack
and
not
dwb_out
.
we
;
p_iram
:
process
(
clk_sys_i
)
is
constant
IRAM_WSIZE
:
natural
:
=
2
**
(
g_IRAM_LOG_SIZE
-
2
);
...
...
@@ -143,106 +142,6 @@ begin
ram_wb_o
.
rty
<=
'0'
;
ram_wb_o
.
stall
<=
'0'
;
-- 1st MByte of the mem is the IRAM
reg_dm_is_wishbone
<=
'1'
when
reg_dm_addr
(
31
downto
20
)
/=
x"000"
else
'0'
;
reg_dm_data_write
<=
not
reg_dm_is_wishbone
and
reg_dm_store
;
dm_data_l
<=
dm_wb_rdata
when
dm_select_wb
=
'1'
else
dm_mem_rdata
;
p_ram
:
process
(
clk_sys_i
)
is
variable
mem
:
t_ram32_type
(
2
**
(
g_DRAM_LOG_SIZE
-
2
)
-
1
downto
0
);
variable
addr
:
natural
range
mem
'range
;
begin
if
rising_edge
(
clk_sys_i
)
then
addr
:
=
to_integer
(
unsigned
(
reg_dm_addr
(
g_DRAM_LOG_SIZE
-
1
downto
2
)));
dm_mem_rdata
<=
mem
(
addr
);
if
reg_dm_data_write
=
'1'
then
for
i
in
0
to
3
loop
if
reg_dm_data_select
(
i
)
=
'1'
then
mem
(
addr
)(
8
*
i
+
7
downto
8
*
i
)
:
=
reg_dm_data_s
(
8
*
i
+
7
downto
8
*
i
);
end
if
;
end
loop
;
end
if
;
end
if
;
end
process
;
-- Wishbone bus arbitration / internal RAM access
p_wishbone_master
:
process
(
clk_sys_i
)
begin
if
rising_edge
(
clk_sys_i
)
then
if
rst_n_i
=
'0'
then
dwb_out
.
cyc
<=
'0'
;
dwb_out
.
stb
<=
'0'
;
dwb_out
.
adr
<=
(
others
=>
'0'
);
dwb_out
.
sel
<=
x"0"
;
dwb_out
.
we
<=
'0'
;
dwb_out
.
dat
<=
(
others
=>
'0'
);
dm_cycle_in_progress
<=
'0'
;
dm_load_done
<=
'0'
;
dm_store_done
<=
'0'
;
dm_select_wb
<=
'0'
;
else
if
dm_cycle_in_progress
=
'0'
then
if
reg_dm_is_wishbone
=
'0'
then
-- Internal access
if
reg_dm_store
=
'1'
then
dm_load_done
<=
'0'
;
dm_store_done
<=
'1'
;
dm_select_wb
<=
'0'
;
elsif
reg_dm_load
=
'1'
then
dm_load_done
<=
'1'
;
dm_store_done
<=
'0'
;
dm_select_wb
<=
'0'
;
else
dm_store_done
<=
'0'
;
dm_load_done
<=
'0'
;
dm_select_wb
<=
'0'
;
end
if
;
else
-- Wishbone access
if
reg_dm_load
=
'1'
or
reg_dm_store
=
'1'
then
dwb_out
.
cyc
<=
'1'
;
dwb_out
.
stb
<=
'1'
;
dwb_out
.
we
<=
reg_dm_store
;
dm_wb_write
<=
reg_dm_store
;
dwb_out
.
adr
<=
reg_dm_addr
;
dwb_out
.
dat
<=
reg_dm_data_s
;
dwb_out
.
sel
<=
reg_dm_data_select
;
dm_load_done
<=
'0'
;
dm_store_done
<=
'0'
;
dm_cycle_in_progress
<=
'1'
;
else
dm_store_done
<=
'0'
;
dm_load_done
<=
'0'
;
dm_cycle_in_progress
<=
'0'
;
end
if
;
end
if
;
else
-- Wishbone transfer in progress.
if
dwb_i
.
stall
=
'0'
then
dwb_out
.
stb
<=
'0'
;
end
if
;
if
dwb_i
.
ack
=
'1'
then
if
dm_wb_write
=
'0'
then
dm_wb_rdata
<=
dwb_i
.
dat
;
dm_select_wb
<=
'1'
;
dm_load_done
<=
'1'
;
else
dm_store_done
<=
'1'
;
dm_select_wb
<=
'0'
;
end
if
;
dm_cycle_in_progress
<=
'0'
;
dwb_out
.
cyc
<=
'0'
;
end
if
;
end
if
;
end
if
;
end
if
;
end
process
p_wishbone_master
;
cpu_rst
<=
not
rst_n_i
;
p_im_valid
:
process
(
clk_sys_i
)
...
...
hdl/rtl/urv_wic/plc_urv_regs.cheby
View file @
cc8ba521
...
...
@@ -5,6 +5,16 @@ memory-map:
x-hdl:
busgroup: True
children:
- memory:
name: sram
address: 0x10000
interface: sram
memsize: 8k
children:
- reg:
name: value
access: rw
width: 32
- submap:
name: mailboxes
filename: "mbox_regs.cheby"
...
...
hdl/rtl/urv_wic/plc_urv_regs.vhd
View file @
cc8ba521
-- Do not edit. Generated on
Fri Feb 14 11:50:20
2020 by tgingold
-- Do not edit. Generated on
Wed Feb 26 09:20:54
2020 by tgingold
-- With Cheby 1.4.dev0 and these options:
-- -i plc_urv_regs.cheby --gen-hdl plc_urv_regs.vhd
...
...
@@ -15,6 +15,12 @@ entity plc_urv_regs is
wb_i
:
in
t_wishbone_slave_in
;
wb_o
:
out
t_wishbone_slave_out
;
-- SRAM bus sram
sram_addr_o
:
out
std_logic_vector
(
12
downto
2
);
sram_data_i
:
in
std_logic_vector
(
31
downto
0
);
sram_data_o
:
out
std_logic_vector
(
31
downto
0
);
sram_wr_o
:
out
std_logic
;
-- Mailbox to the fip urv
mailboxes_mboxout_o
:
out
std_logic_vector
(
31
downto
0
);
mailboxes_mboxout_wr_o
:
out
std_logic
;
...
...
@@ -81,7 +87,7 @@ entity plc_urv_regs is
end
plc_urv_regs
;
architecture
syn
of
plc_urv_regs
is
signal
adr_int
:
std_logic_vector
(
6
downto
2
);
signal
adr_int
:
std_logic_vector
(
1
6
downto
2
);
signal
rd_req_int
:
std_logic
;
signal
wr_req_int
:
std_logic
;
signal
rd_ack_int
:
std_logic
;
...
...
@@ -90,6 +96,8 @@ architecture syn of plc_urv_regs is
signal
ack_int
:
std_logic
;
signal
wb_rip
:
std_logic
;
signal
wb_wip
:
std_logic
;
signal
sram_rack
:
std_logic
;
signal
sram_re
:
std_logic
;
signal
mailboxes_mboxout_wreq
:
std_logic
;
signal
relays_pins_0_reg
:
std_logic_vector
(
31
downto
0
);
signal
relays_pins_0_wreq
:
std_logic
;
...
...
@@ -118,13 +126,15 @@ architecture syn of plc_urv_regs is
signal
rd_ack_d0
:
std_logic
;
signal
rd_dat_d0
:
std_logic_vector
(
31
downto
0
);
signal
wr_req_d0
:
std_logic
;
signal
wr_adr_d0
:
std_logic_vector
(
6
downto
2
);
signal
wr_adr_d0
:
std_logic_vector
(
1
6
downto
2
);
signal
wr_dat_d0
:
std_logic_vector
(
31
downto
0
);
signal
wr_sel_d0
:
std_logic_vector
(
3
downto
0
);
signal
sram_wp
:
std_logic
;
signal
sram_we
:
std_logic
;
begin
-- WB decode signals
adr_int
<=
wb_i
.
adr
(
6
downto
2
);
adr_int
<=
wb_i
.
adr
(
1
6
downto
2
);
wb_en
<=
wb_i
.
cyc
and
wb_i
.
stb
;
process
(
clk_i
)
begin
...
...
@@ -172,6 +182,35 @@ begin
end
if
;
end
process
;
-- Interface sram
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
sram_rack
<=
'0'
;
else
sram_rack
<=
sram_re
and
not
sram_rack
;
end
if
;
end
if
;
end
process
;
sram_data_o
<=
wr_dat_d0
;
process
(
clk_i
)
begin
if
rising_edge
(
clk_i
)
then
if
rst_n_i
=
'0'
then
sram_wp
<=
'0'
;
else
sram_wp
<=
(
wr_req_d0
or
sram_wp
)
and
rd_req_int
;
end
if
;
end
if
;
end
process
;
sram_we
<=
(
wr_req_d0
or
sram_wp
)
and
not
rd_req_int
;
process
(
adr_int
,
wr_adr_d0
,
sram_re
)
begin
if
sram_re
=
'1'
then
sram_addr_o
<=
adr_int
(
12
downto
2
);
else
sram_addr_o
<=
wr_adr_d0
(
12
downto
2
);
end
if
;
end
process
;
-- Register mailboxes_mboxout
mailboxes_mboxout_o
<=
wr_dat_d0
;
mailboxes_mboxout_wr_o
<=
mailboxes_mboxout_wreq
;
...
...
@@ -327,7 +366,8 @@ begin
end
process
;
-- Process for write requests.
process
(
wr_adr_d0
,
wr_req_d0
,
relays_pins_0_wack
,
relays_pins_1_wack
,
relays_pins_2_wack
,
relays_pins_3_wack
,
relays_pins_4_wack
,
relays_pins_5_wack
,
relays_pins_6_wack
,
relays_pins_7_wack
)
begin
process
(
wr_adr_d0
,
sram_we
,
wr_req_d0
,
relays_pins_0_wack
,
relays_pins_1_wack
,
relays_pins_2_wack
,
relays_pins_3_wack
,
relays_pins_4_wack
,
relays_pins_5_wack
,
relays_pins_6_wack
,
relays_pins_7_wack
)
begin
sram_wr_o
<=
'0'
;
mailboxes_mboxout_wreq
<=
'0'
;
relays_pins_0_wreq
<=
'0'
;
relays_pins_1_wreq
<=
'0'
;
...
...
@@ -337,170 +377,190 @@ begin
relays_pins_5_wreq
<=
'0'
;
relays_pins_6_wreq
<=
'0'
;
relays_pins_7_wreq
<=
'0'
;
case
wr_adr_d0
(
6
downto
2
)
is
when
"00000"
=>
-- Reg mailboxes_mboxout
mailboxes_mboxout_wreq
<=
wr_req_d0
;
wr_ack_int
<=
wr_req_d0
;
when
"00001"
=>
-- Reg mailboxes_mboxin
wr_ack_int
<=
wr_req_d0
;
when
"00010"
=>
-- Reg mailboxes_status
wr_ack_int
<=
wr_req_d0
;
when
"00100"
=>
-- Reg presence
wr_ack_int
<=
wr_req_d0
;
when
"01000"
=>
-- Reg loops_pins_0
wr_ack_int
<=
wr_req_d0
;
when
"01001"
=>
-- Reg loops_pins_1
wr_ack_int
<=
wr_req_d0
;
when
"01010"
=>
-- Reg loops_pins_2
wr_ack_int
<=
wr_req_d0
;
when
"01011"
=>
-- Reg loops_pins_3
wr_ack_int
<=
wr_req_d0
;
when
"01100"
=>
-- Reg loops_pins_4
wr_ack_int
<=
wr_req_d0
;
when
"01101"
=>
-- Reg loops_pins_5
wr_ack_int
<=
wr_req_d0
;
when
"01110"
=>
-- Reg loops_pins_6
wr_ack_int
<=
wr_req_d0
;
when
"01111"
=>
-- Reg loops_pins_7
wr_ack_int
<=
wr_req_d0
;
when
"10000"
=>
-- Reg relays_pins_0
relays_pins_0_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_0_wack
;
when
"10001"
=>
-- Reg relays_pins_1
relays_pins_1_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_1_wack
;
when
"10010"
=>
-- Reg relays_pins_2
relays_pins_2_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_2_wack
;
when
"10011"
=>
-- Reg relays_pins_3
relays_pins_3_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_3_wack
;
when
"10100"
=>
-- Reg relays_pins_4
relays_pins_4_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_4_wack
;
when
"10101"
=>
-- Reg relays_pins_5
relays_pins_5_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_5_wack
;
when
"10110"
=>
-- Reg relays_pins_6
relays_pins_6_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_6_wack
;
when
"10111"
=>
-- Reg relays_pins_7
relays_pins_7_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_7_wack
;
case
wr_adr_d0
(
16
downto
13
)
is
when
"1000"
=>
-- Memory sram
sram_wr_o
<=
sram_we
;
wr_ack_int
<=
sram_we
;
when
"1001"
=>
case
wr_adr_d0
(
12
downto
2
)
is
when
"00000000000"
=>
-- Reg mailboxes_mboxout
mailboxes_mboxout_wreq
<=
wr_req_d0
;
wr_ack_int
<=
wr_req_d0
;
when
"00000000001"
=>
-- Reg mailboxes_mboxin
wr_ack_int
<=
wr_req_d0
;
when
"00000000010"
=>
-- Reg mailboxes_status
wr_ack_int
<=
wr_req_d0
;
when
"00000000100"
=>
-- Reg presence
wr_ack_int
<=
wr_req_d0
;
when
"00000001000"
=>
-- Reg loops_pins_0
wr_ack_int
<=
wr_req_d0
;
when
"00000001001"
=>
-- Reg loops_pins_1
wr_ack_int
<=
wr_req_d0
;
when
"00000001010"
=>
-- Reg loops_pins_2
wr_ack_int
<=
wr_req_d0
;
when
"00000001011"
=>
-- Reg loops_pins_3
wr_ack_int
<=
wr_req_d0
;
when
"00000001100"
=>
-- Reg loops_pins_4
wr_ack_int
<=
wr_req_d0
;
when
"00000001101"
=>
-- Reg loops_pins_5
wr_ack_int
<=
wr_req_d0
;
when
"00000001110"
=>
-- Reg loops_pins_6
wr_ack_int
<=
wr_req_d0
;
when
"00000001111"
=>
-- Reg loops_pins_7
wr_ack_int
<=
wr_req_d0
;
when
"00000010000"
=>
-- Reg relays_pins_0
relays_pins_0_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_0_wack
;
when
"00000010001"
=>
-- Reg relays_pins_1
relays_pins_1_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_1_wack
;
when
"00000010010"
=>
-- Reg relays_pins_2
relays_pins_2_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_2_wack
;
when
"00000010011"
=>
-- Reg relays_pins_3
relays_pins_3_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_3_wack
;
when
"00000010100"
=>
-- Reg relays_pins_4
relays_pins_4_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_4_wack
;
when
"00000010101"
=>
-- Reg relays_pins_5
relays_pins_5_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_5_wack
;
when
"00000010110"
=>
-- Reg relays_pins_6
relays_pins_6_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_6_wack
;
when
"00000010111"
=>
-- Reg relays_pins_7
relays_pins_7_wreq
<=
wr_req_d0
;
wr_ack_int
<=
relays_pins_7_wack
;
when
others
=>
wr_ack_int
<=
wr_req_d0
;
end
case
;
when
others
=>
wr_ack_int
<=
wr_req_d0
;
end
case
;
end
process
;
-- Process for read requests.
process
(
adr_int
,
rd_req_int
,
mailboxes_mboxin_i
,
mailboxes_status_mbin_i
,
mailboxes_status_mbout_i
,
presence_en_i
,
loops_pins_0_i
,
loops_pins_1_i
,
loops_pins_2_i
,
loops_pins_3_i
,
loops_pins_4_i
,
loops_pins_5_i
,
loops_pins_6_i
,
loops_pins_7_i
,
relays_pins_0_reg
,
relays_pins_1_reg
,
relays_pins_2_reg
,
relays_pins_3_reg
,
relays_pins_4_reg
,
relays_pins_5_reg
,
relays_pins_6_reg
,
relays_pins_7_reg
)
begin
process
(
adr_int
,
sram_data_i
,
sram_rack
,
rd_req_int
,
mailboxes_mboxin_i
,
mailboxes_status_mbin_i
,
mailboxes_status_mbout_i
,
presence_en_i
,
loops_pins_0_i
,
loops_pins_1_i
,
loops_pins_2_i
,
loops_pins_3_i
,
loops_pins_4_i
,
loops_pins_5_i
,
loops_pins_6_i
,
loops_pins_7_i
,
relays_pins_0_reg
,
relays_pins_1_reg
,
relays_pins_2_reg
,
relays_pins_3_reg
,
relays_pins_4_reg
,
relays_pins_5_reg
,
relays_pins_6_reg
,
relays_pins_7_reg
)
begin
-- By default ack read requests
rd_dat_d0
<=
(
others
=>
'X'
);
sram_re
<=
'0'
;
mailboxes_mboxin_rd_o
<=
'0'
;
case
adr_int
(
6
downto
2
)
is
when
"00000"
=>
-- Reg mailboxes_mboxout
rd_ack_d0
<=
rd_req_int
;
when
"00001"
=>
-- Reg mailboxes_mboxin
mailboxes_mboxin_rd_o
<=
rd_req_int
;
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
mailboxes_mboxin_i
;
when
"00010"
=>
-- Reg mailboxes_status
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
(
0
)
<=
mailboxes_status_mbin_i
;
rd_dat_d0
(
1
)
<=
mailboxes_status_mbout_i
;
rd_dat_d0
(
31
downto
2
)
<=
(
others
=>
'0'
);
when
"00100"
=>
-- Reg presence
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
(
7
downto
0
)
<=
presence_en_i
;
rd_dat_d0
(
31
downto
8
)
<=
(
others
=>
'0'
);
when
"01000"
=>
-- Reg loops_pins_0
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_0_i
;
when
"01001"
=>
-- Reg loops_pins_1
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_1_i
;
when
"01010"
=>
-- Reg loops_pins_2
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_2_i
;
when
"01011"
=>
-- Reg loops_pins_3
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_3_i
;
when
"01100"
=>
-- Reg loops_pins_4
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_4_i
;
when
"01101"
=>
-- Reg loops_pins_5
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_5_i
;
when
"01110"
=>
-- Reg loops_pins_6
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_6_i
;
when
"01111"
=>
-- Reg loops_pins_7
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_7_i
;
when
"10000"
=>
-- Reg relays_pins_0
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_0_reg
;
when
"10001"
=>
-- Reg relays_pins_1
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_1_reg
;
when
"10010"
=>
-- Reg relays_pins_2
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_2_reg
;
when
"10011"
=>
-- Reg relays_pins_3
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_3_reg
;
when
"10100"
=>
-- Reg relays_pins_4
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_4_reg
;
when
"10101"
=>
-- Reg relays_pins_5
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_5_reg
;
when
"10110"
=>
-- Reg relays_pins_6
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_6_reg
;
when
"10111"
=>
-- Reg relays_pins_7
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_7_reg
;
case
adr_int
(
16
downto
13
)
is
when
"1000"
=>
-- Memory sram
rd_dat_d0
<=
sram_data_i
;
rd_ack_d0
<=
sram_rack
;
sram_re
<=
rd_req_int
;
when
"1001"
=>
case
adr_int
(
12
downto
2
)
is
when
"00000000000"
=>
-- Reg mailboxes_mboxout
rd_ack_d0
<=
rd_req_int
;
when
"00000000001"
=>
-- Reg mailboxes_mboxin
mailboxes_mboxin_rd_o
<=
rd_req_int
;
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
mailboxes_mboxin_i
;
when
"00000000010"
=>
-- Reg mailboxes_status
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
(
0
)
<=
mailboxes_status_mbin_i
;
rd_dat_d0
(
1
)
<=
mailboxes_status_mbout_i
;
rd_dat_d0
(
31
downto
2
)
<=
(
others
=>
'0'
);
when
"00000000100"
=>
-- Reg presence
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
(
7
downto
0
)
<=
presence_en_i
;
rd_dat_d0
(
31
downto
8
)
<=
(
others
=>
'0'
);
when
"00000001000"
=>
-- Reg loops_pins_0
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_0_i
;
when
"00000001001"
=>
-- Reg loops_pins_1
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_1_i
;
when
"00000001010"
=>
-- Reg loops_pins_2
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_2_i
;
when
"00000001011"
=>
-- Reg loops_pins_3
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_3_i
;
when
"00000001100"
=>
-- Reg loops_pins_4
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_4_i
;
when
"00000001101"
=>
-- Reg loops_pins_5
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_5_i
;
when
"00000001110"
=>
-- Reg loops_pins_6
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_6_i
;
when
"00000001111"
=>
-- Reg loops_pins_7
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
loops_pins_7_i
;
when
"00000010000"
=>
-- Reg relays_pins_0
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_0_reg
;
when
"00000010001"
=>
-- Reg relays_pins_1
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_1_reg
;
when
"00000010010"
=>
-- Reg relays_pins_2
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_2_reg
;
when
"00000010011"
=>
-- Reg relays_pins_3
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_3_reg
;
when
"00000010100"
=>
-- Reg relays_pins_4
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_4_reg
;
when
"00000010101"
=>
-- Reg relays_pins_5
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_5_reg
;
when
"00000010110"
=>
-- Reg relays_pins_6
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_6_reg
;
when
"00000010111"
=>
-- Reg relays_pins_7
rd_ack_d0
<=
rd_req_int
;
rd_dat_d0
<=
relays_pins_7_reg
;
when
others
=>
rd_ack_d0
<=
rd_req_int
;
end
case
;
when
others
=>
rd_ack_d0
<=
rd_req_int
;
end
case
;
...
...
hdl/syn/diot_urv_demo/top_sim.vhdl
View file @
cc8ba521
...
...
@@ -134,21 +134,24 @@ begin
x"14"
,
x"00"
,
x"10"
,
x"00"
,
others
=>
x"00"
),
-- Second command: load plc
1
=>
(
x"10"
,
x"2f"
,
x"00"
,
x"00"
,
x"00"
,
x"20"
,
x"10"
,
x"00"
,
x"93"
,
x"01"
,
x"00"
,
x"0
3"
,
1
=>
(
x"10"
,
x"2f"
,
x"00"
,
x"00"
,
-- Load block
x"00"
,
x"20"
,
x"10"
,
x"00"
,
-- In plc RAM
x"93"
,
x"01"
,
x"00"
,
x"0
4"
,
-- plc_demo code
x"17"
,
x"01"
,
x"01"
,
x"00"
,
x"13"
,
x"01"
,
x"c1"
,
x"3f"
,
x"ef"
,
x"00"
,
x"c0"
,
x"00"
,
x"ef"
,
x"00"
,
x"
c
0"
,
x"01"
,
x"ef"
,
x"00"
,
x"
4
0"
,
x"01"
,
x"6f"
,
x"f0"
,
x"df"
,
x"ff"
,
x"b7"
,
x"57"
,
x"34"
,
x"12"
,
x"37"
,
x"07"
,
x"10"
,
x"00"
,
x"93"
,
x"87"
,
x"87"
,
x"67"
,
x"23"
,
x"20"
,
x"f7"
,
x"00"
,
x"67"
,
x"80"
,
x"00"
,
x"00"
,
x"b7"
,
x"07"
,
x"10"
,
x"00"
,
x"23"
,
x"a8"
,
x"07"
,
x"04"
,
x"67"
,
x"80"
,
x"00"
,
x"00"
,
others
=>
x"00"
),
x"37"
,
x"07"
,
x"10"
,
x"00"
,
x"83"
,
x"27"
,
x"07"
,
x"03"
,
x"93"
,
x"f7"
,
x"17"
,
x"00"
,
x"b3"
,
x"07"
,
x"f0"
,
x"40"
,
x"93"
,
x"f7"
,
x"e7"
,
x"ff"
,
x"23"
,
x"28"
,
x"f7"
,
x"04"
,
x"6f"
,
x"f0"
,
x"df"
,
x"fe"
),
-- Third command: deassert plc reset
2
=>
(
x"01"
,
x"4b"
,
x"00"
,
x"00"
,
x"00"
,
x"00"
,
x"10"
,
x"00"
,
...
...
hdl/top/diot_urv_demo/diot_urv_top.vhd
View file @
cc8ba521
...
...
@@ -31,6 +31,7 @@ use ieee.std_logic_1164.all;
use
ieee
.
numeric_std
.
all
;
use
work
.
wishbone_pkg
.
all
;
use
work
.
genram_pkg
.
all
;
library
proasic3e
;
use
proasic3e
.
all
;
...
...
@@ -156,6 +157,11 @@ architecture rtl of diot_urv_top is
signal
wb_plc_in
:
t_wishbone_slave_in
;
signal
wb_plc_out
:
t_wishbone_slave_out
;
signal
plc_sram_addr
:
std_logic_vector
(
12
downto
2
);
signal
plc_sram_dato
:
std_logic_vector
(
31
downto
0
);
signal
plc_sram_dati
:
std_logic_vector
(
31
downto
0
);
signal
plc_sram_wr
:
std_logic
;
-- MEM bus for FIP cpu to write into PLC memory.
signal
wb_mem_in
:
t_wishbone_slave_in
;
signal
wb_mem_out
:
t_wishbone_slave_out
;
...
...
@@ -388,19 +394,25 @@ begin
cyc_o
<=
'0'
;
stb_o
<=
'0'
;
we_o
<=
'0'
;
fip_ack
<=
'0'
;
else
cyc_o
<=
fip_cyc
;
stb_o
<=
fip_stb
;
we_o
<=
fip_we
;
dat_o
<=
fip_dato
;
adr_o
<=
fip_adr
;
fip_ack
<=
ack_i
;
fip_dati
<=
dat_i
;
end
if
;
end
if
;
end
process
;
inst_fip_ack
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk_2
,
rst_n_a_i
=>
rst_n
,
d_i
=>
ack_i
,
q_o
=>
fip_ack
);
wclk_o
<=
clk_2
;
rst_o
<=
not
rst_n
;
...
...
@@ -417,8 +429,7 @@ begin
inst_plc_urv
:
entity
work
.
plc_urv
generic
map
(
g_iram_log_size
=>
10
,
g_dram_log_size
=>
12
g_iram_log_size
=>
10
)
port
map
(
clk_sys_i
=>
clk
,
...
...
@@ -435,6 +446,10 @@ begin
clk_i
=>
clk
,
wb_i
=>
wb_plc_in
,
wb_o
=>
wb_plc_out
,
sram_addr_o
=>
plc_sram_addr
,
sram_data_i
=>
plc_sram_dati
,
sram_data_o
=>
plc_sram_dato
,
sram_wr_o
=>
plc_sram_wr
,
mailboxes_mboxout_o
=>
mbox_in_dat
,
mailboxes_mboxout_wr_o
=>
mbox_in_wr
,
mailboxes_mboxin_i
=>
mbox_out_reg
,
...
...
@@ -466,30 +481,112 @@ begin
relays_pins_6_o
=>
open
,
relays_pins_7_o
=>
open
);
p_ram
:
process
(
clk
)
is
constant
c_DRAM_LOG_SIZE
:
natural
:
=
12
;
variable
mem
:
t_ram32_type
(
2
**
(
c_DRAM_LOG_SIZE
-
2
)
-
1
downto
0
);
variable
addr
:
natural
range
mem
'range
;
begin
if
rising_edge
(
clk
)
then
addr
:
=
to_integer
(
unsigned
(
plc_sram_addr
(
c_DRAM_LOG_SIZE
-
1
downto
2
)));
plc_sram_dati
<=
mem
(
addr
);
if
plc_sram_wr
=
'1'
then
for
i
in
0
to
3
loop
if
true
then
-- if reg_dm_data_select (i) = '1' then
mem
(
addr
)(
8
*
i
+
7
downto
8
*
i
)
:
=
plc_sram_dato
(
8
*
i
+
7
downto
8
*
i
);
end
if
;
end
loop
;
end
if
;
end
if
;
end
process
;
-------------------------------------------------------------------------------
GEN_REAL_IO
:
block
begin
-- slots assignment
slots_loops
(
0
)(
15
downto
0
)
<=
s1_p_b
(
15
downto
0
);
slots_loops
(
1
)(
13
downto
0
)
<=
s2_p_b
(
13
downto
0
);
slots_loops
(
2
)(
13
downto
0
)
<=
s3_p_b
(
13
downto
0
);
slots_loops
(
3
)(
8
downto
0
)
<=
s4_p_b
(
13
downto
6
)
&
s4_p_b
(
3
);
slots_loops
(
4
)(
13
downto
0
)
<=
s5_p_b
(
13
downto
0
);
slots_loops
(
5
)(
15
downto
0
)
<=
s7_p_b
(
15
downto
0
);
gen_slots_0
:
for
i
in
15
downto
0
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s1_p_b
(
i
),
q_o
=>
slots_loops
(
0
)(
i
)
);
end
generate
;
slots_loops
(
0
)(
31
downto
16
)
<=
(
others
=>
'0'
);
gen_slots_1
:
for
i
in
13
downto
0
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s2_p_b
(
i
),
q_o
=>
slots_loops
(
1
)(
i
)
);
end
generate
;
slots_loops
(
1
)(
31
downto
14
)
<=
(
others
=>
'0'
);
gen_slots_2
:
for
i
in
13
downto
0
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s3_p_b
(
i
),
q_o
=>
slots_loops
(
2
)(
i
)
);
end
generate
;
slots_loops
(
2
)(
31
downto
14
)
<=
(
others
=>
'0'
);
gen_slots_3
:
for
i
in
13
downto
6
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s4_p_b
(
i
),
q_o
=>
slots_loops
(
3
)(
i
)
);
end
generate
;
inst_slots_3_3
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s4_p_b
(
3
),
q_o
=>
slots_loops
(
3
)(
3
)
);
slots_loops
(
3
)(
31
downto
14
)
<=
(
others
=>
'0'
);
slots_loops
(
3
)(
5
downto
4
)
<=
(
others
=>
'0'
);
slots_loops
(
3
)(
2
downto
0
)
<=
(
others
=>
'0'
);
gen_slots_4
:
for
i
in
13
downto
0
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s5_p_b
(
i
),
q_o
=>
slots_loops
(
4
)(
i
)
);
end
generate
;
slots_loops
(
4
)(
31
downto
14
)
<=
(
others
=>
'0'
);
gen_slots_5
:
for
i
in
15
downto
0
generate
inst_sync
:
entity
work
.
gc_sync
port
map
(
clk_i
=>
clk
,
rst_n_a_i
=>
rst_n
,
d_i
=>
s7_p_b
(
i
),
q_o
=>
slots_loops
(
5
)(
i
)
);
end
generate
;
slots_loops
(
5
)(
31
downto
16
)
<=
(
others
=>
'0'
);
s1_n_b
(
15
downto
0
)
<=
slots_relays
(
0
)(
15
downto
0
);
s2_n_b
(
13
downto
0
)
<=
slots_relays
(
1
)(
13
downto
0
);
s3_n_b
(
13
downto
0
)
<=
slots_relays
(
2
)(
13
downto
0
);
s4_n_b
(
13
downto
6
)
<=
slots_relays
(
3
)(
8
downto
1
);
s4_n_b
(
3
)
<=
slots_relays
(
3
)(
0
);
s4_n_b
(
13
downto
6
)
<=
slots_relays
(
3
)(
13
downto
6
);
s4_n_b
(
3
)
<=
slots_relays
(
3
)(
3
);
s5_n_b
(
13
downto
0
)
<=
slots_relays
(
4
)(
13
downto
0
);
s7_n_b
(
15
downto
0
)
<=
slots_relays
(
5
)(
15
downto
0
);
-- not used loops
slots_loops
(
0
)(
31
downto
16
)
<=
(
others
=>
'0'
);
slots_loops
(
1
)(
31
downto
14
)
<=
(
others
=>
'0'
);
slots_loops
(
2
)(
31
downto
14
)
<=
(
others
=>
'0'
);
slots_loops
(
3
)(
31
downto
9
)
<=
(
others
=>
'0'
);
slots_loops
(
4
)(
31
downto
14
)
<=
(
others
=>
'0'
);
end
block
;
-- Leds: assign to '0' to switch on the led, 'Z' to switch off.
...
...
sw/plc_urv/Makefile
View file @
cc8ba521
...
...
@@ -9,7 +9,7 @@ SIZE = $(CROSS_COMPILE)size
PROG
=
plc_mbox
CFLAGS
=
-mabi
=
ilp32
-march
=
rv32im
-Os
-Wall
CFLAGS
=
-mabi
=
ilp32
-march
=
rv32im
-Os
-Wall
-ffreestanding
-fno-delete-null-pointer-checks
OBJS
=
crt0.o
$(PROG)
.o
LDS
=
plc.ld
...
...
sw/plc_urv/plc.ld
View file @
cc8ba521
...
...
@@ -8,7 +8,7 @@ MEMORY
LENGTH = 1024
bss :
ORIGIN = 0x00010000,
LENGTH =
2048
LENGTH =
4096
/* Sorry, but there is no initialized ram. */
empty :
...
...
sw/plc_urv/plc_demo.c
View file @
cc8ba521
...
...
@@ -7,7 +7,7 @@ void
init
(
void
)
{
volatile
struct
plc_urv_regs
*
regs
=
(
volatile
struct
plc_urv_regs
*
)
0x
1
00000
;
(
volatile
struct
plc_urv_regs
*
)
0x00000
;
regs
->
relays
.
SLOT
=
0
;
}
...
...
@@ -16,9 +16,11 @@ void
main
(
void
)
{
volatile
struct
plc_urv_regs
*
regs
=
(
volatile
struct
plc_urv_regs
*
)
0x
1
00000
;
(
volatile
struct
plc_urv_regs
*
)
0x00000
;
while
(
1
)
{
unsigned
v
=
regs
->
loops
.
SLOT
;
regs
->
relays
.
SLOT
=
-
(
v
&
1
)
&
(
~
1
);
}
}
sw/plc_urv/plc_urv_regs.h
View file @
cc8ba521
...
...
@@ -2,87 +2,103 @@
#define __CHEBY__PLC_URV_REGS__H__
#include "mbox_regs.h"
#define PLC_URV_REGS_SIZE
96
#define PLC_URV_REGS_SIZE
73824
/* None */
#define PLC_URV_REGS_MAILBOXES 0x0UL
#define PLC_URV_REGS_SRAM 0x10000UL
#define PLC_URV_REGS_SRAM_SIZE 4
/* None */
#define PLC_URV_REGS_SRAM_VALUE 0x0UL
/* None */
#define PLC_URV_REGS_MAILBOXES 0x12000UL
#define PLC_URV_REGS_MAILBOXES_SIZE 16
/* presence lines for boards */
#define PLC_URV_REGS_PRESENCE 0x10UL
#define PLC_URV_REGS_PRESENCE 0x1
201
0UL
#define PLC_URV_REGS_PRESENCE_EN_MASK 0xffUL
#define PLC_URV_REGS_PRESENCE_EN_SHIFT 0
/* None */
#define PLC_URV_REGS_LOOPS 0x20UL
#define PLC_URV_REGS_LOOPS 0x
120
20UL
#define PLC_URV_REGS_LOOPS_SIZE 32
/* None */
#define PLC_URV_REGS_LOOPS_PINS_0 0x20UL
#define PLC_URV_REGS_LOOPS_PINS_0 0x
120
20UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_1 0x24UL
#define PLC_URV_REGS_LOOPS_PINS_1 0x
120
24UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_2 0x28UL
#define PLC_URV_REGS_LOOPS_PINS_2 0x
120
28UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_3 0x2cUL
#define PLC_URV_REGS_LOOPS_PINS_3 0x
120
2cUL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_4 0x30UL
#define PLC_URV_REGS_LOOPS_PINS_4 0x
120
30UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_5 0x34UL
#define PLC_URV_REGS_LOOPS_PINS_5 0x
120
34UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_6 0x38UL
#define PLC_URV_REGS_LOOPS_PINS_6 0x
120
38UL
/* None */
#define PLC_URV_REGS_LOOPS_PINS_7 0x3cUL
#define PLC_URV_REGS_LOOPS_PINS_7 0x
120
3cUL
/* None */
#define PLC_URV_REGS_RELAYS 0x40UL
#define PLC_URV_REGS_RELAYS 0x
120
40UL
#define PLC_URV_REGS_RELAYS_SIZE 32
/* None */
#define PLC_URV_REGS_RELAYS_PINS_0 0x40UL
#define PLC_URV_REGS_RELAYS_PINS_0 0x
120
40UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_1 0x44UL
#define PLC_URV_REGS_RELAYS_PINS_1 0x
120
44UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_2 0x48UL
#define PLC_URV_REGS_RELAYS_PINS_2 0x
120
48UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_3 0x4cUL
#define PLC_URV_REGS_RELAYS_PINS_3 0x
120
4cUL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_4 0x50UL
#define PLC_URV_REGS_RELAYS_PINS_4 0x
120
50UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_5 0x54UL
#define PLC_URV_REGS_RELAYS_PINS_5 0x
120
54UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_6 0x58UL
#define PLC_URV_REGS_RELAYS_PINS_6 0x
120
58UL
/* None */
#define PLC_URV_REGS_RELAYS_PINS_7 0x5cUL
#define PLC_URV_REGS_RELAYS_PINS_7 0x
120
5cUL
struct
plc_urv_regs
{
/* [0x0]: SUBMAP (no description) */
/* padding to: 16384 words */
uint32_t
__padding_0
[
16384
];
/* [0x10000]: MEMORY (no description) */
struct
sram
{
/* [0x0]: REG (rw) (no description) */
uint32_t
value
;
}
sram
[
2048
];
/* [0x12000]: SUBMAP (no description) */
struct
mbox_regs
mailboxes
;
/* padding to:
4
words */
uint32_t
__padding_
0
[
1
];
/* padding to:
18436
words */
uint32_t
__padding_
1
[
1
];
/* [0x10]: REG (ro) presence lines for boards */
/* [0x1
201
0]: REG (ro) presence lines for boards */
uint32_t
presence
;
/* padding to:
8
words */
uint32_t
__padding_
1
[
3
];
/* padding to:
18440
words */
uint32_t
__padding_
2
[
3
];
/* [0x20]: BLOCK (no description) */
/* [0x
120
20]: BLOCK (no description) */
struct
loops
{
/* [0x0]: REG (ro) (no description) */
uint32_t
pins_0
;
...
...
@@ -109,7 +125,7 @@ struct plc_urv_regs {
uint32_t
pins_7
;
}
loops
;
/* [0x40]: BLOCK (no description) */
/* [0x
120
40]: BLOCK (no description) */
struct
relays
{
/* [0x0]: REG (rw) (no description) */
uint32_t
pins_0
;
...
...
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