Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
TTool
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
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
mbe-tools
TTool
Commits
0f36d8c3
Commit
0f36d8c3
authored
8 years ago
by
Daniela Genius
Browse files
Options
Downloads
Patches
Plain Diff
update on mapping table
parent
eaad7d66
No related branches found
No related tags found
No related merge requests found
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
src/ddtranslatorSoclib/toTopCell/MappingTable.java
+26
-94
26 additions, 94 deletions
src/ddtranslatorSoclib/toTopCell/MappingTable.java
src/ddtranslatorSoclib/toTopCell/NetList.java
+6
-18
6 additions, 18 deletions
src/ddtranslatorSoclib/toTopCell/NetList.java
with
32 additions
and
112 deletions
src/ddtranslatorSoclib/toTopCell/MappingTable.java
+
26
−
94
View file @
0f36d8c3
...
@@ -64,58 +64,54 @@ public class MappingTable {
...
@@ -64,58 +64,54 @@ public class MappingTable {
int
j
=
0
;
int
i
=
0
;
int
j
=
0
;
int
i
=
0
;
int
size
;
int
size
;
//if(TopCellGenerator.avatardd.getAllCrossbar().size()==0){
//if(TopCellGenerator.avatardd.getAllCrossbar().size()==0){
for
(
AvatarRAM
ram
:
TopCellGenerator
.
avatardd
.
getAllRAM
())
{
for
(
AvatarRAM
ram
:
TopCellGenerator
.
avatardd
.
getAllRAM
())
{
if
(
ram
.
getDataSize
()==
0
){
// if no data size is given calculate default data size
if
(
ram
.
getDataSize
()==
0
){
if
((
nb_clusters
<
16
)||(
TopCellGenerator
.
avatardd
.
getAllRAM
().
size
()<
16
)){
if
((
nb_clusters
<
16
)||(
TopCellGenerator
.
avatardd
.
getAllRAM
().
size
()<
16
)){
size
=
1073741824
;
size
=
1073741824
;
}
}
else
{
//
smaller segments
else
{
//
dimension segments to be smaller
size
=
268435456
;
size
=
268435456
;
}
// to be refined, a la DSX
}
}
}
else
{
else
{
size
=
ram
.
getDataSize
();
size
=
ram
.
getDataSize
();
}
}
ram
.
setDataSize
(
size
);
ram
.
setDataSize
(
size
);
//ram.setDataSize(0);
size
=
ram
.
getDataSize
();
// this is the hardware RAM size
size
=
ram
.
getDataSize
();
// this is the hardware RAM size
int
cacheability_bit
=
2097152
;
//0x00200000
int
step
=
268435456
;
// DG 11.10. attention cacheability bit, cannot take any size given in DD, must be checked, toDo
int
cacheability_bit
=
2097152
;
//0x00200000
/* Boot Ram segments 0,1,2 */
/* Boot Ram segments 0,1,2 */
if
(
ram
.
getNo_ram
()
==
0
){
if
(
ram
.
getNo_ram
()
==
0
){
ram
.
setNo_target
(
2
);
//in the following assign target number 2
ram
.
setNo_target
(
2
);
//in the following assign target number 2
//mapping += "maptab.add(Segment(\"cram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0000000, 0x00100000, IntTab("+(ram.getNo_target())+"), true));" + CR;
//mapping += "maptab.add(Segment(\"uram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0200000, 0x00100000, IntTab("+(ram.getNo_target())+"), false));" + CR;
/* mapping += "maptab.add(Segment(\"cram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0000000, "+ram.getDataSize()+", IntTab("+(ram.getNo_target())+"), true));" + CR;
mapping += "maptab.add(Segment(\"uram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0200000, "+ram.getDataSize()+", IntTab("+(ram.getNo_target())+"), false));" + CR;*/
mapping
+=
"maptab.add(Segment(\"cram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
size
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), true));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"cram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
step
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), true));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"uram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
size
+
cacheability_bit
+
ram
.
getDataSize
()/
2
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), false));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"uram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
step
+
cacheability_bit
+
ram
.
getDataSize
()/
2
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), false));"
+
CR
;
i
++;
}
}
else
{
else
{
ram
.
setNo_target
(
7
+
j
);
ram
.
setNo_target
(
7
+
j
);
//mapping += "maptab.add(Segment(\"cram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0000000, 0x00100000, IntTab("+(ram.getNo_target())+"), true));" + CR;
//mapping += "maptab.add(Segment(\"uram" + ram.getNo_ram() + "\", 0x" +(ram.getNo_ram()+1)+ "0200000, 0x00100000, IntTab("+(ram.getNo_target())+"), false));" + CR;
mapping
+=
"maptab.add(Segment(\"cram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
step
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), true));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"cram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
size
)+
", 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), true));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"uram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
step
+
ram
.
getDataSize
()/
2
+
cacheability_bit
)
+
" , 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), false));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"uram"
+
ram
.
getNo_ram
()
+
"\", 0x"
+
Integer
.
toHexString
(
address_start
+
i
*
size
+
size
/
2
+
cacheability_bit
)
+
" , 0x"
+
Integer
.
toHexString
(
ram
.
getDataSize
()/
2
)+
", IntTab("
+(
ram
.
getNo_target
())+
"), false));"
+
CR
;
j
++;
i
++;
j
++;
}
}
i
++;
}
}
int
m
=
0
;
int
m
=
0
;
for
(
AvatarTTY
tty
:
TopCellGenerator
.
avatardd
.
getAllTTY
())
{
for
(
AvatarTTY
tty
:
TopCellGenerator
.
avatardd
.
getAllTTY
())
{
/* we calculate the target number of one or several (multi-) ttys which come after the j rams and the 7 compulsory targets */
/* we calculate the target number of one or several (multi-) ttys which come after the j rams and the 7 compulsory targets */
tty
.
setNo_target
(
7
+
j
);
tty
.
setNo_target
(
7
+
j
);
/* we use a simple formula for calculating the TTY address in case of multiple (multi-) ttys */
/* we use a simple formula for calculating the TTY address in case of multiple (multi-) ttys */
/* attention this will not work for more than 10 TTYs */
/* attention this will not work for more than 10 TTYs */
mapping
+=
"maptab.add(Segment(\"vci_multi_tty"
+
m
+
"\" , 0xd"
+
tty
.
getNo_tty
()+
"200000, 0x00000010, IntTab("
+
tty
.
getNo_target
()
+
"), false));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"vci_multi_tty"
+
m
+
"\" , 0xd"
+
tty
.
getNo_tty
()+
"200000, 0x00000010, IntTab("
+
tty
.
getNo_target
()
+
"), false));"
+
CR
;
// mapping += "maptab.add(Segment(\"vci_multi_tty"+m+"\" , 0xe"+(m+1)+"200000, 0x00000010, IntTab(" +tty.getNo_target() +"), false));" + CR;
j
++;
j
++;
m
++;
m
++;
...
@@ -126,50 +122,10 @@ public class MappingTable {
...
@@ -126,50 +122,10 @@ public class MappingTable {
mapping
=
mapping
+
"maptab.add(Segment(\"vci_ethernet\", 0xd5000000, 0x00000020, IntTab("
+(
l
+
2
)+
"), false));"
+
CR
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_ethernet\", 0xd5000000, 0x00000020, IntTab("
+(
l
+
2
)+
"), false));"
+
CR
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_block_device\", 0xd1200000, 0x00000020, IntTab("
+(
l
+
3
)+
"), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_block_device\", 0xd1200000, 0x00000020, IntTab("
+(
l
+
3
)+
"), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_locks\", 0xC0200000, 0x00000100, IntTab("
+(
l
+
4
)+
"), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_locks\", 0xC0200000, 0x00000100, IntTab("
+(
l
+
4
)+
"), false));"
+
CR2
;
// mapping = mapping + "maptab.add(Segment(\"mwmr_ram\", 0xA0200000, 0x00001000, IntTab("+(l+5)+"), false));" + CR2;
//mapping = mapping + "maptab.add(Segment(\"mwmrd_ram\", 0xB0200000, 0x00003000, IntTab("+(l+6)+"), false));" + CR2;
//DG 29.08.
// mapping = mapping + "maptab.add(Segment(\"cram\", 0xA0200000, 0x00001000, IntTab("+(l+5)+"), true));" + CR2;
//mapping = mapping + "maptab.add(Segment(\"uram\", 0xB0200000, 0x00003000, IntTab("+(l+6)+"), false));" + CR2;
return
mapping
;
return
mapping
;
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
// Mapping Table //
// There are 4 replicated segments in each cluster, and 8 single (not replicated) segments. //
// - Peripheral single segments (rom, ramdac, tg) are mapped in the cluster_rom and cluster_io. //
// - RAM single segments are mapped in each cluster at the first addresse of the cluster. //
// - Peripherals replicated segments (timer, icu, dma) are replicated in each cluster. //
///////////////////////////////////////////////////////////////////////////////////////////////////
/* MappingTable maptab(32, IntTab(8,4), IntTab(8,4), 0xFFFF0000);
maptab.add(Segment("seg_ie" , SEG_IE_BASE , SEG_IE_SIZE , IntTab(cluster_io , TGTID_IE), false));
maptab.add(Segment("seg_oe", SEG_OE_BASE, SEG_OE_SIZE, IntTab(cluster_io , TGTID_OE), false));
maptab.add(Segment("seg_tty" , SEG_TTY_BASE , SEG_TTY_SIZE , IntTab(cluster_io , TGTID_TTY), false));
maptab.add(Segment("seg_reset" , SEG_RESET_BASE , SEG_RESET_SIZE , IntTab(cluster_rom, tgtid_rom), true));
for (size_t c = 0; c < nc; c++) {
uint32_t ram_base = SEG_RAM_BASE + c * CLUSTER_SIZE;
uint32_t ram_size = SEG_RAM_SIZE;
std::ostringstream seg_ram_name;
seg_ram_name << "seg_ram_" << c;
maptab.add(Segment(seg_ram_name.str(), ram_base, ram_size, IntTab(c, TGTID_RAM), true));
uint32_t timer_base = SEG_TIM_BASE + c * CLUSTER_SIZE;
uint32_t timer_size = SEG_TIM_SIZE;
std::ostringstream seg_timer_name;
seg_timer_name << "seg_timer_" << c;
maptab.add(Segment(seg_timer_name.str(), timer_base, timer_size, IntTab(c, TGTID_TIM), true));
uint32_t icu_base = SEG_ICU_BASE + c * CLUSTER_SIZE;
uint32_t icu_size = SEG_ICU_SIZE;
std::ostringstream seg_icu_name;
seg_icu_name << "seg_icu_" << c;
maptab.add(Segment(seg_icu_name.str(), icu_base, icu_size, IntTab(c, TGTID_ICU), false)); */
else
{
else
{
/* clustered version */
/* clustered version */
...
@@ -188,31 +144,7 @@ public class MappingTable {
...
@@ -188,31 +144,7 @@ public class MappingTable {
mapping
=
mapping
+
"maptab.add(Segment(\"vci_ethernet\", 0x18200000, 0x00000020, IntTab(0,6), false));"
+
CR
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_ethernet\", 0x18200000, 0x00000020, IntTab(0,6), false));"
+
CR
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_block_device\", 0x19200000, 0x00000020, IntTab(0,7), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_block_device\", 0x19200000, 0x00000020, IntTab(0,7), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_locks\", 0x1A200000, 0x00000020, IntTab(0,8), false));"
+
CR2
;
mapping
=
mapping
+
"maptab.add(Segment(\"vci_locks\", 0x1A200000, 0x00000020, IntTab(0,8), false));"
+
CR2
;
// uint32_t ram_base = SEG_RAM_BASE + c * CLUSTER_SIZE;
// soft/hard_config.h:#define CLUSTER_SIZE 0x40000000
// int SEG_RAM_BASE = 0x10000000;
//the following three components are added transparently in the deployment diagram
/* int SEG_ICU_BASE = 0x11000000;
int SEG_ICU_SIZE = 0x00000014;
int NB_DMAS = 1;
int SEG_DMA_BASE = 0x12200000;
int SEG_DMA_SIZE = (NB_DMAS * 0x00000014);
int NB_TIMERS = 1;
int SEG_TIM_BASE = 0x13000000;
int SEG_TIM_SIZE = (NB_TIMERS * 16 );
int SEG_TTY_BASE = 0x14200000;
int SEG_TTY_SIZE = 0x00000010;
int CLUSTER_SIZE = 0x40000000;*/
int
SEG_ICU_BASE
=
285212672
;
int
SEG_ICU_BASE
=
285212672
;
int
SEG_ICU_SIZE
=
20
;
int
SEG_ICU_SIZE
=
20
;
...
@@ -236,7 +168,7 @@ public class MappingTable {
...
@@ -236,7 +168,7 @@ public class MappingTable {
CLUSTER_SIZE
=
134217728
;
CLUSTER_SIZE
=
134217728
;
}
// to be refined, cf DSX -> dynamically adapt
}
// to be refined, cf DSX -> dynamically adapt
/* RAM adresses always start at 0x10000000 dec 268435456*/
/* RAM adresses always start at 0x10000000 dec
imal
268435456*/
int
SEG_RAM_BASE
=
268435456
;
int
SEG_RAM_BASE
=
268435456
;
int
cluster
=
0
;
int
cluster
=
0
;
...
@@ -250,7 +182,7 @@ mapping += "maptab.add(Segment(\"dma\", 0x"+ Integer.toHexString(SEG_DMA_BASE)+"
...
@@ -250,7 +182,7 @@ mapping += "maptab.add(Segment(\"dma\", 0x"+ Integer.toHexString(SEG_DMA_BASE)+"
mapping
+=
"maptab.add(Segment(\"vci_rttimer\", 0x"
+
Integer
.
toHexString
(
SEG_TIM_BASE
)+
", 0x"
+
Integer
.
toHexString
(
SEG_TIM_SIZE
)+
", IntTab(0,11), true));"
+
CR
;
mapping
+=
"maptab.add(Segment(\"vci_rttimer\", 0x"
+
Integer
.
toHexString
(
SEG_TIM_BASE
)+
", 0x"
+
Integer
.
toHexString
(
SEG_TIM_SIZE
)+
", IntTab(0,11), true));"
+
CR
;
// all other clusters
// all other clusters
// for(cluster=1;cluster<nb_clusters; cluster++){
// for(cluster=1;cluster<nb_clusters; cluster++){
// mapping += "maptab.add(Segment(\"icu" + cluster + "\", 0x"+ Integer.toHexString(SEG_ICU_BASE + cluster * CLUSTER_SIZE)+", 0x"+Integer.toHexString(SEG_ICU_SIZE)+", IntTab("+cluster +","+1+"), true));" + CR;
// mapping += "maptab.add(Segment(\"icu" + cluster + "\", 0x"+ Integer.toHexString(SEG_ICU_BASE + cluster * CLUSTER_SIZE)+", 0x"+Integer.toHexString(SEG_ICU_SIZE)+", IntTab("+cluster +","+1+"), true));" + CR;
...
@@ -261,7 +193,7 @@ mapping += "maptab.add(Segment(\"vci_rttimer\", 0x"+ Integer.toHexString(SEG_TIM
...
@@ -261,7 +193,7 @@ mapping += "maptab.add(Segment(\"vci_rttimer\", 0x"+ Integer.toHexString(SEG_TIM
// }
// }
int
cacheability_bit
=
2097152
;
//0x00200000
int
cacheability_bit
=
2097152
;
//0x00200000
T
/* RAM base address is SEG_RAM_BASE + CLUSTER_NUMBER * CLUSTER_SIZE;
/* RAM base address is SEG_RAM_BASE + CLUSTER_NUMBER * CLUSTER_SIZE;
this is the memory space covered by the RAMs of a cluster */
this is the memory space covered by the RAMs of a cluster */
...
...
This diff is collapsed.
Click to expand it.
src/ddtranslatorSoclib/toTopCell/NetList.java
+
6
−
18
View file @
0f36d8c3
...
@@ -139,19 +139,7 @@ public class NetList {
...
@@ -139,19 +139,7 @@ public class NetList {
else
{
else
{
netlist
=
netlist
+
"vgsb.p_to_target["
+(
ram
.
getNo_target
())+
"](signal_vci_vciram"
+
ram
.
getNo_ram
()+
");"
+
CR2
;
netlist
=
netlist
+
"vgsb.p_to_target["
+(
ram
.
getNo_target
())+
"](signal_vci_vciram"
+
ram
.
getNo_ram
()+
");"
+
CR2
;
}
}
}
}
//MWMR RAM added transparently
/* netlist = netlist +"mwmr_ram.p_clk(" + NAME_CLK + ");" + CR;
netlist = netlist +"mwmr_ram.p_resetn(" + NAME_RST + ");" + CR;
netlist = netlist +"mwmr_ram.p_vci(signal_vci_mwmr_ram);" + CR2;
netlist = netlist + "vgsb.p_to_target["+(TopCellGenerator.avatardd.getNb_target()+4)+"](signal_vci_mwmr_ram);" + CR2;
//MWMRd RAM added transparently
netlist = netlist +"mwmrd_ram.p_clk(" + NAME_CLK + ");" + CR;
netlist = netlist +"mwmrd_ram.p_resetn(" + NAME_RST + ");" + CR;
netlist = netlist +"mwmrd_ram.p_vci(signal_vci_mwmrd_ram);" + CR2;
netlist = netlist + "vgsb.p_to_target["+(TopCellGenerator.avatardd.getNb_target()+5)+"](signal_vci_mwmrd_ram);" + CR2;*/
}
}
/* clustered version */
/* clustered version */
...
@@ -351,7 +339,7 @@ public class NetList {
...
@@ -351,7 +339,7 @@ public class NetList {
}
}
//generate trace file if marked trace option
//generate trace file if marked trace option
netlist
+=
"sc_trace_file *tf;"
+
CR
;
/*
netlist += "sc_trace_file *tf;" + CR;
netlist += "tf=sc_create_vcd_trace_file(\"mytrace\");" + CR;
netlist += "tf=sc_create_vcd_trace_file(\"mytrace\");" + CR;
netlist += "sc_trace(tf,signal_clk,\"CLK\");" + CR;
netlist += "sc_trace(tf,signal_clk,\"CLK\");" + CR;
netlist += "sc_trace(tf,signal_resetn,\"RESETN\");" + CR;
netlist += "sc_trace(tf,signal_resetn,\"RESETN\");" + CR;
...
@@ -391,16 +379,16 @@ public class NetList {
...
@@ -391,16 +379,16 @@ public class NetList {
if (ram.getMonitored()==0){
if (ram.getMonitored()==0){
netlist += "sc_trace(tf,signal_vci_vciram"+ram.getNo_ram()+",\"Memory"+ram.getNo_ram()+"\");" + CR;
netlist += "sc_trace(tf,signal_vci_vciram"+ram.getNo_ram()+",\"Memory"+ram.getNo_ram()+"\");" + CR;
}
}
}
}*/
netlist
=
netlist
+
" sc_core::sc_start(sc_core::sc_time(0, sc_core::SC_NS));"
+
CR
;
netlist
=
netlist
+
" sc_core::sc_start(sc_core::sc_time(0, sc_core::SC_NS));"
+
CR
;
netlist
=
netlist
+
" signal_resetn = false;"
+
CR
;
netlist
=
netlist
+
" signal_resetn = false;"
+
CR
;
netlist
=
netlist
+
" sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_NS));"
+
CR
;
netlist
=
netlist
+
" sc_core::sc_start(sc_core::sc_time(1, sc_core::SC_NS));"
+
CR
;
netlist
=
netlist
+
" signal_resetn = true;"
+
CR
;
netlist
=
netlist
+
" signal_resetn = true;"
+
CR
;
netlist
=
netlist
+
" sc_core::sc_start();"
+
CR
;
netlist
=
netlist
+
" sc_core::sc_start();"
+
CR
;
if
(
tracing
){
//
if(tracing){
netlist
+=
"sc_close_vcd_trace_file(tf);"
+
CR
;
//
netlist += "sc_close_vcd_trace_file(tf);" + CR;
}
//
}
netlist
=
netlist
+
CR
+
" return EXIT_SUCCESS;"
+
CR
;
netlist
=
netlist
+
CR
+
" return EXIT_SUCCESS;"
+
CR
;
netlist
=
netlist
+
"}"
+
CR
;
netlist
=
netlist
+
"}"
+
CR
;
return
netlist
;
return
netlist
;
...
...
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