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
a9afe7e8
Commit
a9afe7e8
authored
Jul 21, 2013
by
Alan Mishchenko
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improvements to post-mapping re-sizing.
parent
710835f8
Show whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
150 additions
and
120 deletions
+150
-120
src/base/io/ioWriteBlif.c
+2
-0
src/map/scl/scl.c
+70
-22
src/map/scl/sclDnsize.c
+25
-23
src/map/scl/sclInt.h
+7
-34
src/map/scl/sclMan.h
+1
-1
src/map/scl/sclTime.c
+14
-13
src/map/scl/sclUpsize.c
+29
-27
src/map/scl/sclUtil.c
+2
-0
No files found.
src/base/io/ioWriteBlif.c
View file @
a9afe7e8
...
...
@@ -718,6 +718,7 @@ void Io_WriteTimingInfo( FILE * pFile, Abc_Ntk_t * pNtk )
pTimeDef
=
Abc_NtkReadDefaultInputDrive
(
pNtk
);
if
(
pTimeDef
->
Rise
!=
0
.
0
||
pTimeDef
->
Fall
!=
0
.
0
)
fprintf
(
pFile
,
".default_input_drive %g %g
\n
"
,
pTimeDef
->
Rise
,
pTimeDef
->
Fall
);
if
(
Abc_NodeReadInputDrive
(
pNtk
,
0
)
)
Abc_NtkForEachPi
(
pNtk
,
pNode
,
i
)
{
pTime
=
Abc_NodeReadInputDrive
(
pNtk
,
i
);
...
...
@@ -729,6 +730,7 @@ void Io_WriteTimingInfo( FILE * pFile, Abc_Ntk_t * pNtk )
pTimeDef
=
Abc_NtkReadDefaultOutputLoad
(
pNtk
);
if
(
pTimeDef
->
Rise
!=
0
.
0
||
pTimeDef
->
Fall
!=
0
.
0
)
fprintf
(
pFile
,
".default_output_load %g %g
\n
"
,
pTimeDef
->
Rise
,
pTimeDef
->
Fall
);
if
(
Abc_NodeReadOutputLoad
(
pNtk
,
0
)
)
Abc_NtkForEachPo
(
pNtk
,
pNode
,
i
)
{
pTime
=
Abc_NodeReadOutputLoad
(
pNtk
,
i
);
...
...
src/map/scl/scl.c
View file @
a9afe7e8
...
...
@@ -580,15 +580,17 @@ usage:
***********************************************************************/
int
Scl_CommandUpsize
(
Abc_Frame_t
*
pAbc
,
int
argc
,
char
**
argv
)
{
SC_
Up
SizePars
Pars
,
*
pPars
=
&
Pars
;
SC_SizePars
Pars
,
*
pPars
=
&
Pars
;
Abc_Ntk_t
*
pNtk
=
Abc_FrameReadNtk
(
pAbc
);
int
c
;
memset
(
pPars
,
0
,
sizeof
(
SC_
Up
SizePars
)
);
memset
(
pPars
,
0
,
sizeof
(
SC_SizePars
)
);
pPars
->
nIters
=
1000
;
pPars
->
nIterNoChange
=
50
;
pPars
->
Window
=
2
;
pPars
->
Ratio
=
10
;
pPars
->
Notches
=
20
;
pPars
->
Notches
=
1000
;
pPars
->
DelayUser
=
0
;
pPars
->
DelayGap
=
0
;
pPars
->
TimeOut
=
0
;
pPars
->
fUseDept
=
1
;
pPars
->
fUseWireLoads
=
1
;
...
...
@@ -596,7 +598,7 @@ int Scl_CommandUpsize( Abc_Frame_t * pAbc, int argc, char **argv )
pPars
->
fVerbose
=
0
;
pPars
->
fVeryVerbose
=
0
;
Extra_UtilGetoptReset
();
while
(
(
c
=
Extra_UtilGetopt
(
argc
,
argv
,
"IJWRNTcsdvwh"
)
)
!=
EOF
)
while
(
(
c
=
Extra_UtilGetopt
(
argc
,
argv
,
"IJWRN
DG
Tcsdvwh"
)
)
!=
EOF
)
{
switch
(
c
)
{
...
...
@@ -655,6 +657,26 @@ int Scl_CommandUpsize( Abc_Frame_t * pAbc, int argc, char **argv )
if
(
pPars
->
Notches
<
0
)
goto
usage
;
break
;
case
'D'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-D
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
DelayUser
=
atoi
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
if
(
pPars
->
DelayUser
<
0
)
goto
usage
;
break
;
case
'G'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-G
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
DelayGap
=
atoi
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
break
;
case
'T'
:
if
(
globalUtilOptind
>=
argc
)
{
...
...
@@ -713,13 +735,15 @@ int Scl_CommandUpsize( Abc_Frame_t * pAbc, int argc, char **argv )
return
0
;
usage:
fprintf
(
pAbc
->
Err
,
"usage: upsize [-IJWRNT num] [-csdvwh]
\n
"
);
fprintf
(
pAbc
->
Err
,
"usage: upsize [-IJWRN
DG
T num] [-csdvwh]
\n
"
);
fprintf
(
pAbc
->
Err
,
"
\t
selectively increases gate sizes on the critical path
\n
"
);
fprintf
(
pAbc
->
Err
,
"
\t
-I <num> : the number of upsizing iterations to perform [default = %d]
\n
"
,
pPars
->
nIters
);
fprintf
(
pAbc
->
Err
,
"
\t
-J <num> : the number of iterations without improvement to stop [default = %d]
\n
"
,
pPars
->
nIterNoChange
);
fprintf
(
pAbc
->
Err
,
"
\t
-W <num> : delay window (in percent) of near-critical COs [default = %d]
\n
"
,
pPars
->
Window
);
fprintf
(
pAbc
->
Err
,
"
\t
-R <num> : ratio of critical nodes (in percent) to update [default = %d]
\n
"
,
pPars
->
Ratio
);
fprintf
(
pAbc
->
Err
,
"
\t
-N <num> : limit on discrete upsizing steps at a node [default = %d]
\n
"
,
pPars
->
Notches
);
fprintf
(
pAbc
->
Err
,
"
\t
-D <num> : delay target set by the user, in picoseconds [default = %d]
\n
"
,
pPars
->
DelayUser
);
fprintf
(
pAbc
->
Err
,
"
\t
-G <num> : delay gap during updating, in picoseconds [default = %d]
\n
"
,
pPars
->
DelayGap
);
fprintf
(
pAbc
->
Err
,
"
\t
-T <num> : approximate timeout in seconds [default = %d]
\n
"
,
pPars
->
TimeOut
);
fprintf
(
pAbc
->
Err
,
"
\t
-c : toggle using wire-loads if specified [default = %s]
\n
"
,
pPars
->
fUseWireLoads
?
"yes"
:
"no"
);
fprintf
(
pAbc
->
Err
,
"
\t
-s : toggle using slack based on departure times [default = %s]
\n
"
,
pPars
->
fUseDept
?
"yes"
:
"no"
);
...
...
@@ -743,13 +767,15 @@ usage:
***********************************************************************/
int
Scl_CommandDnsize
(
Abc_Frame_t
*
pAbc
,
int
argc
,
char
**
argv
)
{
SC_
Dn
SizePars
Pars
,
*
pPars
=
&
Pars
;
SC_SizePars
Pars
,
*
pPars
=
&
Pars
;
Abc_Ntk_t
*
pNtk
=
Abc_FrameReadNtk
(
pAbc
);
int
c
;
memset
(
pPars
,
0
,
sizeof
(
SC_DnSizePars
)
);
pPars
->
DUser
=
0
;
memset
(
pPars
,
0
,
sizeof
(
SC_SizePars
)
);
pPars
->
nIters
=
5
;
pPars
->
nIterNoChange
=
50
;
pPars
->
Notches
=
1000
;
pPars
->
DelayUser
=
0
;
pPars
->
DelayGap
=
1000
;
pPars
->
TimeOut
=
0
;
pPars
->
fUseDept
=
1
;
pPars
->
fUseWireLoads
=
1
;
...
...
@@ -757,21 +783,10 @@ int Scl_CommandDnsize( Abc_Frame_t * pAbc, int argc, char **argv )
pPars
->
fVerbose
=
0
;
pPars
->
fVeryVerbose
=
0
;
Extra_UtilGetoptReset
();
while
(
(
c
=
Extra_UtilGetopt
(
argc
,
argv
,
"
DIJ
Tcsdvwh"
)
)
!=
EOF
)
while
(
(
c
=
Extra_UtilGetopt
(
argc
,
argv
,
"
IJNDG
Tcsdvwh"
)
)
!=
EOF
)
{
switch
(
c
)
{
case
'D'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-D
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
DUser
=
atof
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
if
(
pPars
->
DUser
<
0
)
goto
usage
;
break
;
case
'I'
:
if
(
globalUtilOptind
>=
argc
)
{
...
...
@@ -794,6 +809,37 @@ int Scl_CommandDnsize( Abc_Frame_t * pAbc, int argc, char **argv )
if
(
pPars
->
nIterNoChange
<
0
)
goto
usage
;
break
;
case
'N'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-N
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
Notches
=
atoi
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
if
(
pPars
->
Notches
<
0
)
goto
usage
;
break
;
case
'D'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-D
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
DelayUser
=
atoi
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
if
(
pPars
->
DelayUser
<
0
)
goto
usage
;
break
;
case
'G'
:
if
(
globalUtilOptind
>=
argc
)
{
Abc_Print
(
-
1
,
"Command line switch
\"
-G
\"
should be followed by a positive integer.
\n
"
);
goto
usage
;
}
pPars
->
DelayGap
=
atoi
(
argv
[
globalUtilOptind
]);
globalUtilOptind
++
;
break
;
case
'T'
:
if
(
globalUtilOptind
>=
argc
)
{
...
...
@@ -852,11 +898,13 @@ int Scl_CommandDnsize( Abc_Frame_t * pAbc, int argc, char **argv )
return
0
;
usage:
fprintf
(
pAbc
->
Err
,
"usage: dnsize [-
DIJ
T num] [-csdvwh]
\n
"
);
fprintf
(
pAbc
->
Err
,
"usage: dnsize [-
IJNDG
T num] [-csdvwh]
\n
"
);
fprintf
(
pAbc
->
Err
,
"
\t
selectively decreases gate sizes while maintaining delay
\n
"
);
fprintf
(
pAbc
->
Err
,
"
\t
-D <num> : the target max delay after downsizing in picosecs [default = %.2f]
\n
"
,
pPars
->
DUser
);
fprintf
(
pAbc
->
Err
,
"
\t
-I <num> : the number of upsizing iterations to perform [default = %d]
\n
"
,
pPars
->
nIters
);
fprintf
(
pAbc
->
Err
,
"
\t
-J <num> : the number of iterations without improvement to stop [default = %d]
\n
"
,
pPars
->
nIterNoChange
);
fprintf
(
pAbc
->
Err
,
"
\t
-N <num> : limit on discrete upsizing steps at a node [default = %d]
\n
"
,
pPars
->
Notches
);
fprintf
(
pAbc
->
Err
,
"
\t
-D <num> : delay target set by the user, in picoseconds [default = %d]
\n
"
,
pPars
->
DelayUser
);
fprintf
(
pAbc
->
Err
,
"
\t
-G <num> : delay gap during updating, in picoseconds [default = %d]
\n
"
,
pPars
->
DelayGap
);
fprintf
(
pAbc
->
Err
,
"
\t
-T <num> : approximate timeout in seconds [default = %d]
\n
"
,
pPars
->
TimeOut
);
fprintf
(
pAbc
->
Err
,
"
\t
-c : toggle using wire-loads if specified [default = %s]
\n
"
,
pPars
->
fUseWireLoads
?
"yes"
:
"no"
);
fprintf
(
pAbc
->
Err
,
"
\t
-s : toggle using slack based on departure times [default = %s]
\n
"
,
pPars
->
fUseDept
?
"yes"
:
"no"
);
...
...
src/map/scl/sclDnsize.c
View file @
a9afe7e8
...
...
@@ -99,7 +99,7 @@ void Abc_SclFindWindow( Abc_Obj_t * pPivot, Vec_Int_t ** pvNodes, Vec_Int_t ** p
SeeAlso []
***********************************************************************/
int
Abc_SclCheckImprovement
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
Vec_Int_t
*
vNodes
,
Vec_Int_t
*
vEvals
)
int
Abc_SclCheckImprovement
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
Vec_Int_t
*
vNodes
,
Vec_Int_t
*
vEvals
,
int
Notches
,
int
DelayGap
)
{
Abc_Obj_t
*
pTemp
;
SC_Cell
*
pCellOld
,
*
pCellNew
;
...
...
@@ -114,11 +114,13 @@ clk = Abc_Clock();
Abc_SclLoadStore
(
p
,
pObj
);
// try different gate sizes for this node
gateBest
=
-
1
;
dGainBest
=
-
ABC_INFINITY
;
//0.0
;
SC_RingForEachCell
(
pCellOld
,
pCellNew
,
i
)
dGainBest
=
-
SC_LibTimeFromPs
(
p
->
pLib
,
(
float
)
DelayGap
)
;
SC_RingForEachCell
Rev
(
pCellOld
,
pCellNew
,
i
)
{
if
(
pCellNew
->
area
>=
pCellOld
->
area
)
continue
;
if
(
i
>
Notches
)
break
;
// set new cell
Abc_SclObjSetCell
(
p
,
pObj
,
pCellNew
);
Abc_SclUpdateLoad
(
p
,
pObj
,
pCellOld
,
pCellNew
);
...
...
@@ -240,7 +242,7 @@ void Abc_SclDnsizePrint( SC_Man * p, int Iter, int nAttempts, int nOverlaps, int
SeeAlso []
***********************************************************************/
void
Abc_SclDnsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_
Dn
SizePars
*
pPars
)
void
Abc_SclDnsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_SizePars
*
pPars
)
{
SC_Man
*
p
;
Abc_Obj_t
*
pObj
;
...
...
@@ -250,17 +252,18 @@ void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_DnSizePars * pPar
if
(
pPars
->
fVerbose
)
{
printf
(
"Downsizing parameters: "
);
printf
(
"Delay =%8.2f ps. "
,
pPars
->
DUser
);
printf
(
"Parameters: "
);
printf
(
"Iters =%5d. "
,
pPars
->
nIters
);
printf
(
"UseDept =%2d. "
,
pPars
->
fUseDept
);
printf
(
"UseWL =%2d. "
,
pPars
->
fUseWireLoads
);
printf
(
"Target =%5d ps. "
,
pPars
->
DelayUser
);
printf
(
"DelayGap =%3d ps. "
,
pPars
->
DelayGap
);
printf
(
"Timeout =%4d sec"
,
pPars
->
TimeOut
);
printf
(
"
\n
"
);
}
// prepare the manager; collect init stats
p
=
Abc_SclManStart
(
pLib
,
pNtk
,
pPars
->
fUseWireLoads
,
pPars
->
fUseDept
,
SC_LibTimeFromPs
(
pLib
,
pPars
->
DUser
)
);
p
=
Abc_SclManStart
(
pLib
,
pNtk
,
pPars
->
fUseWireLoads
,
pPars
->
fUseDept
,
SC_LibTimeFromPs
(
pLib
,
pPars
->
D
elay
User
)
);
p
->
timeTotal
=
Abc_Clock
();
assert
(
p
->
vGatesBest
==
NULL
);
p
->
vGatesBest
=
Vec_IntDup
(
p
->
vGates
);
...
...
@@ -281,38 +284,35 @@ void Abc_SclDnsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_DnSizePars * pPar
Abc_NtkIncrementTravId
(
pNtk
);
while
(
Vec_QueSize
(
p
->
vNodeByGain
)
>
0
)
{
clk
=
Abc_Clock
();
clk
=
Abc_Clock
();
pObj
=
Abc_NtkObj
(
p
->
pNtk
,
Vec_QuePop
(
p
->
vNodeByGain
)
);
Abc_SclFindWindow
(
pObj
,
&
vNodes
,
&
vEvals
);
p
->
timeCone
+=
Abc_Clock
()
-
clk
;
p
->
timeCone
+=
Abc_Clock
()
-
clk
;
if
(
Abc_SclCheckOverlap
(
p
->
pNtk
,
vNodes
)
)
nOverlap
++
,
Vec_IntPush
(
vTryLater
,
Abc_ObjId
(
pObj
)
);
else
nChanges
+=
Abc_SclCheckImprovement
(
p
,
pObj
,
vNodes
,
vEvals
);
nChanges
+=
Abc_SclCheckImprovement
(
p
,
pObj
,
vNodes
,
vEvals
,
pPars
->
Notches
,
pPars
->
DelayGap
);
nAttempt
++
;
}
Abc_NtkForEachObjVec
(
vTryLater
,
pNtk
,
pObj
,
k
)
Vec_QuePush
(
p
->
vNodeByGain
,
Abc_ObjId
(
pObj
)
);
clk
=
Abc_Clock
();
Abc_SclTimeNtkRecompute
(
p
,
NULL
,
NULL
,
pPars
->
fUseDept
,
pPars
->
DUser
);
p
->
timeTime
+=
Abc_Clock
()
-
clk
;
clk
=
Abc_Clock
();
Abc_SclTimeNtkRecompute
(
p
,
&
p
->
SumArea
,
&
p
->
MaxDelay
,
pPars
->
fUseDept
,
pPars
->
DelayUser
);
p
->
timeTime
+=
Abc_Clock
()
-
clk
;
p
->
MaxDelay
=
Abc_SclReadMaxDelay
(
p
);
if
(
pPars
->
fUseDept
&&
pPars
->
D
User
>
0
&&
p
->
MaxDelay
<
pPars
->
D
User
)
p
->
MaxDelay
=
pPars
->
DUser
;
if
(
pPars
->
fUseDept
&&
pPars
->
D
elayUser
>
0
&&
p
->
MaxDelay
<
pPars
->
Delay
User
)
p
->
MaxDelay
=
pPars
->
D
elay
User
;
Abc_SclDnsizePrint
(
p
,
nRounds
++
,
nAttempt
,
nOverlap
,
nChanges
,
pPars
->
fVeryVerbose
);
nAttemptAll
+=
nAttempt
;
nOverlapAll
+=
nOverlap
;
nChangesAll
+=
nChanges
;
nAttemptAll
+=
nAttempt
;
nOverlapAll
+=
nOverlap
;
nChangesAll
+=
nChanges
;
if
(
nRuntimeLimit
&&
Abc_Clock
()
>
nRuntimeLimit
)
break
;
}
// recompute
Abc_SclTimeNtkRecompute
(
p
,
&
p
->
SumArea
,
&
p
->
MaxDelay
,
pPars
->
fUseDept
,
pPars
->
D
User
);
// Abc_SclTimeNtkRecompute( p, &p->SumArea, &p->MaxDelay, pPars->fUseDept, pPars->Delay
User );
if
(
pPars
->
fVerbose
)
Abc_SclDnsizePrint
(
p
,
-
1
,
nAttemptAll
,
nOverlapAll
,
nChangesAll
,
1
);
else
printf
(
"
\r
"
);
if
(
nRuntimeLimit
&&
Abc_Clock
()
>
nRuntimeLimit
)
break
;
if
(
nAttemptAll
==
0
)
...
...
@@ -321,6 +321,8 @@ p->timeTime += Abc_Clock() - clk;
Vec_IntFree
(
vNodes
);
Vec_IntFree
(
vEvals
);
Vec_IntFree
(
vTryLater
);
if
(
!
pPars
->
fVerbose
)
printf
(
"
\r
"
);
// report runtime
p
->
timeTotal
=
Abc_Clock
()
-
p
->
timeTotal
;
...
...
@@ -333,8 +335,8 @@ p->timeTime += Abc_Clock() - clk;
ABC_PRTP
(
"Runtime: Other "
,
p
->
timeOther
,
p
->
timeTotal
);
ABC_PRTP
(
"Runtime: TOTAL "
,
p
->
timeTotal
,
p
->
timeTotal
);
}
//
if ( pPars->fDumpStats )
//
Abc_SclDumpStats( p, "stats2.txt", p->timeTotal );
if
(
pPars
->
fDumpStats
)
Abc_SclDumpStats
(
p
,
"stats2.txt"
,
p
->
timeTotal
);
if
(
nRuntimeLimit
&&
Abc_Clock
()
>
nRuntimeLimit
)
printf
(
"Gate sizing timed out at %d seconds.
\n
"
,
pPars
->
TimeOut
);
...
...
src/map/scl/sclInt.h
View file @
a9afe7e8
...
...
@@ -63,39 +63,13 @@ typedef enum // -- timing sense, positive-, negative- or non-unate
typedef
struct
SC_SizePars_
SC_SizePars
;
struct
SC_SizePars_
{
int
nSteps
;
int
nRange
;
int
nRangeF
;
int
nTimeOut
;
int
fTryAll
;
int
fUseWireLoads
;
int
fPrintCP
;
int
fVerbose
;
int
fVeryVerbose
;
};
typedef
struct
SC_UpSizePars_
SC_UpSizePars
;
struct
SC_UpSizePars_
{
int
nIters
;
int
nIterNoChange
;
int
Window
;
int
Ratio
;
int
Window
;
// used for upsizing
int
Ratio
;
// used for upsizing
int
Notches
;
int
TimeOut
;
int
fUseDept
;
int
fDumpStats
;
int
fUseWireLoads
;
int
fVerbose
;
int
fVeryVerbose
;
};
typedef
struct
SC_DnSizePars_
SC_DnSizePars
;
struct
SC_DnSizePars_
{
float
DUser
;
int
nIters
;
int
nIterNoChange
;
int
DelayUser
;
int
DelayGap
;
int
TimeOut
;
int
fUseDept
;
int
fDumpStats
;
...
...
@@ -242,6 +216,7 @@ static inline double SC_LibTimeFromPs( SC_Lib * p, double ps ) { return ps
#define SC_CellForEachPinIn( p, pPin, i ) Vec_PtrForEachEntryStop( SC_Pin *, p->vPins, pPin, i, p->n_inputs )
#define SC_CellForEachPinOut( p, pPin, i ) Vec_PtrForEachEntryStart( SC_Pin *, p->vPins, pPin, i, p->n_inputs )
#define SC_RingForEachCell( pRing, pCell, i ) for ( i = 0, pCell = pRing; i == 0 || pCell != pRing; pCell = pCell->pNext, i++ )
#define SC_RingForEachCellRev( pRing, pCell, i ) for ( i = 0, pCell = pRing; i == 0 || pCell != pRing; pCell = pCell->pPrev, i++ )
#define SC_PinForEachRTiming( p, pRTime, i ) Vec_PtrForEachEntry( SC_Timings *, p->vRTimings, pRTime, i )
...
...
@@ -459,7 +434,7 @@ static inline void Abc_SclLibFree( SC_Lib * p )
extern
int
Abc_SclCheckNtk
(
Abc_Ntk_t
*
p
,
int
fVerbose
);
extern
Abc_Ntk_t
*
Abc_SclPerformBuffering
(
Abc_Ntk_t
*
p
,
int
Degree
,
int
fVerbose
);
/*=== sclDnsize.c ===============================================================*/
extern
void
Abc_SclDnsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_
Dn
SizePars
*
pPars
);
extern
void
Abc_SclDnsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_SizePars
*
pPars
);
/*=== sclFile.c ===============================================================*/
extern
SC_Lib
*
Abc_SclRead
(
char
*
pFileName
);
extern
void
Abc_SclWrite
(
char
*
pFileName
,
SC_Lib
*
p
);
...
...
@@ -471,10 +446,8 @@ extern SC_WireLoad * Abc_SclFindWireLoadModel( SC_Lib * p, float Area );
/*=== sclTime.c ===============================================================*/
extern
void
Abc_SclTimePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
int
fUseWireLoads
,
int
fShowAll
,
int
fShort
,
int
fDumpStats
);
extern
void
Abc_SclPrintBuffers
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
int
fVerbose
);
/*=== sclSize.c ===============================================================*/
extern
void
Abc_SclSizingPerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_SizePars
*
p
);
/*=== sclUpsize.c ===============================================================*/
extern
void
Abc_SclUpsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_
Up
SizePars
*
pPars
);
extern
void
Abc_SclUpsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_SizePars
*
pPars
);
/*=== sclUtil.c ===============================================================*/
extern
void
Abc_SclHashCells
(
SC_Lib
*
p
);
extern
int
Abc_SclCellFind
(
SC_Lib
*
p
,
char
*
pName
);
...
...
src/map/scl/sclMan.h
View file @
a9afe7e8
...
...
@@ -114,7 +114,7 @@ static inline float Abc_SclObjGetSlackF( SC_Man * p, Abc_Obj_t * pObj, float
static
inline
float
Abc_SclObjSlack
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
)
{
return
p
->
pSlack
[
Abc_ObjId
(
pObj
)];
}
static
inline
void
Abc_SclObjDupFanin
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
)
{
assert
(
Abc_ObjIsCo
(
pObj
)
);
*
Abc_SclObjTime
(
p
,
pObj
)
=
*
Abc_SclObjTime
(
p
,
Abc_ObjFanin0
(
pObj
));
}
static
inline
float
Abc_SclObjGain
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
)
{
return
(
Abc_SclObjTime2
(
p
,
pObj
)
->
rise
-
Abc_SclObjTime
(
p
,
pObj
)
->
rise
)
+
(
Abc_SclObjTime2
(
p
,
pObj
)
->
fall
-
Abc_SclObjTime
(
p
,
pObj
)
->
fall
);
}
static
inline
float
Abc_SclObjGain
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
)
{
return
0
.
5
*
((
Abc_SclObjTime2
(
p
,
pObj
)
->
rise
-
Abc_SclObjTime
(
p
,
pObj
)
->
rise
)
+
(
Abc_SclObjTime2
(
p
,
pObj
)
->
fall
-
Abc_SclObjTime
(
p
,
pObj
)
->
fall
)
);
}
static
inline
int
Abc_SclObjLegal
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
float
D
)
{
return
Abc_SclObjTime
(
p
,
pObj
)
->
rise
<=
Abc_SclObjTime2
(
p
,
pObj
)
->
rise
+
Abc_SclObjGetSlackR
(
p
,
pObj
,
D
)
&&
Abc_SclObjTime
(
p
,
pObj
)
->
fall
<=
Abc_SclObjTime2
(
p
,
pObj
)
->
fall
+
Abc_SclObjGetSlackF
(
p
,
pObj
,
D
);
}
static
inline
double
Abc_SclObjLoadFf
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
int
fRise
)
{
return
SC_LibCapFf
(
p
->
pLib
,
fRise
?
Abc_SclObjLoad
(
p
,
pObj
)
->
rise
:
Abc_SclObjLoad
(
p
,
pObj
)
->
fall
);
}
...
...
src/map/scl/sclTime.c
View file @
a9afe7e8
...
...
@@ -108,18 +108,19 @@ Abc_Obj_t * Abc_SclFindMostCriticalFanin( SC_Man * p, int * pfRise, Abc_Obj_t *
***********************************************************************/
static
inline
void
Abc_SclTimeNodePrint
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
int
fRise
,
int
Length
,
float
maxDelay
)
{
printf
(
"%
7d : "
,
Abc_ObjId
(
pObj
)
);
printf
(
"%
6d : "
,
Abc_ObjId
(
pObj
)
);
printf
(
"%d "
,
Abc_ObjFaninNum
(
pObj
)
);
printf
(
"%2d "
,
Abc_ObjFanoutNum
(
pObj
)
);
printf
(
"%-*s "
,
Length
,
Abc_ObjIsPi
(
pObj
)
?
"pi"
:
Abc_SclObjCell
(
p
,
pObj
)
->
pName
);
printf
(
"%-*s "
,
Length
,
Abc_ObjIsNode
(
pObj
)
?
Abc_SclObjCell
(
p
,
pObj
)
->
pName
:
"pi"
);
if
(
fRise
>=
0
)
printf
(
"(%s) "
,
fRise
?
"rise"
:
"fall"
);
printf
(
"delay = ("
);
printf
(
"%8.2f ps "
,
Abc_SclObjTimePs
(
p
,
pObj
,
1
)
);
printf
(
"A =%7.2f "
,
Abc_ObjIsNode
(
pObj
)
?
Abc_SclObjCell
(
p
,
pObj
)
->
area
:
0
.
0
);
printf
(
"D = ("
);
printf
(
"%8.2f ps"
,
Abc_SclObjTimePs
(
p
,
pObj
,
1
)
);
printf
(
"%8.2f ps ) "
,
Abc_SclObjTimePs
(
p
,
pObj
,
0
)
);
printf
(
"
load =%7.2f ff "
,
Abc_SclObjLoadFf
(
p
,
pObj
,
fRise
>=
0
?
fRise
:
0
)
);
printf
(
"
slew =%7.2f ps "
,
Abc_SclObjSlewPs
(
p
,
pObj
,
fRise
>=
0
?
fRise
:
0
)
);
printf
(
"
slack
=%6.2f ps"
,
Abc_SclObjSlack
(
p
,
pObj
)
);
printf
(
"
L =%7.2f ff "
,
Abc_SclObjLoadFf
(
p
,
pObj
,
fRise
>=
0
?
fRise
:
0
)
);
printf
(
"
S =%7.2f ps "
,
Abc_SclObjSlewPs
(
p
,
pObj
,
fRise
>=
0
?
fRise
:
0
)
);
printf
(
"
SL
=%6.2f ps"
,
Abc_SclObjSlack
(
p
,
pObj
)
);
printf
(
"
\n
"
);
}
void
Abc_SclTimeNtkPrint
(
SC_Man
*
p
,
int
fShowAll
,
int
fShort
)
...
...
@@ -129,9 +130,9 @@ void Abc_SclTimeNtkPrint( SC_Man * p, int fShowAll, int fShort )
float
maxDelay
=
Abc_SclObjTimePs
(
p
,
pPivot
,
fRise
);
printf
(
"WireLoad model =
\"
%s
\"
. "
,
p
->
pWLoadUsed
?
p
->
pWLoadUsed
->
pName
:
"none"
);
printf
(
"Gates = %d. "
,
Abc_NtkNodeNum
(
p
->
pNtk
)
);
printf
(
"Area = %
.2f. "
,
Abc_SclGetTotalArea
(
p
)
);
printf
(
"Critical delay = %.2f ps
\n
"
,
maxDelay
);
printf
(
"Gates = %
6
d. "
,
Abc_NtkNodeNum
(
p
->
pNtk
)
);
printf
(
"Area = %
12.2f. "
,
Abc_SclGetTotalArea
(
p
)
);
printf
(
"Critical delay = %
8
.2f ps
\n
"
,
maxDelay
);
if
(
fShort
)
return
;
...
...
@@ -519,7 +520,7 @@ int Abc_SclHasBufferFanout( Abc_Obj_t * pObj )
return
1
;
return
0
;
}
void
Abc_Scl
_PrintBuffers
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
int
nOffset
)
void
Abc_Scl
PrintBuffersInt
(
SC_Man
*
p
,
Abc_Obj_t
*
pObj
,
int
nOffset
)
{
// SC_Cell_t * pCell = Abc_SclObjCell(p, pObj);
Abc_Obj_t
*
pFanout
;
...
...
@@ -541,7 +542,7 @@ void Abc_Scl_PrintBuffers( SC_Man * p, Abc_Obj_t * pObj, int nOffset )
printf
(
"
\n
"
);
Abc_ObjForEachFanout
(
pObj
,
pFanout
,
i
)
if
(
Abc_ObjIsBuffer
(
pFanout
)
)
Abc_Scl
_PrintBuffers
(
p
,
pFanout
,
nOffset
+
1
);
Abc_Scl
PrintBuffersInt
(
p
,
pFanout
,
nOffset
+
1
);
}
void
Abc_SclPrintBufferTrees
(
SC_Man
*
p
,
Abc_Ntk_t
*
pNtk
)
{
...
...
@@ -549,7 +550,7 @@ void Abc_SclPrintBufferTrees( SC_Man * p, Abc_Ntk_t * pNtk )
int
i
;
Abc_NtkForEachObj
(
pNtk
,
pObj
,
i
)
if
(
Abc_ObjIsBuffer
(
pObj
)
&&
Abc_SclHasBufferFanout
(
pObj
)
)
Abc_Scl
_PrintBuffers
(
p
,
pObj
,
0
),
printf
(
"
\n
"
);
Abc_Scl
PrintBuffersInt
(
p
,
pObj
,
0
),
printf
(
"
\n
"
);
}
void
Abc_SclPrintBuffers
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
int
fVerbose
)
{
...
...
src/map/scl/sclUpsize.c
View file @
a9afe7e8
...
...
@@ -194,16 +194,17 @@ void Abc_SclUnmarkCriticalNodeWindow( SC_Man * p, Vec_Int_t * vPath )
SeeAlso []
***********************************************************************/
Vec_Int_t
*
Abc_SclFindNodesToUpdate
(
Abc_Obj_t
*
pPivot
,
Vec_Int_t
**
pvEvals
)
void
Abc_SclFindNodesToUpdate
(
Abc_Obj_t
*
pPivot
,
Vec_Int_t
**
pvNodes
,
Vec_Int_t
**
pvEvals
)
{
Abc_Ntk_t
*
p
=
Abc_ObjNtk
(
pPivot
);
Abc_Obj_t
*
pObj
,
*
pNext
,
*
pNext2
;
Vec_Int_t
*
vNodes
;
Vec_Int_t
*
vNodes
=
*
pvNodes
;
Vec_Int_t
*
vEvals
=
*
pvEvals
;
int
i
,
k
;
assert
(
Abc_ObjIsNode
(
pPivot
)
);
assert
(
pPivot
->
fMarkA
);
// collect fanins, node, and fanouts
vNodes
=
Vec_IntAlloc
(
16
);
Vec_IntClear
(
vNodes
);
Abc_ObjForEachFanin
(
pPivot
,
pNext
,
i
)
if
(
Abc_ObjIsNode
(
pNext
)
&&
Abc_ObjFaninNum
(
pNext
)
>
0
)
Vec_IntPush
(
vNodes
,
Abc_ObjId
(
pNext
)
);
...
...
@@ -224,21 +225,20 @@ Vec_Int_t * Abc_SclFindNodesToUpdate( Abc_Obj_t * pPivot, Vec_Int_t ** pvEvals )
pObj
->
fMarkB
=
1
;
}
// collect nodes visible from the critical paths
*
pvEvals
=
Vec_IntAlloc
(
10
);
Vec_IntClear
(
vEvals
);
Abc_NtkForEachObjVec
(
vNodes
,
p
,
pObj
,
i
)
Abc_ObjForEachFanout
(
pObj
,
pNext
,
k
)
if
(
pNext
->
fMarkA
&&
!
pNext
->
fMarkB
)
// if ( !pNext->fMarkB )
{
assert
(
pObj
->
fMarkB
);
Vec_IntPush
(
*
p
vEvals
,
Abc_ObjId
(
pObj
)
);
Vec_IntPush
(
vEvals
,
Abc_ObjId
(
pObj
)
);
break
;
}
assert
(
Vec_IntSize
(
*
p
vEvals
)
>
0
);
assert
(
Vec_IntSize
(
vEvals
)
>
0
);
// label nodes
Abc_NtkForEachObjVec
(
vNodes
,
p
,
pObj
,
i
)
pObj
->
fMarkB
=
0
;
return
vNodes
;
}
...
...
@@ -253,7 +253,7 @@ Vec_Int_t * Abc_SclFindNodesToUpdate( Abc_Obj_t * pPivot, Vec_Int_t ** pvEvals )
SeeAlso []
***********************************************************************/
int
Abc_SclFindUpsizes
(
SC_Man
*
p
,
Vec_Int_t
*
vPathNodes
,
int
Ratio
,
int
Notches
,
int
iIter
)
int
Abc_SclFindUpsizes
(
SC_Man
*
p
,
Vec_Int_t
*
vPathNodes
,
int
Ratio
,
int
Notches
,
int
iIter
,
int
DelayGap
)
{
SC_Cell
*
pCellOld
,
*
pCellNew
;
Vec_Int_t
*
vRecalcs
,
*
vEvals
;
...
...
@@ -262,6 +262,8 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch
int
i
,
k
,
n
,
gateBest
,
Limit
,
iIterLast
;
// compute savings due to upsizing each node
vRecalcs
=
Vec_IntAlloc
(
100
);
vEvals
=
Vec_IntAlloc
(
100
);
Vec_QueClear
(
p
->
vNodeByGain
);
Abc_NtkForEachObjVec
(
vPathNodes
,
p
->
pNtk
,
pObj
,
i
)
{
...
...
@@ -269,7 +271,7 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch
if
(
iIterLast
>=
0
&&
iIterLast
+
10
>
iIter
)
continue
;
// compute nodes to recalculate timing and nodes to evaluate afterwards
vRecalcs
=
Abc_SclFindNodesToUpdate
(
pObj
,
&
vEvals
);
Abc_SclFindNodesToUpdate
(
pObj
,
&
vRecalcs
,
&
vEvals
);
assert
(
Vec_IntSize
(
vEvals
)
>
0
);
//printf( "%d -> %d\n", Vec_IntSize(vRecalcs), Vec_IntSize(vEvals) );
// save old gate, timing, fanin load
...
...
@@ -278,7 +280,7 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch
Abc_SclLoadStore
(
p
,
pObj
);
// try different gate sizes for this node
gateBest
=
-
1
;
dGainBest
=
0
.
0
;
dGainBest
=
-
SC_LibTimeFromPs
(
p
->
pLib
,
(
float
)
DelayGap
)
;
SC_RingForEachCell
(
pCellOld
,
pCellNew
,
k
)
{
if
(
pCellNew
==
pCellOld
)
...
...
@@ -316,15 +318,14 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch
// put back old cell and timing
Abc_SclObjSetCell
(
p
,
pObj
,
pCellOld
);
Abc_SclConeRestore
(
p
,
vRecalcs
);
// cleanup
}
Vec_IntFree
(
vRecalcs
);
Vec_IntFree
(
vEvals
);
}
if
(
Vec_QueSize
(
p
->
vNodeByGain
)
<
3
)
if
(
Vec_QueSize
(
p
->
vNodeByGain
)
==
0
)
return
0
;
Limit
=
Abc_MinInt
(
Vec_QueSize
(
p
->
vNodeByGain
),
(
int
)(
0
.
01
*
Ratio
*
Vec_IntSize
(
vPathNodes
))
+
1
);
//printf( "\nSelecting %d out of %d\n", Limit, Vec_QueSize(p->vNodeByGain) );
Limit
=
Abc_MinInt
(
Vec_QueSize
(
p
->
vNodeByGain
),
Abc_MaxInt
((
int
)(
0
.
01
*
Ratio
*
Vec_IntSize
(
vPathNodes
)),
1
)
);
//printf( "\nSelecting %d out of %d\n", Limit, Vec_QueSize(p->vNodeByGain) );
for
(
i
=
0
;
i
<
Limit
;
i
++
)
{
// get the object
...
...
@@ -334,8 +335,8 @@ int Abc_SclFindUpsizes( SC_Man * p, Vec_Int_t * vPathNodes, int Ratio, int Notch
pCellOld
=
Abc_SclObjCell
(
p
,
pObj
);
pCellNew
=
SC_LibCell
(
p
->
pLib
,
Vec_IntEntry
(
p
->
vNode2Gate
,
Abc_ObjId
(
pObj
))
);
assert
(
pCellNew
!=
NULL
);
//
printf( "%6d %20s -> %20s ", Abc_ObjId(pObj), pCellOld->pName, pCellNew->pName );
//
printf( "gain is %f\n", Vec_FltEntry(p->vNode2Gain, Abc_ObjId(pObj)) );
//
printf( "%6d %20s -> %20s ", Abc_ObjId(pObj), pCellOld->pName, pCellNew->pName );
//
printf( "gain is %f\n", Vec_FltEntry(p->vNode2Gain, Abc_ObjId(pObj)) );
// update gate
Abc_SclUpdateLoad
(
p
,
pObj
,
pCellOld
,
pCellNew
);
p
->
SumArea
+=
pCellNew
->
area
-
pCellOld
->
area
;
...
...
@@ -461,7 +462,7 @@ void Abc_SclUpsizePrint( SC_Man * p, int Iter, int win, int nPathPos, int nPathN
SeeAlso []
***********************************************************************/
void
Abc_SclUpsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_
Up
SizePars
*
pPars
)
void
Abc_SclUpsizePerform
(
SC_Lib
*
pLib
,
Abc_Ntk_t
*
pNtk
,
SC_SizePars
*
pPars
)
{
SC_Man
*
p
;
Vec_Int_t
*
vPathPos
=
NULL
;
// critical POs
...
...
@@ -473,12 +474,14 @@ void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_UpSizePars * pPar
if
(
pPars
->
fVerbose
)
{
printf
(
"
Upsizing p
arameters: "
);
printf
(
"
P
arameters: "
);
printf
(
"Iters =%5d. "
,
pPars
->
nIters
);
printf
(
"Time win =%3d %%. "
,
pPars
->
Window
);
printf
(
"Update ratio =%3d %%. "
,
pPars
->
Ratio
);
printf
(
"UseDept =%2d. "
,
pPars
->
fUseDept
);
printf
(
"UseWL =%2d. "
,
pPars
->
fUseWireLoads
);
printf
(
"Target =%5d ps. "
,
pPars
->
DelayUser
);
printf
(
"DelayGap =%3d ps. "
,
pPars
->
DelayGap
);
printf
(
"Timeout =%4d sec"
,
pPars
->
TimeOut
);
printf
(
"
\n
"
);
}
...
...
@@ -504,7 +507,7 @@ void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_UpSizePars * pPar
// selectively upsize the nodes
clk
=
Abc_Clock
();
nUpsizes
=
Abc_SclFindUpsizes
(
p
,
vPathNodes
,
pPars
->
Ratio
,
pPars
->
Notches
,
i
);
nUpsizes
=
Abc_SclFindUpsizes
(
p
,
vPathNodes
,
pPars
->
Ratio
,
pPars
->
Notches
,
i
,
pPars
->
DelayGap
);
p
->
timeSize
+=
Abc_Clock
()
-
clk
;
// unmark critical path
...
...
@@ -545,13 +548,6 @@ void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_UpSizePars * pPar
}
else
nFramesNoChange
++
;
if
(
nFramesNoChange
>
pPars
->
nIterNoChange
)
{
Vec_IntFree
(
vPathPos
);
Vec_IntFree
(
vPathNodes
);
Vec_IntFree
(
vTFO
);
break
;
}
// report and cleanup
Abc_SclUpsizePrint
(
p
,
i
,
win
,
Vec_IntSize
(
vPathPos
),
Vec_IntSize
(
vPathNodes
),
nUpsizes
,
Vec_IntSize
(
vTFO
),
pPars
->
fVeryVerbose
||
(
pPars
->
fVerbose
&&
nFramesNoChange
==
0
)
);
//|| (i == nIters-1) );
...
...
@@ -565,6 +561,12 @@ void Abc_SclUpsizePerform( SC_Lib * pLib, Abc_Ntk_t * pNtk, SC_UpSizePars * pPar
// check timeout
if
(
nRuntimeLimit
&&
Abc_Clock
()
>
nRuntimeLimit
)
break
;
// check no change
if
(
nFramesNoChange
>
pPars
->
nIterNoChange
)
break
;
// check best delay
if
(
p
->
BestDelay
<=
SC_LibTimeFromPs
(
p
->
pLib
,
(
float
)
pPars
->
DelayUser
)
)
break
;
}
// update for best gates and recompute timing
ABC_SWAP
(
Vec_Int_t
*
,
p
->
vGatesBest
,
p
->
vGates
);
...
...
src/map/scl/sclUtil.c
View file @
a9afe7e8
...
...
@@ -335,6 +335,8 @@ void Abc_SclMinsizePerform( SC_Lib * pLib, Abc_Ntk_t * p, int fUseMax, int fVerb
Abc_NtkForEachNode1
(
p
,
pObj
,
i
)
{
gateId
=
Vec_IntEntry
(
vGates
,
i
);
// if ( SC_LibCell(pLib, gateId)->n_outputs > 1 )
// continue;
assert
(
gateId
>=
0
&&
gateId
<
Vec_PtrSize
(
pLib
->
vCells
)
);
gateId
=
Vec_IntEntry
(
vMinCells
,
gateId
);
assert
(
gateId
>=
0
&&
gateId
<
Vec_PtrSize
(
pLib
->
vCells
)
);
...
...
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