Home | History | Annotate | Download | only in inc
      1 
      2 /*
      3  * Copyright (C) Texas Instruments - http://www.ti.com/
      4  *
      5  * This library is free software; you can redistribute it and/or
      6  * modify it under the terms of the GNU Lesser General Public
      7  * License as published by the Free Software Foundation; either
      8  * version 2.1 of the License, or (at your option) any later version.
      9  *
     10  *
     11  * This library is distributed in the hope that it will be useful,
     12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14  * Lesser General Public License for more details.
     15  *
     16  *
     17  * You should have received a copy of the GNU Lesser General Public
     18  * License along with this library; if not, write to the Free Software
     19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     20  */
     21 /* NOTE: This header should be only included from perf.h */
     22 
     23 /* this union is used to convert a float to a long representation without
     24    breaking strict aliasing rules */
     25 union __PERF_float_long
     26 {
     27     float f;
     28     unsigned long l;
     29 };
     30 
     31 /* combine 2 values in a unsigned long */
     32 #define PERF_mask(field, len) \
     33     ( ((unsigned long) (field)) & ((1 << (len)) - 1) )
     34 
     35 #define PERF_bits(field, start, len) \
     36     ( (((unsigned long) (field)) >> start) & ((1 << (len)) - 1) )
     37 
     38 #define PERF_log_combine(flag, field, len) \
     39     ( ((unsigned long) (flag)) | (PERF_mask(field, len) & PERF_LOG_NotMask) )
     40 
     41 #define PERF_COMBINE2(field1, len1, field2, len2) \
     42     ( ( PERF_mask(field1, len1) << (len2) ) |     \
     43         PERF_mask(field2, len2) )
     44 
     45 #define PERF_LOGCOMBINE2(flag, field1, len1, field2, len2)            \
     46     PERF_log_combine(flag, PERF_COMBINE2(field1, len1, field2, len2), \
     47     (len1) + (len2))
     48 
     49 #define PERF_COMBINE3(field1, len1, field2, len2, field3, len3) \
     50     ((( ( PERF_mask(field1, len1)   << (len2) ) |               \
     51           PERF_mask(field2, len2) ) << (len3) ) |               \
     52           PERF_mask(field3, len3) )
     53 
     54 #define PERF_LOGCOMBINE3(flag, field1, len1, field2, len2, field3, len3)     \
     55     PERF_log_combine(flag,                                                   \
     56                     PERF_COMBINE3(field1, len1, field2, len2, field3, len3), \
     57                     (len1) + (len2) + (len3))
     58 
     59 /*=============================================================================
     60     HARD CODED (default) INTERFACE
     61 
     62     This translates each instrumentation directly into a logging call.  It is
     63     always defined, so that the logs can be done by the custom interface.
     64 =============================================================================*/
     65 
     66 #define __PERF_LOG_Boundary(           \
     67         hObject,                       \
     68         eBoundary)                     \
     69     PERF_check((hObject),              \
     70      __PERF_log1(get_Private(hObject), \
     71                  PERF_log_combine(PERF_LOG_Boundary, eBoundary, 26)) ) /* Macro End */
     72 
     73 /* we squeeze PERF_LOG flag into 2 or 4 bits */
     74 #define __PERF_LOG_Buffer(                                                  \
     75         hObject,                                                            \
     76         flSending,                                                          \
     77         flMultiple,                                                         \
     78         flFrame,                                                            \
     79         ulAddress1,                                                         \
     80         ulAddress2,                                                         \
     81         ulSize,                                                             \
     82         eModule1,                                                           \
     83         eModule2)                                                           \
     84     PERF_check((hObject),                                                   \
     85      PERF_IsMultiple(flMultiple) ?                                          \
     86       __PERF_log3(get_Private(hObject),                                     \
     87                   PERF_IsXfering(flSending) ?                               \
     88                   (PERF_LOG_Buffer | PERF_LOG_Xfering |  /* 2 bits */       \
     89                    PERF_COMBINE3((ulSize) >> 3, 30 - 2 * PERF_ModuleBits,   \
     90                                  eModule2, PERF_ModuleBits,                 \
     91                                  eModule1, PERF_ModuleBits) ) :             \
     92                   (PERF_LOG_Buffer | flSending |  /* 4 bits */              \
     93                    PERF_COMBINE2(ulSize, 28 - PERF_ModuleBits,              \
     94                                  eModule1, PERF_ModuleBits) ),              \
     95                   ( ((unsigned long) (ulAddress1)) & ~3 ) |                 \
     96                   ( PERF_IsFrame   (flFrame)    ? PERF_LOG_Frame    : 0 ) | \
     97                   ( PERF_IsMultiple(flMultiple) ? PERF_LOG_Multiple : 0 ),  \
     98                   (unsigned long) (ulAddress2) ) :                          \
     99       __PERF_log2(get_Private(hObject),                                     \
    100                   PERF_IsXfering(flSending) ?                               \
    101                   (PERF_LOG_Buffer | PERF_LOG_Xfering |  /* 2 bits */       \
    102                    PERF_COMBINE3((ulSize) >> 3, 30 - 2 * PERF_ModuleBits,   \
    103                                  eModule2, PERF_ModuleBits,                 \
    104                                  eModule1, PERF_ModuleBits) ) :             \
    105                   (PERF_LOG_Buffer | flSending | /* 4 bits */               \
    106                    PERF_COMBINE2(ulSize, 28 - PERF_ModuleBits,              \
    107                                  eModule1, PERF_ModuleBits) ),              \
    108                   ( ((unsigned long) (ulAddress1)) & ~3 ) |                 \
    109                   ( PERF_IsFrame   (flFrame)    ? PERF_LOG_Frame    : 0 ) | \
    110                   ( PERF_IsMultiple(flMultiple) ? PERF_LOG_Multiple : 0 ) ))
    111 
    112 #define __PERF_LOG_Command(                                               \
    113         hObject,                                                          \
    114         ulSending,                                                        \
    115         ulArgument,                                                       \
    116         ulCommand,                                                        \
    117         eModule)                                                          \
    118     PERF_check((hObject),                                                 \
    119      __PERF_log3(get_Private(hObject),                                    \
    120                  PERF_log_combine(PERF_LOG_Command | ulSending, eModule, 28), \
    121                  ((unsigned long) (ulCommand)),                           \
    122                  ((unsigned long) (ulArgument)) ) ) /* Macro End */
    123 
    124 #define __PERF_LOG_Log(                              \
    125         hObject,                                     \
    126         ulData1,                                     \
    127         ulData2,                                     \
    128         ulData3)                                     \
    129     PERF_check((hObject),                            \
    130     __PERF_log3(get_Private(hObject),                \
    131         PERF_log_combine(PERF_LOG_Log, ulData1, 28), \
    132         ((unsigned long) (ulData2)),                 \
    133         ((unsigned long) (ulData3)) ) ) /* Macro End */
    134 
    135 #define __PERF_LOG_SyncAV(                                                \
    136         hObject,                                                          \
    137         fTimeAudio,                                                       \
    138         fTimeVideo,                                                       \
    139         eSyncOperation)                                                   \
    140     do                                                                    \
    141     {                                                                     \
    142         union __PERF_float_long uA,uV;                                    \
    143         uA.f = fTimeAudio;  uV.f = fTimeVideo;                            \
    144         PERF_check((hObject),                                             \
    145          __PERF_log3(get_Private(hObject),                                \
    146                      PERF_log_combine(PERF_LOG_Sync, eSyncOperation, 28), \
    147                      uA.l, uV.l));                                        \
    148     }\
    149     while(0) /* Macro End */
    150 
    151 #define __PERF_LOG_ThreadCreated(                          \
    152         hObject,                                           \
    153         ulThreadID,                                        \
    154         ulThreadName)                                      \
    155     PERF_check((hObject),                                  \
    156     __PERF_log2(get_Private(hObject),                      \
    157         PERF_log_combine(PERF_LOG_Thread, ulThreadID, 26), \
    158         ((unsigned long) (ulThreadName)) ) ) /* Macro End */
    159 
    160 
    161 /* ============================================================================
    162    PERF LOG Data Structures
    163 ============================================================================ */
    164 
    165 /* private PERF structure for logging */
    166 typedef struct PERF_LOG_Private
    167 {
    168     unsigned long   uBufferCount; /* number of buffers filled */
    169     unsigned long   uBufSize;     /* size of buffer */
    170     unsigned long  *puBuffer;     /* start of current buffer */
    171     unsigned long  *puEnd;        /* 'end' of current buffer */
    172     unsigned long  *puPtr;        /* current buffer pointer */
    173     FILE *fOut;                   /* output file */
    174     char *fOutFile;               /* output file name */
    175 } PERF_LOG_Private;
    176 
    177 /* log flags used */
    178 enum PERF_LogStamps
    179 {
    180     /* 1 arguments */
    181     PERF_LOG_Done     = 0x00000000,
    182     PERF_LOG_Boundary = 0x08000000,
    183     /* 2 arguments */
    184     PERF_LOG_Thread   = 0x0C000000,
    185     /* 3 arguments */
    186     PERF_LOG_Log      = 0x10000000,
    187     PERF_LOG_Sync     = 0x20000000,
    188 #ifdef __PERF_LOG_LOCATION__
    189     /* many arguments */
    190     PERF_LOG_Location = 0x30000000,
    191 #endif
    192     PERF_LOG_Command  = 0x40000000,  /* - 0x70000000 */
    193     /* 2 or 3 arguments */
    194     PERF_LOG_Buffer   = 0x80000000,  /* - 0xF0000000 */
    195 
    196     /* flags and masks */
    197     PERF_LOG_Mask     = 0xF0000000,
    198     PERF_LOG_NotMask  = ~PERF_LOG_Mask,
    199     PERF_LOG_Mask2    = 0xFC000000,
    200     PERF_LOG_NotMask2 = ~PERF_LOG_Mask2,
    201     PERF_LOG_Frame    = 0x00000002,
    202     PERF_LOG_Multiple = 0x00000001,
    203 
    204     /* NOTE: we identify xfer buffer from upper 2 bits (11) */
    205     PERF_LOG_Xfering  = 0x40000000,
    206     /* NOTE: we identify other buffer logs from upper 4 bits (1000 or 1011) */
    207     PERF_LOG_Sending  = 0x30000000,
    208 };
    209 
    210 
    211 #ifdef __PERF_LOG_LOCATION__
    212 
    213 /* PERF log locations are encoded in 6-bits/char.  The last 20 characters of
    214    the filename and functionname are saved (20*6*2 bits), along with the last
    215    12 bits of the line.  4-bit log stamp makes this 240+12+4=256 bits.  */
    216 
    217 /* __PERF_ENCODE_CHAR converts a character to a 6-bit value:
    218     a-z => 0-25
    219     A-Z => 26-51
    220     1-9 => 52-60
    221       0 => 'O' (41)
    222       . => 61
    223     /,\ => 62
    224  else,_ => 63         */
    225 #define __PERF_ENCODE_CHAR(c) \
    226    ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 'a')      : \
    227      ((c) >= 'A' && (c) <= 'Z') ? ((c) - 'A' + 26) : \
    228      ((c) >= '1' && (c) <= '9') ? ((c) - '1' + 52) : \
    229                      (c) == '.' ? 61 :               \
    230                      (c) == '0' ? ('O' - 'A' + 26) : \
    231     ((c) == '/' || (c) == '\\') ? 62 : 63 )
    232 
    233 /* Get the i-th character from the end of a string, or '/' if i is too big */
    234 #define __PERF_GET_INDEXED_CHAR(sz, i) (strlen(sz) <= i ? '/' : sz[strlen(sz) - i - 1])
    235 
    236 /* Encode i-th character of a string (from the end) */
    237 #define __PERF_ENCODE_INDEXED(sz, i) \
    238     __PERF_ENCODE_CHAR(__PERF_GET_INDEXED_CHAR(sz, i))
    239 
    240 /* Encode and pack 6 characters into 32 bits.  Only the left 2 bits of the
    241    6th character will fit */
    242 #define __PERF_PACK6(a1,a2,a3,a4,a5,a6) \
    243     (((unsigned long) (a1))        | \
    244     (((unsigned long) (a2)) << 6)  | \
    245     (((unsigned long) (a3)) << 12) | \
    246     (((unsigned long) (a4)) << 18) | \
    247     (((unsigned long) (a5)) << 24) | \
    248    ((((unsigned long) (a6)) & 0x30) << 26))
    249 
    250 #endif
    251 
    252 /* ============================================================================
    253    PERF LOG External methods
    254 ============================================================================ */
    255 
    256 extern void __PERF_LOG_log_common(PERF_Private *perf, unsigned long *time_loc);
    257 
    258 /* ============================================================================
    259    PERF LOG Inline methods
    260 ============================================================================ */
    261 #if defined(__PERF_C__) || defined(INLINE_SUPPORTED)
    262 
    263 /* Effects: logs 1 data */
    264 INLINE void __PERF_log1(PERF_Private *priv,
    265                         unsigned long ulData1)
    266 {
    267     /* get log private structures */
    268     PERF_LOG_Private *me   = priv->pLog;
    269     unsigned long *time_loc = me->puPtr++;
    270 
    271     *me->puPtr++ = ulData1;
    272     __PERF_LOG_log_common(priv, time_loc);
    273 }
    274 
    275 /* Effects: logs 2 data */
    276 INLINE void __PERF_log2(PERF_Private *priv,
    277                         unsigned long ulData1,
    278                         unsigned long ulData2)
    279 {
    280     /* get log private structures */
    281     PERF_LOG_Private *me   = priv->pLog;
    282     unsigned long *time_loc = me->puPtr++;
    283 
    284     *me->puPtr++ = ulData1;
    285     *me->puPtr++ = ulData2;
    286     __PERF_LOG_log_common(priv, time_loc);
    287 }
    288 
    289 /* Effects: logs 3 data */
    290 INLINE void __PERF_log3(PERF_Private *priv,
    291                         unsigned long ulData1,
    292                         unsigned long ulData2,
    293                         unsigned long ulData3)
    294 {
    295     /* get log private structures */
    296     PERF_LOG_Private *me   = priv->pLog;
    297     unsigned long *time_loc = me->puPtr++;
    298 
    299     *me->puPtr++ = ulData1;
    300     *me->puPtr++ = ulData2;
    301     *me->puPtr++ = ulData3;
    302     __PERF_LOG_log_common(priv, time_loc);
    303 }
    304 
    305 #ifdef __PERF_LOG_LOCATION__
    306 
    307 void __PERF_LOG_flush(PERF_LOG_Private *me);
    308 
    309 /* Effects: logs 3 data */
    310 INLINE void
    311 __PERF_log8(PERF_Private *priv,
    312             unsigned long ulData1,
    313             unsigned long ulData2,
    314             unsigned long ulData3,
    315             unsigned long ulData4,
    316             unsigned long ulData5,
    317             unsigned long ulData6,
    318             unsigned long ulData7,
    319             unsigned long ulData8)
    320 {
    321     /* get log private structures */
    322     PERF_LOG_Private *me   = priv->pLog;
    323 
    324     *me->puPtr++ = ulData8;
    325     *me->puPtr++ = (ulData1 & PERF_LOG_NotMask) | PERF_LOG_Location;
    326     *me->puPtr++ = ulData2;
    327     *me->puPtr++ = ulData3;
    328     *me->puPtr++ = ulData4;
    329     *me->puPtr++ = ulData5;
    330     *me->puPtr++ = ulData6;
    331     *me->puPtr++ = ulData7;
    332 
    333     /* flush if we reached end of the buffer */
    334     if (me->puPtr > me->puEnd) __PERF_LOG_flush(me);
    335 }
    336 
    337 INLINE void
    338 __PERF_LOG_Location(PERF_OBJHANDLE hObject,
    339                     const char *szFile,
    340                     unsigned long ulLine,
    341                     const char *szFunc)
    342 {
    343     if (hObject)
    344     {
    345         unsigned long a6  = __PERF_ENCODE_INDEXED(szFile, 5);
    346         unsigned long a12 = __PERF_ENCODE_INDEXED(szFile, 11);
    347         unsigned long a18 = __PERF_ENCODE_INDEXED(szFile, 17);
    348         unsigned long b6  = __PERF_ENCODE_INDEXED(szFunc, 5);
    349         unsigned long b12 = __PERF_ENCODE_INDEXED(szFunc, 11);
    350         unsigned long b18 = __PERF_ENCODE_INDEXED(szFunc, 17);
    351 
    352         /* get log private structures */
    353         __PERF_log8(get_Private(hObject),
    354                     (a18 & 0xf) | ((b6 & 0xf) << 4) | ((b12 & 0xf) << 8) |
    355                     ((b18 & 0xf) << 12) | ((ulLine & 0xfff) << 16),
    356                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 0),
    357                                  __PERF_ENCODE_INDEXED(szFile, 1),
    358                                  __PERF_ENCODE_INDEXED(szFile, 2),
    359                                  __PERF_ENCODE_INDEXED(szFile, 3),
    360                                  __PERF_ENCODE_INDEXED(szFile, 4), a6),
    361                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 6),
    362                                  __PERF_ENCODE_INDEXED(szFile, 7),
    363                                  __PERF_ENCODE_INDEXED(szFile, 8),
    364                                  __PERF_ENCODE_INDEXED(szFile, 9),
    365                                  __PERF_ENCODE_INDEXED(szFile, 10), a12),
    366                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 12),
    367                                  __PERF_ENCODE_INDEXED(szFile, 13),
    368                                  __PERF_ENCODE_INDEXED(szFile, 14),
    369                                  __PERF_ENCODE_INDEXED(szFile, 15),
    370                                  __PERF_ENCODE_INDEXED(szFile, 16), a18),
    371                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 0),
    372                                  __PERF_ENCODE_INDEXED(szFunc, 1),
    373                                  __PERF_ENCODE_INDEXED(szFunc, 2),
    374                                  __PERF_ENCODE_INDEXED(szFunc, 3),
    375                                  __PERF_ENCODE_INDEXED(szFunc, 4), b6),
    376                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 6),
    377                                  __PERF_ENCODE_INDEXED(szFunc, 7),
    378                                  __PERF_ENCODE_INDEXED(szFunc, 8),
    379                                  __PERF_ENCODE_INDEXED(szFunc, 9),
    380                                  __PERF_ENCODE_INDEXED(szFunc, 10), b12),
    381                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 12),
    382                                  __PERF_ENCODE_INDEXED(szFunc, 13),
    383                                  __PERF_ENCODE_INDEXED(szFunc, 14),
    384                                  __PERF_ENCODE_INDEXED(szFunc, 15),
    385                                  __PERF_ENCODE_INDEXED(szFunc, 16), b18),
    386                     __PERF_ENCODE_INDEXED(szFile, 18) |
    387                     (__PERF_ENCODE_INDEXED(szFile, 19) << 6)  |
    388                     (__PERF_ENCODE_INDEXED(szFunc, 18) << 12) |
    389                     (__PERF_ENCODE_INDEXED(szFunc, 19) << 18) |
    390                     ((a6 & 0xf) << 24) | ((a12 & 0xf) << 28) );
    391     }
    392 }
    393 
    394 #endif
    395 
    396 #else
    397 
    398 extern void __PERF_log1(PERF_Private *priv,
    399                         unsigned long ulData1);
    400 extern void __PERF_log2(PERF_Private *priv,
    401                         unsigned long ulData1,
    402                         unsigned long ulData2);
    403 extern void __PERF_log3(PERF_Private *priv,
    404                         unsigned long ulData1,
    405                         unsigned long ulData2,
    406                         unsigned long ulData3);
    407 
    408 #ifdef __PERF_LOG_LOCATION__
    409 
    410 extern void __PERF_log8(PERF_Private *priv,
    411                         unsigned long ulData1,
    412                         unsigned long ulData2,
    413                         unsigned long ulData3,
    414                         unsigned long ulData4,
    415                         unsigned long ulData5,
    416                         unsigned long ulData6,
    417                         unsigned long ulData7,
    418                         unsigned long ulData8);
    419 
    420 
    421 #define __PERF_LOG_Location(hObject, szFile, ulLine, szFunc)           \
    422 do                                                                     \
    423 {                                                                      \
    424     if (hObject)                                                       \
    425     {                                                                  \
    426         unsigned long a6  = __PERF_ENCODE_INDEXED(szFile, 5);          \
    427         unsigned long a12 = __PERF_ENCODE_INDEXED(szFile, 11);         \
    428         unsigned long a18 = __PERF_ENCODE_INDEXED(szFile, 17);         \
    429         unsigned long b6  = __PERF_ENCODE_INDEXED(szFunc, 5);          \
    430         unsigned long b12 = __PERF_ENCODE_INDEXED(szFunc, 11);         \
    431         unsigned long b18 = __PERF_ENCODE_INDEXED(szFunc, 17);         \
    432                                                                        \
    433         __PERF_log8(get_Private(hObject),                              \
    434                     (a18 & 0xf)        | ((b6 & 0xf) << 4)   |         \
    435                     ((b12 & 0xf) << 8) | ((b18 & 0xf) << 12) |         \
    436                     ((ulLine & 0xfff) << 16),                          \
    437                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 0),     \
    438                               __PERF_ENCODE_INDEXED(szFile, 1),        \
    439                               __PERF_ENCODE_INDEXED(szFile, 2),        \
    440                               __PERF_ENCODE_INDEXED(szFile, 3),        \
    441                               __PERF_ENCODE_INDEXED(szFile, 4), a6),   \
    442                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 6),     \
    443                               __PERF_ENCODE_INDEXED(szFile, 7),        \
    444                               __PERF_ENCODE_INDEXED(szFile, 8),        \
    445                               __PERF_ENCODE_INDEXED(szFile, 9),        \
    446                               __PERF_ENCODE_INDEXED(szFile, 10), a12), \
    447                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFile, 12),    \
    448                               __PERF_ENCODE_INDEXED(szFile, 13),       \
    449                               __PERF_ENCODE_INDEXED(szFile, 14),       \
    450                               __PERF_ENCODE_INDEXED(szFile, 15),       \
    451                               __PERF_ENCODE_INDEXED(szFile, 16), a18), \
    452                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 0),     \
    453                               __PERF_ENCODE_INDEXED(szFunc, 1),        \
    454                               __PERF_ENCODE_INDEXED(szFunc, 2),        \
    455                               __PERF_ENCODE_INDEXED(szFunc, 3),        \
    456                               __PERF_ENCODE_INDEXED(szFunc, 4), b6),   \
    457                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 6),     \
    458                               __PERF_ENCODE_INDEXED(szFunc, 7),        \
    459                               __PERF_ENCODE_INDEXED(szFunc, 8),        \
    460                               __PERF_ENCODE_INDEXED(szFunc, 9),        \
    461                               __PERF_ENCODE_INDEXED(szFunc, 10), b12), \
    462                     __PERF_PACK6(__PERF_ENCODE_INDEXED(szFunc, 12),    \
    463                               __PERF_ENCODE_INDEXED(szFunc, 13),       \
    464                               __PERF_ENCODE_INDEXED(szFunc, 14),       \
    465                               __PERF_ENCODE_INDEXED(szFunc, 15),       \
    466                               __PERF_ENCODE_INDEXED(szFunc, 16), b18), \
    467                     __PERF_ENCODE_INDEXED(szFile, 18) |                \
    468                     (__PERF_ENCODE_INDEXED(szFile, 19) << 6)  |        \
    469                     (__PERF_ENCODE_INDEXED(szFunc, 18) << 12) |        \
    470                     (__PERF_ENCODE_INDEXED(szFunc, 19) << 18) |        \
    471                     ((a6 & 0xf) << 24) |  ((a12 & 0xf) << 28));        \
    472     }                                                                  \
    473 }                                                                      \
    474 while (0);
    475 
    476 #endif
    477 
    478 #endif
    479 
    480