GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / cfe / cfe / arch / mips / cpu / sb1250 / src / sb1250_l1cache.S
blob5ba2563936c761725338bb542c4cae4033e2042c
1 /*  *********************************************************************
2     *  SB1250 Board Support Package
3     *  
4     *  L1 Cache initialization                  File: sb1250_l1cache.S
5     *  
6     *  This module contains code to initialize the L1 cache.
7     *  
8     *  Note: all the routines in this module rely on registers only,
9     *        since DRAM may not be active yet.
10     *
11     *  Author:  Mitch Lichtenberg (mpl@broadcom.com)
12     *  
13     *********************************************************************  
14     *
15     *  Copyright 2000,2001,2002,2003
16     *  Broadcom Corporation. All rights reserved.
17     *  
18     *  This software is furnished under license and may be used and 
19     *  copied only in accordance with the following terms and 
20     *  conditions.  Subject to these conditions, you may download, 
21     *  copy, install, use, modify and distribute modified or unmodified 
22     *  copies of this software in source and/or binary form.  No title 
23     *  or ownership is transferred hereby.
24     *  
25     *  1) Any source code used, modified or distributed must reproduce 
26     *     and retain this copyright notice and list of conditions 
27     *     as they appear in the source file.
28     *  
29     *  2) No right is granted to use any trade name, trademark, or 
30     *     logo of Broadcom Corporation.  The "Broadcom Corporation" 
31     *     name may not be used to endorse or promote products derived 
32     *     from this software without the prior written permission of 
33     *     Broadcom Corporation.
34     *  
35     *  3) THIS SOFTWARE IS PROVIDED "AS-IS" AND ANY EXPRESS OR
36     *     IMPLIED WARRANTIES, INCLUDING BUT NOT LIMITED TO, ANY IMPLIED
37     *     WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR 
38     *     PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT 
39     *     SHALL BROADCOM BE LIABLE FOR ANY DAMAGES WHATSOEVER, AND IN 
40     *     PARTICULAR, BROADCOM SHALL NOT BE LIABLE FOR DIRECT, INDIRECT,
41     *     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
42     *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
43     *     GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
44     *     BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
45     *     OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 
46     *     TORT (INCLUDING NEGLIGENCE OR OTHERWISE), EVEN IF ADVISED OF 
47     *     THE POSSIBILITY OF SUCH DAMAGE.
48     ********************************************************************* */
50 #include "sbmips.h"
51 #include "mipsmacros.h"
52 #include "sb1250_defs.h"
53 #include "sb1250_regs.h"
54 #include "sb1250_scd.h"
55 #include "sb1250_wid.h"
58  * This lets us override the WID by poking values into our PromICE 
59  */
60 #ifdef _MAGICWID_
61 #undef A_SCD_SYSTEM_REVISION
62 #define A_SCD_SYSTEM_REVISION 0x1FC00508
63 #endif
65                 .text
67                 .set    mips64
70 /*  *********************************************************************
71     *  Macros
72     ********************************************************************* */
74 #define L1CACHE_NUMWAYS 4
75 #define L1CACHE_NUMIDX  256
76 #define L1CACHE_LINESIZE 32
77 #define L1CACHE_IDXHIGH (L1CACHE_LINESIZE*L1CACHE_NUMWAYS*L1CACHE_NUMIDX)
79 #define L1CACHEOP(cachename,op) ((cachename) | ((op) << 2))
81 #define L1C_OP_IDXINVAL     0
82 #define L1C_OP_IDXLOADTAG   1
83 #define L1C_OP_IDXSTORETAG  2
84 #define L1C_OP_IMPLRSVD     3
85 #define L1C_OP_HITINVAL     4
86 #define L1C_OP_FILL         5
87 #define L1C_OP_HITWRITEBACK 6
88 #define L1C_OP_FETCHLOCK    7
90 #define L1C_I               0
91 #define L1C_D               1
94  * CP0 C0_TAGHI values for cache freezing/way elimination
95  */
97 #define L1C_LRU_FREEZE0     (1<<22)|(3<<20)|(2<<18)|(1<<16)|(0<<14)     /* 3,2,1,0[F] */
98 #define L1C_LRU_FREEZE1     (1<<22)|(3<<20)|(2<<18)|(0<<16)|(1<<14)     /* 3,2,0,1[F] */
99 #define L1C_LRU_FREEZE2     (1<<22)|(3<<20)|(0<<18)|(1<<16)|(2<<14)     /* 3,0,1,2[F] */
100 #define L1C_LRU_FREEZE3     (1<<22)|(2<<20)|(1<<18)|(0<<16)|(3<<14)     /* 2,1,0,3[F] */
102 #define L1C_LRU_REMOVE0     (1<<22)|(3<<20)|(2<<18)|(1<<16)|(3<<14)     /* 3,2,1,3 */
103 #define L1C_LRU_REMOVE1     (1<<22)|(3<<20)|(2<<18)|(0<<16)|(2<<14)     /* 3,2,0,2 */
104 #define L1C_LRU_REMOVE2     (1<<22)|(3<<20)|(0<<18)|(1<<16)|(1<<14)     /* 3,0,1,1 */
105 #define L1C_LRU_REMOVE3     (1<<22)|(2<<20)|(1<<18)|(0<<16)|(0<<14)     /* 2,1,0,0 */
108  * Macro to test bin numbers
109  */
111 #define HAZARD ssnop ;  ssnop ;  ssnop ;  ssnop ;  ssnop ;  ssnop ;  ssnop
113 #define IF_BIN(binreg,binmask,label) \
114         .set noat ; \
115         andi AT,binreg,binmask ; \
116         bne  AT,zero,label ; \
117         .set at
119 #define IF_CPU1(label) \
120         .set noat ; \
121         mfc0 AT,C0_PRID ; \
122         srl  AT,AT,25 ; \
123         andi AT,AT,7 ; \
124         bne  AT,zero,label ; \
125         .set at
127 /*  *********************************************************************
128     *  SB1250_L1CACHE_DISABLETABLE
129     *  
130     *  This table maps the bits in the diagnostic result 
131     *  register (part of WID) to which ways we want to enable/remove
132     *  from the L1.
133     *  
134     *  The format of the table is:
135     *  
136     *       X DD II
137     *  
138     *  Where X is one for 1/4 (way indicated is the GOOD way)
139     *  or    X is zero for 3/4 (way indicated is the BAD way)
140     *  
141     *  and
142     *  
143     *  DD is the way number for the DCache
144     *  II is the way number for the ICache
145     *  
146     *  there are 32 64-bit entries in this table.
147     ********************************************************************* */
149 #define L1DISTBL(d,i)  (d),(i)
151 sb1250_l1cache_disabletable:
153         .word   L1DISTBL(L1C_LRU_REMOVE0, L1C_LRU_REMOVE0)
154         .word   L1DISTBL(L1C_LRU_REMOVE0, L1C_LRU_REMOVE1)
155         .word   L1DISTBL(L1C_LRU_REMOVE0, L1C_LRU_REMOVE2)
156         .word   L1DISTBL(L1C_LRU_REMOVE0, L1C_LRU_REMOVE3)
158         .word   L1DISTBL(L1C_LRU_REMOVE1, L1C_LRU_REMOVE0)
159         .word   L1DISTBL(L1C_LRU_REMOVE1, L1C_LRU_REMOVE1)
160         .word   L1DISTBL(L1C_LRU_REMOVE1, L1C_LRU_REMOVE2)
161         .word   L1DISTBL(L1C_LRU_REMOVE1, L1C_LRU_REMOVE3)
163         .word   L1DISTBL(L1C_LRU_REMOVE2, L1C_LRU_REMOVE0)
164         .word   L1DISTBL(L1C_LRU_REMOVE2, L1C_LRU_REMOVE1)
165         .word   L1DISTBL(L1C_LRU_REMOVE2, L1C_LRU_REMOVE2)
166         .word   L1DISTBL(L1C_LRU_REMOVE2, L1C_LRU_REMOVE3)
168         .word   L1DISTBL(L1C_LRU_REMOVE3, L1C_LRU_REMOVE0)
169         .word   L1DISTBL(L1C_LRU_REMOVE3, L1C_LRU_REMOVE1)
170         .word   L1DISTBL(L1C_LRU_REMOVE3, L1C_LRU_REMOVE2)
171         .word   L1DISTBL(L1C_LRU_REMOVE3, L1C_LRU_REMOVE3)
173         .word   L1DISTBL(L1C_LRU_FREEZE0, L1C_LRU_FREEZE0)
174         .word   L1DISTBL(L1C_LRU_FREEZE0, L1C_LRU_FREEZE1)
175         .word   L1DISTBL(L1C_LRU_FREEZE0, L1C_LRU_FREEZE2)
176         .word   L1DISTBL(L1C_LRU_FREEZE0, L1C_LRU_FREEZE3)
178         .word   L1DISTBL(L1C_LRU_FREEZE1, L1C_LRU_FREEZE0)
179         .word   L1DISTBL(L1C_LRU_FREEZE1, L1C_LRU_FREEZE1)
180         .word   L1DISTBL(L1C_LRU_FREEZE1, L1C_LRU_FREEZE2)
181         .word   L1DISTBL(L1C_LRU_FREEZE1, L1C_LRU_FREEZE3)
183         .word   L1DISTBL(L1C_LRU_FREEZE2, L1C_LRU_FREEZE0)
184         .word   L1DISTBL(L1C_LRU_FREEZE2, L1C_LRU_FREEZE1)
185         .word   L1DISTBL(L1C_LRU_FREEZE2, L1C_LRU_FREEZE2)
186         .word   L1DISTBL(L1C_LRU_FREEZE2, L1C_LRU_FREEZE3)
188         .word   L1DISTBL(L1C_LRU_FREEZE3, L1C_LRU_FREEZE0)
189         .word   L1DISTBL(L1C_LRU_FREEZE3, L1C_LRU_FREEZE1)
190         .word   L1DISTBL(L1C_LRU_FREEZE3, L1C_LRU_FREEZE2)
191         .word   L1DISTBL(L1C_LRU_FREEZE3, L1C_LRU_FREEZE3)
196 /*  *********************************************************************
197     *  SB1250_L1CACHE_INIT()
198     *  
199     *  Initialize the L1 Cache tags to be "invalid"
200     *  
201     *  Input parameters: 
202     *      nothing
203     *      
204     *  Return value:
205     *      nothing
206     *  
207     *  Registers used:
208     *      t0,t1,t2,t3
209     ********************************************************************* */
211         
212 LEAF(sb1250_l1cache_init)
214         /*
215          * Test to see if we're running on a pre-production part with
216          * a defective L1 cache.  We store information in the SCD
217          * SYSTEM_REVISION register that identifies what is
218          * going on.
219          */
221         /*
222          * First, check the part number 
223          */
225                 li      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
227                 ld      t1,0(t0)                        /* get SYSTEM_REVISION */
229                 dsrl    t1,t1,S_SYS_PART
230                 andi    t1,t1,(M_SYS_PART >> S_SYS_PART)
232                 beq     t1,0x1250,sb1250_l1cache_check_rev /* Go if real 1250 */
233                 beq     t1,0x1150,sb1250_l1cache_check_rev /* or 1250 in uni-cpu mode */
234                 b       sb1250_l1cache_init_good        /* otherwise not a 1250, no WID check */
236         /*
237          * Now, check the revision.  Anything earlier than step A3 
238          * does not need this check. Pass 3 does not need this check also.
239          *
240          * Exception: Step A6 parts return 0x04 in their revision field.
241          * These parts can can be verified as A6 by having a nonzero WID.
242          */
244 sb1250_l1cache_check_rev:
245                 ld      t1,0(t0)                        /* get the SYSTEM_REVISION again */
246                 dsrl    t1,t1,S_SYS_REVISION
247                 andi    t1,t1,(M_SYS_REVISION >> S_SYS_REVISION)
248                 beq     t1,0x04,sb1250_l1cache_check_wid
249                 blt     t1,0x05,sb1250_l1cache_init_good
250                 bge     t1,0x20,sb1250_l1cache_init_good
252         /*
253          * Okay, we really need to check the WID now.  If the WID is 
254          * not programmed at all, assume the part is good.
255          * (yes, this includes the wafer/lot bits)
256          */
258 sb1250_l1cache_check_wid:
259                 ld      t1,0(t0)                        /* Get the WID bits back */
260                 dsrl    t1,t1,S_SYS_WID                 /* wafer ID to bits 0..31 */
261                 li      t2,(M_SYS_WID >> S_SYS_WID)
262                 and     t1,t1,t2
264                 WID_UNCONVOLUTE(t1,t2,t3,t4)
266                 beq     t1,zero,sb1250_l1cache_init_good
268         /*
269          * Get the bin number from the WID.  This tells us many things.
270          * For the L1 cache we need to know which ways to use,
271          * and this is determined by what we put in the tag registers.
272          */
274                 dmtc0   zero,C0_TAGLO                   /* assume all is good. */
275                 dmtc0   zero,C0_TAGHI
276                 dmtc0   zero,C0_TAGLO,2
277                 dmtc0   zero,C0_TAGHI,2
279                 andi    t0,t1,M_WID_BIN                 /* bin # into T0 */
280                 li      t2,1                            /* make a bitmask */
281                 sll     t0,t2,t0                        /* put '1' in correct place */
283         /*
284          * t0 now contains a single bit set corresponding to the bin number
285          * that this chip belongs to.
286          * for example, if it is in bin 4, then the value is 1<<4
287          */
289         /*
290          * Check for the case of a fully operational cache.
291          */
293                 IF_BIN(t0,M_WID_BIN_FID,sb1250_l1cache_init_good)
295         /*
296          * Now compute an index into the table using the WID bits and
297          * the "3/4" value from the bin number.
298          */
300                 li      t1,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
301                 ld      t1,0(t1)                        /* get SYSTEM_REVISION */
302                 dsrl    t1,t1,S_SYS_WID                 /* get WID bits */
304                 WID_UNCONVOLUTE(t1,t2,t3,t4)
306                 IF_CPU1(sb1250_l1init_cpu1)
308                 li      t2,PHYS_TO_K1(A_SCD_SYSTEM_CFG)
309                 ld      t2,0(t2)
310                 dli     t3,M_SYS_UNICPU1
311                 and     t2,t3                   /* T2 nonzero if UNICPU1 */
312                 bne     t2,zero,sb1250_l1init_cpu1
315 sb1250_l1init_cpu0:
316                 li      t2,S_WID_CPU0
317                 b       sb1250_l1init_cont
319 sb1250_l1init_cpu1:
320                 li      t2,S_WID_CPU1
323 sb1250_l1init_cont:
324                 dsrl    t1,t1,t2                        /* move CPU way bits into posn */
325                 andi    t1,t1,(M_WID_CPUX_L1I|M_WID_CPUX_L1D) /* keep only way bits */
328                 IF_BIN(t0,M_WID_BIN_3ID,1f)
329                 ori     t1,t1,0x10                      /* 1/4 bit set */
332         /*
333          * Okay, now t1 is the index into the table.
334          * Look up the I and D way disable values from the table and store
335          * them in the TAGHI and TAGHI,2 registers.
336          */
337                 sll     t1,3                            /* make 64-bit offset */
339                 move    t3,ra
340                 LOADREL(t2,sb1250_l1cache_disabletable)
341                 or      t2,K1BASE
342                 move    ra,t3
343                 add     t2,t2,t1                        /* t2 points at our table entry */
345                 lw      t1,0(t2)                        /* DCache disable mask */
346                 dmtc0   t1,C0_TAGHI,2
347                 lw      t1,4(t2)                        /* ICache disable mask */
348                 dmtc0   t1,C0_TAGHI
350         /*
351          * Go ahead and initialize the cache now, using the
352          * values programmed into the TAGHI registers.
353          *
354          * T0 is _still_ our bitmask from the bin register.  We will
355          * need that later.
356          */
359                 li      t2,K1BASE
360 #ifdef _FASTINIT_
361                 li      t3,L1CACHE_LINESIZE*8                   /* only 8 indicies now */
362 #else
363                 li      t3,L1CACHE_IDXHIGH
364 #endif
366                 add     t1,t2,t3
367 1:              cache   L1CACHEOP(L1C_I,L1C_OP_IDXSTORETAG),0(t2)
368                 addu    t2,L1CACHE_LINESIZE
369                 bne     t1,t2,1b
371                 li      t2,K1BASE
372                 add     t1,t2,t3
373 1:              cache   L1CACHEOP(L1C_D,L1C_OP_IDXSTORETAG),0(t2)
374                 addu    t2,L1CACHE_LINESIZE
375                 bne     t1,t2,1b
378         /*      
379          * Set the defeature register if we're doing the 1/4 case.
380          * If we're here, at least _something_ is wrong.
381          */
383                 IF_BIN(t0,M_WID_BIN_3ID,2f)
385         /*
386          * In the 1/4 case, we'll always freeze the D cache.
387          * We might not freeze the I cache, though.
388          */
390                 li      t2,(1<<10)                      /* Freeze D */
391                 mfc0    t1,$23,2                        /* start with current value */
393                 IF_BIN(t0,M_WID_BIN_FI,1f)              /* If I cache is ok, no freeze */
394                 li      t3,(1<<28)
395                 or      t2,t2,t3                        /* also freeze I */
397                 or      t1,t1,t2                        /* Merge in new bits */
398                 HAZARD
399                 mtc0    t1,$23,2                        /* Write back to defeature register */
400                 HAZARD
403         /*
404          * Done, if you can believe it!
405          */
407                 j       ra
409 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
411         /*
412          * This part of the routine handles a fully operational L1
413          * cache. 
414          */
416 sb1250_l1cache_init_good:
418                 dmtc0   zero,C0_TAGLO
419                 dmtc0   zero,C0_TAGHI
421                 li      t2,K1BASE
422 #ifdef _FASTINIT_
423                 li      t3,L1CACHE_LINESIZE*8                   /* only 8 indicies now */
424 #else
425                 li      t3,L1CACHE_IDXHIGH
426 #endif
428                 add     t0,t2,t3
429                 .align  4
430 1:              cache   L1CACHEOP(L1C_I,L1C_OP_IDXSTORETAG),0(t2)
431                 addu    t2,L1CACHE_LINESIZE
432                 bne     t0,t2,1b
434                 dmtc0   zero,C0_TAGLO,2
435                 dmtc0   zero,C0_TAGHI,2
437                 li      t2,K1BASE
438                 add     t0,t2,t3
439                 .align  4
440 1:              cache   L1CACHEOP(L1C_D,L1C_OP_IDXSTORETAG),0(t2)
441                 addu    t2,L1CACHE_LINESIZE
442                 bne     t0,t2,1b
444                 j       ra
446 END(sb1250_l1cache_init)
449 #if CFG_VAPI
451 LEAF(sb1250_reset_defeature)
453         /*
454          * Test to see if we're running on a pre-production part with
455          * a defective L1 cache.  We store information in the SCD
456          * SYSTEM_REVISION register that identifies what is
457          * going on.
458          */
460         /*
461          * First, check the part number 
462          */
464                 li      t0,PHYS_TO_K1(A_SCD_SYSTEM_REVISION)
465                 ld      t1,0(t0)                        /* get SYSTEM_REVISION */
467                 dsrl    t1,t1,S_SYS_PART
468                 andi    t1,t1,(M_SYS_PART >> S_SYS_PART)
470                 beq     t1,0x1250,1f                    /* Go if real 1250 */
471                 beq     t1,0x1150,1f                    /* or 1250 in uni-cpu mode */
472                 b       sb1250_no_defeature     /* otherwise not a 1250, no WID check */
474         /*
475          * Now, check the revision.  Anything earlier than step A3 
476          * does not need this check.
477          *
478          * Exception: Step A6 parts return 0x04 in their revision field.
479          * These parts can can be verified as A6 by having a nonzero WID.
480          */
482 1:              ld      t1,0(t0)                        /* get the SYSTEM_REVISION again */
483                 dsrl    t1,t1,S_SYS_REVISION
484                 andi    t1,t1,(M_SYS_REVISION >> S_SYS_REVISION)
485                 beq     t1,0x04,1f
486                 blt     t1,0x05,sb1250_no_defeature
488         /*
489          * Okay, we really need to check the WID now.  If the WID is 
490          * not programmed at all, assume the part is good.
491          * (yes, this includes the wafer/lot bits)
492          */
494 1:              ld      t1,0(t0)                        /* Get the WID bits back */
495                 dsrl    t1,t1,S_SYS_WID                 /* wafer ID to bits 0..31 */
496                 li      t2,(M_SYS_WID >> S_SYS_WID)
497                 and     t1,t1,t2
499                 WID_UNCONVOLUTE(t1,t2,t3,t4)
501                 beq     t1,zero,sb1250_no_defeature
503         /*
504          * Get the bin number from the WID.  This tells us many things.
505          * For the L1 cache we need to know which ways to use,
506          * and this is determined by what we put in the tag registers.
507          */
509                 andi    t0,t1,M_WID_BIN                 /* bin # into T0 */
510                 li      t2,1                            /* make a bitmask */
511                 sll     t0,t2,t0                        /* put '1' in correct place */
513         /*      
514          * Set the defeature register if we're doing the 1/4 case.
515          * If we're here, at least _something_ is wrong.
516          * The 3/4 and full cache cases don't need defeaturing.
517          */
519                 IF_BIN(t0,(M_WID_BIN_3ID | M_WID_BIN_FID),sb1250_no_defeature)
521         /*
522          * In the 1/4 case, we'll always freeze the D cache.
523          * We might not freeze the I cache, though.
524          */
526                 li      t2,(1<<10)                      /* Freeze D */
527                 mfc0    t1,$23,2                        /* start with current value */
529                 IF_BIN(t0,M_WID_BIN_FI,1f)              /* If I cache is ok, no freeze */
530                 li      t3,(1<<28)
531                 or      t2,t2,t3                        /* also freeze I */
533                 or      t1,t1,t2                        /* Merge in new bits */
534                 HAZARD
535                 mtc0    t1,$23,2                        /* Write back to defeature register */
536                 HAZARD
538 sb1250_no_defeature:
540                 j       ra
542 END(sb1250_reset_defeature)
544 #endif
547 /*  *********************************************************************
548     *  SB1250_L1CACHE_INVAL_I()
549     *  
550     *  Invalidate the L1 ICache
551     *  
552     *  Input parameters: 
553     *      nothing
554     *      
555     *  Return value:
556     *      nothing
557     *  
558     *  Registers used:
559     *      t0,t1,t2,t3
560     ********************************************************************* */
562         
563 LEAF(sb1250_l1cache_inval_i)
566                 li      t2,K1BASE
567                 li      t3,L1CACHE_IDXHIGH
569                 add     t0,t2,t3
570                 .align  4
571 1:              cache   L1CACHEOP(L1C_I,L1C_OP_IDXINVAL),0(t2)
572                 addu    t2,L1CACHE_LINESIZE
573                 bne     t0,t2,1b
575                 j       ra
577 END(sb1250_l1cache_inval_i)
580 /*  *********************************************************************
581     *  SB1250_L1CACHE_FLUSH_D()
582     *  
583     *  Flush the entire L1 DCache (write dirty lines back to memory)
584     *  
585     *  Input parameters: 
586     *      nothing
587     *      
588     *  Return value:
589     *      nothing
590     *  
591     *  Registers used:
592     *      t0,t1,t2,t3
593     ********************************************************************* */
595         
596 LEAF(sb1250_l1cache_flush_d)
598                 li      t2,K1BASE
599                 li      t3,L1CACHE_IDXHIGH
601                 li      t2,K1BASE
602                 add     t0,t2,t3
603                 .align  4
604 1:              cache   L1CACHEOP(L1C_D,L1C_OP_IDXINVAL),0(t2)
605                 addu    t2,L1CACHE_LINESIZE
606                 bne     t0,t2,1b
608                 sync
609                 sync                            /* pass1 issue. */
611                 j       ra
613 END(sb1250_l1cache_flush_d)
616 /*  *********************************************************************
617     *  End
618     ********************************************************************* */