Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
A
abc
Overview
Overview
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
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
abc
Commits
27311713
Commit
27311713
authored
May 18, 2011
by
Alan Mishchenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Special BLIF writing (bug fixes).
parent
26fb1fcd
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
50 additions
and
49 deletions
+50
-49
src/base/io/io.c
+3
-3
src/base/io/ioWriteBlif.c
+38
-20
src/map/if/ifDec.c
+9
-26
No files found.
src/base/io/io.c
View file @
27311713
...
@@ -1559,9 +1559,9 @@ int IoCommandWriteBlif( Abc_Frame_t * pAbc, int argc, char **argv )
...
@@ -1559,9 +1559,9 @@ int IoCommandWriteBlif( Abc_Frame_t * pAbc, int argc, char **argv )
// get the output file name
// get the output file name
pFileName
=
argv
[
globalUtilOptind
];
pFileName
=
argv
[
globalUtilOptind
];
// call the corresponding file writer
// call the corresponding file writer
//
if ( fSpecial )
if
(
fSpecial
)
//
Io_WriteBlifSpecial( pAbc->pNtkCur, pFileName );
Io_WriteBlifSpecial
(
pAbc
->
pNtkCur
,
pFileName
);
//
else
else
Io_Write
(
pAbc
->
pNtkCur
,
pFileName
,
IO_FILE_BLIF
);
Io_Write
(
pAbc
->
pNtkCur
,
pFileName
,
IO_FILE_BLIF
);
return
0
;
return
0
;
...
...
src/base/io/ioWriteBlif.c
View file @
27311713
...
@@ -641,19 +641,21 @@ void Abc_NtkConvertBb2Wb( char * pFileNameIn, char * pFileNameOut, int fSeq, int
...
@@ -641,19 +641,21 @@ void Abc_NtkConvertBb2Wb( char * pFileNameIn, char * pFileNameOut, int fSeq, int
SeeAlso []
SeeAlso []
***********************************************************************/
***********************************************************************/
char
*
Io_NtkDeriveSop
(
Mem_Flex_t
*
pMem
,
unsigned
uTruth
,
int
nVars
)
char
*
Io_NtkDeriveSop
(
Mem_Flex_t
*
pMem
,
unsigned
uTruth
,
int
nVars
,
Vec_Int_t
*
vCover
)
{
{
char
*
pSop
;
char
*
pSop
;
Vec_Int_t
*
vCover
=
Vec_IntAlloc
(
100
);
int
RetValue
=
Kit_TruthIsop
(
&
uTruth
,
nVars
,
vCover
,
1
);
int
RetValue
=
Kit_TruthIsop
(
&
uTruth
,
nVars
,
vCover
,
1
);
assert
(
RetValue
==
0
||
RetValue
==
1
);
assert
(
RetValue
==
0
||
RetValue
==
1
);
// check the case of constant cover
// check the case of constant cover
assert
(
!
(
Vec_IntSize
(
vCover
)
==
0
||
(
Vec_IntSize
(
vCover
)
==
1
&&
Vec_IntEntry
(
vCover
,
0
)
==
0
))
);
if
(
Vec_IntSize
(
vCover
)
==
0
||
(
Vec_IntSize
(
vCover
)
==
1
&&
Vec_IntEntry
(
vCover
,
0
)
==
0
)
)
{
assert
(
RetValue
==
0
);
return
Vec_IntSize
(
vCover
)
==
0
?
" 0
\n
"
:
" 1
\n
"
;
}
// derive the AIG for that tree
// derive the AIG for that tree
pSop
=
Abc_SopCreateFromIsop
(
pMem
,
nVars
,
vCover
);
pSop
=
Abc_SopCreateFromIsop
(
pMem
,
nVars
,
vCover
);
if
(
RetValue
)
if
(
RetValue
)
Abc_SopComplement
(
pSop
);
Abc_SopComplement
(
pSop
);
Vec_IntFree
(
vCover
);
return
pSop
;
return
pSop
;
}
}
...
@@ -668,7 +670,7 @@ char * Io_NtkDeriveSop( Mem_Flex_t * pMem, unsigned uTruth, int nVars )
...
@@ -668,7 +670,7 @@ char * Io_NtkDeriveSop( Mem_Flex_t * pMem, unsigned uTruth, int nVars )
SeeAlso []
SeeAlso []
***********************************************************************/
***********************************************************************/
void
Io_NtkWriteNodeInt
(
FILE
*
pFile
,
Abc_Obj_t
*
pNode
)
void
Io_NtkWriteNodeInt
(
FILE
*
pFile
,
Abc_Obj_t
*
pNode
,
Vec_Int_t
*
vCover
)
{
{
Abc_Obj_t
*
pNet
;
Abc_Obj_t
*
pNet
;
int
i
,
nVars
=
Abc_ObjFaninNum
(
pNode
);
int
i
,
nVars
=
Abc_ObjFaninNum
(
pNode
);
...
@@ -677,6 +679,8 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
...
@@ -677,6 +679,8 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
printf
(
"Node
\"
%s
\"
has more than 7 inputs. Writing BLIF has failed.
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
printf
(
"Node
\"
%s
\"
has more than 7 inputs. Writing BLIF has failed.
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
return
;
return
;
}
}
fprintf
(
pFile
,
"
\n
"
);
if
(
nVars
<=
4
)
if
(
nVars
<=
4
)
{
{
// write the .names line
// write the .names line
...
@@ -716,6 +720,7 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
...
@@ -716,6 +720,7 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
uTruth6
=
Abc_SopToTruth
(
(
char
*
)
Abc_ObjData
(
pNode
),
nVars
);
uTruth6
=
Abc_SopToTruth
(
(
char
*
)
Abc_ObjData
(
pNode
),
nVars
);
iVar
=
If_Dec6PickBestMux
(
uTruth6
,
Cofs6
);
iVar
=
If_Dec6PickBestMux
(
uTruth6
,
Cofs6
);
}
}
// perform MUX decomposition
// perform MUX decomposition
if
(
iVar
>=
0
)
if
(
iVar
>=
0
)
{
{
...
@@ -731,41 +736,49 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
...
@@ -731,41 +736,49 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
}
}
assert
(
nVarsMin
[
0
]
<
5
);
assert
(
nVarsMin
[
0
]
<
5
);
assert
(
nVarsMin
[
1
]
<
5
);
assert
(
nVarsMin
[
1
]
<
5
);
// write MUX
fprintf
(
pFile
,
".names"
);
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
iVar
))
);
fprintf
(
pFile
,
" %s_cascade0"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
" %s_cascade1"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
" %s
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
"1-1 1
\n
01- 1
\n
"
);
// write cofactors
// write cofactors
for
(
c
=
0
;
c
<
2
;
c
++
)
for
(
c
=
0
;
c
<
2
;
c
++
)
{
{
pSop
=
Io_NtkDeriveSop
(
(
Mem_Flex_t
*
)
Abc_ObjNtk
(
pNode
)
->
pManFunc
,
pSop
=
Io_NtkDeriveSop
(
(
Mem_Flex_t
*
)
Abc_ObjNtk
(
pNode
)
->
pManFunc
,
(
unsigned
)(
nVars
==
7
?
Cofs7
[
c
][
0
]
:
Cofs6
[
c
]),
nVarsMin
[
c
]
);
(
unsigned
)(
nVars
==
7
?
Cofs7
[
c
][
0
]
:
Cofs6
[
c
]),
nVarsMin
[
c
]
,
vCover
);
fprintf
(
pFile
,
".names"
);
fprintf
(
pFile
,
".names"
);
for
(
i
=
0
;
i
<
nVarsMin
[
c
];
i
++
)
for
(
i
=
0
;
i
<
nVarsMin
[
c
];
i
++
)
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
pVars
[
c
][
i
]))
);
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
pVars
[
c
][
i
]))
);
fprintf
(
pFile
,
" %s_cascade%d
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
)),
c
);
fprintf
(
pFile
,
" %s_cascade%d
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
)),
c
);
fprintf
(
pFile
,
"%s"
,
pSop
);
fprintf
(
pFile
,
"%s"
,
pSop
);
}
}
// write MUX
fprintf
(
pFile
,
".names"
);
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
iVar
))
);
fprintf
(
pFile
,
" %s_cascade0"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
" %s_cascade1"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
" %s
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
"1-1 1
\n
01- 1
\n
"
);
return
;
return
;
}
}
assert
(
nVars
==
6
||
nVars
==
7
);
// try cascade decomposition
// try cascade decomposition
if
(
nVars
==
7
)
if
(
nVars
==
7
)
{
z
=
If_Dec7Perform
(
uTruth7
,
1
);
z
=
If_Dec7Perform
(
uTruth7
,
1
);
//If_Dec7Verify( uTruth7, z );
}
else
else
{
z
=
If_Dec6Perform
(
uTruth6
,
1
);
z
=
If_Dec6Perform
(
uTruth6
,
1
);
//If_Dec6Verify( uTruth6, z );
}
if
(
z
==
0
)
if
(
z
==
0
)
{
{
printf
(
"Node
\"
%s
\"
is not decomposable. Writing BLIF has failed.
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
printf
(
"Node
\"
%s
\"
is not decomposable. Writing BLIF has failed.
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
return
;
return
;
}
}
//
collect th
e nodes
//
deriv
e nodes
for
(
c
=
0
;
c
<
2
;
i
++
)
for
(
c
=
1
;
c
>=
0
;
c
--
)
{
{
// collect fanins
uTruth7
[
c
]
=
((
c
?
z
>>
32
:
z
)
&
0xffff
);
uTruth7
[
c
]
=
((
c
?
z
>>
32
:
z
)
&
0xffff
);
uTruth7
[
c
]
|=
(
uTruth7
[
c
]
<<
16
);
uTruth7
[
c
]
|=
(
uTruth7
[
c
]
<<
16
);
uTruth7
[
c
]
|=
(
uTruth7
[
c
]
<<
32
);
uTruth7
[
c
]
|=
(
uTruth7
[
c
]
<<
32
);
...
@@ -773,18 +786,20 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
...
@@ -773,18 +786,20 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
pVars
[
c
][
i
]
=
(
z
>>
(
c
*
32
+
16
+
4
*
i
))
&
7
;
pVars
[
c
][
i
]
=
(
z
>>
(
c
*
32
+
16
+
4
*
i
))
&
7
;
// minimize truth table
// minimize truth table
Cofs6
[
i
]
=
If_Dec6MinimumBase
(
uTruth7
[
i
],
pVars
[
i
],
4
,
&
nVarsMin
[
i
]
);
Cofs6
[
c
]
=
If_Dec6MinimumBase
(
uTruth7
[
c
],
pVars
[
c
],
4
,
&
nVarsMin
[
c
]
);
assert
(
c
?
nVarsMin
[
0
]
==
4
:
nVarsMin
[
1
]
<=
4
);
// write the nodes
// write the nodes
pSop
=
Io_NtkDeriveSop
(
(
Mem_Flex_t
*
)
Abc_ObjNtk
(
pNode
)
->
pManFunc
,
(
unsigned
)
Cofs6
[
c
],
nVarsMin
[
c
]
);
fprintf
(
pFile
,
".names"
);
fprintf
(
pFile
,
".names"
);
for
(
i
=
0
;
i
<
nVarsMin
[
c
];
i
++
)
for
(
i
=
0
;
i
<
nVarsMin
[
c
];
i
++
)
if
(
pVars
[
c
][
i
]
==
7
)
if
(
pVars
[
c
][
i
]
==
7
)
fprintf
(
pFile
,
" %s_cascade"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
fprintf
(
pFile
,
" %s_cascade"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
))
);
else
else
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
pVars
[
c
][
i
]))
);
fprintf
(
pFile
,
" %s"
,
Abc_ObjName
(
Abc_ObjFanin
(
pNode
,
pVars
[
c
][
i
]))
);
fprintf
(
pFile
,
" %s%s
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
)),
c
?
"_cascade"
:
""
);
fprintf
(
pFile
,
" %s%s
\n
"
,
Abc_ObjName
(
Abc_ObjFanout0
(
pNode
)),
c
?
""
:
"_cascade"
);
// write SOP
pSop
=
Io_NtkDeriveSop
(
(
Mem_Flex_t
*
)
Abc_ObjNtk
(
pNode
)
->
pManFunc
,
(
unsigned
)
Cofs6
[
c
],
nVarsMin
[
c
],
vCover
);
fprintf
(
pFile
,
"%s"
,
pSop
);
fprintf
(
pFile
,
"%s"
,
pSop
);
}
}
}
}
...
@@ -804,6 +819,7 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
...
@@ -804,6 +819,7 @@ void Io_NtkWriteNodeInt( FILE * pFile, Abc_Obj_t * pNode )
void
Io_WriteBlifInt
(
Abc_Ntk_t
*
pNtk
,
char
*
FileName
)
void
Io_WriteBlifInt
(
Abc_Ntk_t
*
pNtk
,
char
*
FileName
)
{
{
FILE
*
pFile
;
FILE
*
pFile
;
Vec_Int_t
*
vCover
;
Abc_Obj_t
*
pNode
,
*
pLatch
;
Abc_Obj_t
*
pNode
,
*
pLatch
;
int
i
;
int
i
;
assert
(
Abc_NtkIsNetlist
(
pNtk
)
);
assert
(
Abc_NtkIsNetlist
(
pNtk
)
);
...
@@ -833,8 +849,10 @@ void Io_WriteBlifInt( Abc_Ntk_t * pNtk, char * FileName )
...
@@ -833,8 +849,10 @@ void Io_WriteBlifInt( Abc_Ntk_t * pNtk, char * FileName )
if
(
Abc_NtkLatchNum
(
pNtk
)
)
if
(
Abc_NtkLatchNum
(
pNtk
)
)
fprintf
(
pFile
,
"
\n
"
);
fprintf
(
pFile
,
"
\n
"
);
// write each internal node
// write each internal node
vCover
=
Vec_IntAlloc
(
(
1
<<
16
)
);
Abc_NtkForEachNode
(
pNtk
,
pNode
,
i
)
Abc_NtkForEachNode
(
pNtk
,
pNode
,
i
)
Io_NtkWriteNodeInt
(
pFile
,
pNode
);
Io_NtkWriteNodeInt
(
pFile
,
pNode
,
vCover
);
Vec_IntFree
(
vCover
);
// write the end
// write the end
fprintf
(
pFile
,
".end
\n\n
"
);
fprintf
(
pFile
,
".end
\n\n
"
);
fclose
(
pFile
);
fclose
(
pFile
);
...
...
src/map/if/ifDec.c
View file @
27311713
...
@@ -72,7 +72,7 @@ extern void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits );
...
@@ -72,7 +72,7 @@ extern void Extra_PrintBinary( FILE * pFile, unsigned Sign[], int nBits );
/// FUNCTION DEFINITIONS ///
/// FUNCTION DEFINITIONS ///
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
static
void
If_DecPrintConfig
(
word
z
)
void
If_DecPrintConfig
(
word
z
)
{
{
unsigned
S
[
1
];
unsigned
S
[
1
];
S
[
0
]
=
(
z
&
0xffff
)
|
((
z
&
0xffff
)
<<
16
);
S
[
0
]
=
(
z
&
0xffff
)
|
((
z
&
0xffff
)
<<
16
);
...
@@ -113,7 +113,7 @@ static word If_Dec6ComposeLut4( int t, word f[4] )
...
@@ -113,7 +113,7 @@ static word If_Dec6ComposeLut4( int t, word f[4] )
}
}
return
r
;
return
r
;
}
}
static
void
If_Dec6Verify
(
word
t
,
word
z
)
void
If_Dec6Verify
(
word
t
,
word
z
)
{
{
word
r
,
q
,
f
[
4
];
word
r
,
q
,
f
[
4
];
int
i
,
v
;
int
i
,
v
;
...
@@ -160,7 +160,7 @@ static void If_Dec7ComposeLut4( int t, word f[4][2], word r[2] )
...
@@ -160,7 +160,7 @@ static void If_Dec7ComposeLut4( int t, word f[4][2], word r[2] )
r
[
1
]
|=
c
[
1
];
r
[
1
]
|=
c
[
1
];
}
}
}
}
static
void
If_Dec7Verify
(
word
t
[
2
],
word
z
)
void
If_Dec7Verify
(
word
t
[
2
],
word
z
)
{
{
word
f
[
4
][
2
],
r
[
2
];
word
f
[
4
][
2
],
r
[
2
];
int
i
,
v
;
int
i
,
v
;
...
@@ -374,6 +374,7 @@ static word If_Dec7DeriveDisjoint( word t[2], int Pla2Var[7], int Var2Pla[7] )
...
@@ -374,6 +374,7 @@ static word If_Dec7DeriveDisjoint( word t[2], int Pla2Var[7], int Var2Pla[7] )
z
|=
((
word
)((
Cof1
<<
8
)
|
Cof0
)
<<
32
);
z
|=
((
word
)((
Cof1
<<
8
)
|
Cof0
)
<<
32
);
for
(
i
=
0
;
i
<
3
;
i
++
)
for
(
i
=
0
;
i
<
3
;
i
++
)
z
|=
(((
word
)
Pla2Var
[
i
])
<<
(
48
+
4
*
i
));
z
|=
(((
word
)
Pla2Var
[
i
])
<<
(
48
+
4
*
i
));
z
|=
(((
word
)
7
)
<<
(
48
+
4
*
i
));
return
z
;
return
z
;
}
}
...
@@ -641,7 +642,7 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
...
@@ -641,7 +642,7 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
{
{
word
c0
[
2
],
c1
[
2
];
word
c0
[
2
],
c1
[
2
];
int
v
,
vBest
=
-
1
,
Count0
,
Count1
,
CountBest
=
1000
;
int
v
,
vBest
=
-
1
,
Count0
,
Count1
,
CountBest
=
1000
;
for
(
v
=
0
;
v
<
6
;
v
++
)
for
(
v
=
0
;
v
<
7
;
v
++
)
{
{
If_Dec7Cofactor
(
t
,
v
,
0
,
c0
);
If_Dec7Cofactor
(
t
,
v
,
0
,
c0
);
If_Dec7Cofactor
(
t
,
v
,
1
,
c1
);
If_Dec7Cofactor
(
t
,
v
,
1
,
c1
);
...
@@ -659,7 +660,6 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
...
@@ -659,7 +660,6 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
}
}
/**Function*************************************************************
/**Function*************************************************************
Synopsis [Performs additional check.]
Synopsis [Performs additional check.]
...
@@ -671,9 +671,9 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
...
@@ -671,9 +671,9 @@ int If_Dec7PickBestMux( word t[2], word c0r[2], word c1r[2] )
SeeAlso []
SeeAlso []
***********************************************************************/
***********************************************************************/
int
If_CutPerformCheck
Int
(
unsigned
*
pTruth
,
int
nVars
,
int
nLeaves
)
int
If_CutPerformCheck
(
unsigned
*
pTruth
,
int
nVars
,
int
nLeaves
)
{
{
int
fDerive
=
0
;
int
fDerive
=
1
;
if
(
nLeaves
<
6
)
if
(
nLeaves
<
6
)
return
1
;
return
1
;
if
(
nLeaves
==
6
)
if
(
nLeaves
==
6
)
...
@@ -696,30 +696,13 @@ int If_CutPerformCheckInt( unsigned * pTruth, int nVars, int nLeaves )
...
@@ -696,30 +696,13 @@ int If_CutPerformCheckInt( unsigned * pTruth, int nVars, int nLeaves )
z
=
If_Dec7Perform
(
t
,
fDerive
);
z
=
If_Dec7Perform
(
t
,
fDerive
);
if
(
fDerive
&&
z
)
if
(
fDerive
&&
z
)
If_Dec7Verify
(
t
,
z
);
If_Dec7Verify
(
t
,
z
);
return
z
!=
0
;
return
z
!=
0
;
}
}
assert
(
0
);
assert
(
0
);
return
0
;
return
0
;
}
}
int
If_CutPerformCheck
(
unsigned
*
pTruth
,
int
nVars
,
int
nLeaves
)
{
int
RetValue
=
If_CutPerformCheckInt
(
pTruth
,
nVars
,
nLeaves
);
/*
// if ( nLeaves == 6 || nLeaves == 7 )
if ( nLeaves == 7 )
{
if ( RetValue == 0 )
{
printf( "%d ", RetValue );
Kit_DsdPrintFromTruth( pTruth, nLeaves );
printf( "\n" );
If_CutPerformCheckInt( pTruth, nVars, nLeaves );
}
}
*/
return
RetValue
;
}
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
/// END OF FILE ///
/// END OF FILE ///
...
...
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