source: trunk/libs/newlib/src/libgloss/bfin/basiccrt.S @ 546

Last change on this file since 546 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 15.2 KB
Line 
1/*
2 * Basic startup code for Blackfin processor
3 *
4 * Copyright (C) 2008 Analog Devices, Inc.
5 *
6 * The authors hereby grant permission to use, copy, modify, distribute,
7 * and license this software and its documentation for any purpose, provided
8 * that existing copyright notices are retained in all copies and that this
9 * notice is included verbatim in any distributions. No written agreement,
10 * license, or royalty fee is required for any of the authorized uses.
11 * Modifications to this software may be copyrighted by their authors
12 * and need not follow the licensing terms described here, provided that
13 * the new terms are clearly indicated on the first page of each file where
14 * they apply.
15 */
16
17// basic startup code which
18// - turns the cycle counter on
19// - loads up FP & SP (both supervisor and user)
20// - initialises the device drivers (FIOCRT)
21// - calls monstartup to set up the profiling routines (PROFCRT)
22// - calls the C++ startup (CPLUSCRT)
23// - initialises argc/argv (FIOCRT/normal)
24// - calls _main
25// - calls _exit (which calls monexit to dump accumulated prof data (PROFCRT))
26// - defines dummy IO routines (!FIOCRT)
27
28#include <sys/platform.h>
29#include <cplb.h>
30#include <sys/anomaly_macros_rtl.h>
31
32#define IVBh (EVT0 >> 16)
33#define IVBl (EVT0 & 0xFFFF)
34#define UNASSIGNED_VAL 0
35#define UNASSIGNED_FILL 0
36// just IVG15
37#define INTERRUPT_BITS 0x400
38#if defined(_ADI_THREADS) || \
39    !defined(__ADSPLPBLACKFIN__) || defined(__ADSPBF561__) || defined(__ADSPBF566__)
40#define SET_CLOCK_SPEED 0
41#else
42#define SET_CLOCK_SPEED 1
43#endif
44
45#if SET_CLOCK_SPEED == 1
46#include <sys/pll.h>
47#define SET_CLK_MSEL 0x16
48#define SET_CLK_DF 0
49#define SET_CLK_LOCK_COUNT 0x300
50#define SET_CLK_CSEL 0
51#define SET_CLK_SSEL 5
52
53/*
54** CLKIN == 27MHz on the EZ-Kits.
55** D==0 means CLKIN is passed to PLL without dividing.
56** MSEL==0x16 means VCO==27*0x16 == 594MHz
57** CSEL==0 means CCLK==VCO == 594MHz
58** SSEL==5 means SCLK==VCO/5 == 118MHz
59*/
60
61#endif
62
63#ifdef __ADSPBF561_COREB__
64        .section        .b.text,"ax",@progbits
65        .align 2;
66        .global __coreb_start;
67        .type __coreb_start, STT_FUNC;
68__coreb_start:
69#elif defined(__ADSPBF60x_CORE1__)
70        .section        .1.text,"ax",@progbits
71        .align 2;
72        .global __core1_start;
73        .type __core1_start, STT_FUNC;
74__core1_start:
75#else
76        .text;
77        .align 2;
78        .global __start;
79        .type __start, STT_FUNC;
80__start:
81#endif
82#if WA_05000109
83        // Avoid Anomaly ID 05000109.
84#       define SYSCFG_VALUE 0x30
85        R1 = SYSCFG_VALUE;
86        SYSCFG = R1;
87#endif
88#if WA_05000229
89   // Avoid Anomaly 05-00-0229: DMA5_CONFIG and SPI_CTL not cleared on reset.
90   R1 = 0x400;
91#if defined(__ADSPBF538__) || defined(__ADSPBF539__)
92   P0.L = SPI0_CTL & 0xFFFF;
93   P0.H = SPI0_CTL >> 16;
94   W[P0] = R1.L;
95#else
96   P0.L = SPI_CTL & 0xFFFF;
97   P0.H = SPI_CTL >> 16;
98   W[P0] = R1.L;
99#endif
100   P0.L = DMA5_CONFIG & 0xFFFF;
101   P0.H = DMA5_CONFIG >> 16;
102   R1 = 0;
103   W[P0] = R1.L;
104#endif
105        // Zap loop counters to zero, to make sure that
106        // hw loops are disabled - it could be really baffling
107        // if the counters and bottom regs are set, and we happen
108        // to run into them.
109        R7 = 0;
110        LC0 = R7;
111        LC1 = R7;
112
113        // Clear the DAG Length regs too, so that it's safe to
114        // use I-regs without them wrapping around.
115        L0 = R7;
116        L1 = R7;
117        L2 = R7;
118        L3 = R7;
119
120        // Zero ITEST_COMMAND and DTEST_COMMAND
121        // (in case they have crud in them and
122        // does a write somewhere when we enable cache)
123        I0.L = (ITEST_COMMAND & 0xFFFF);
124        I0.H = (ITEST_COMMAND >> 16);
125        I1.L = (DTEST_COMMAND & 0xFFFF);
126        I1.H = (DTEST_COMMAND >> 16);
127        R7 = 0;
128        [I0] = R7;
129        [I1] = R7;
130        // It seems writing ITEST_COMMAND from SDRAM with icache enabled
131        // needs SSYNC.
132#ifdef __BFIN_SDRAM
133        SSYNC;
134#else
135        CSYNC;
136#endif
137
138        // Initialise the Event Vector table.
139        P0.H = IVBh;
140        P0.L = IVBl;
141
142        // Install __unknown_exception_occurred in EVT so that
143        // there is defined behaviour.
144        P0 += 2*4;              // Skip Emulation and Reset
145        P1 = 13;
146        R1.L = __unknown_exception_occurred;
147        R1.H = __unknown_exception_occurred;
148        LSETUP (L$ivt,L$ivt) LC0 = P1;
149L$ivt:  [P0++] = R1;
150        // Set IVG15's handler to be the start of the mode-change
151        // code. Then, before we return from the Reset back to user
152        // mode, we'll raise IVG15. This will mean we stay in supervisor
153        // mode, and continue from the mode-change point., but at a
154        // much lower priority.
155        P1.H = L$supervisor_mode;
156        P1.L = L$supervisor_mode;
157        [P0] = P1;
158
159        // Initialise the stack.
160        // Note: this points just past the end of the section.
161        // First write should be with [--SP].
162#ifdef __BFIN_SDRAM
163        SP.L = __end + 0x400000 - 12;
164        SP.H = __end + 0x400000 - 12;
165#else
166#ifdef __ADSPBF561_COREB__
167        SP.L=__coreb_stack_end - 12;
168        SP.H=__coreb_stack_end - 12;
169#elif defined(__ADSPBF60x_CORE1__)
170        SP.L=__core1_stack_end - 12;
171        SP.H=__core1_stack_end - 12;
172#else
173        SP.L=__stack_end - 12;
174        SP.H=__stack_end - 12;
175#endif
176#endif
177        usp = sp;
178
179        // We're still in supervisor mode at the moment, so the FP
180        // needs to point to the supervisor stack.
181        FP = SP;
182
183        // And make space for incoming "parameters" for functions
184        // we call from here:
185        SP += -12;
186
187        // Zero out bss section
188#ifdef __BFIN_SDRAM
189        R0.L = ___bss_start;
190        R0.H = ___bss_start;
191        R1.L = __end;
192        R1.H = __end;
193#else
194#ifdef __ADSPBF561_COREB__
195        R0.L = __coreb_bss_start;
196        R0.H = __coreb_bss_start;
197        R1.L = __coreb_bss_end;
198        R1.H = __coreb_bss_end;
199#elif defined(__ADSPBF60x_CORE1__)
200        R0.L = __core1_bss_start;
201        R0.H = __core1_bss_start;
202        R1.L = __core1_bss_end;
203        R1.H = __core1_bss_end;
204#else
205        R0.L = __bss_start;
206        R0.H = __bss_start;
207        R1.L = __bss_end;
208        R1.H = __bss_end;
209#endif
210#endif
211        R2 = R1 - R0;
212        R1 = 0;
213#ifdef __ADSPBF561_COREB__
214        CALL.X __coreb_memset;
215#elif defined(__ADSPBF60x_CORE1__)
216        CALL.X __core1_memset;
217#else
218        CALL.X _memset;
219#endif
220
221        R0 = INTERRUPT_BITS;
222        R0 <<= 5;       // Bits 0-4 not settable.
223        // CALL.X __install_default_handlers;
224        R4 = R0;                // Save modified list
225
226        R0 = SYSCFG;            // Enable the Cycle counter
227        BITSET(R0,1);
228        SYSCFG = R0;
229
230#if WA_05000137
231        // Avoid anomaly #05000137
232
233        // Set the port preferences of DAG0 and DAG1 to be
234        // different; this gives better performance when
235        // performing dual-dag operations on SDRAM.
236        P0.L = DMEM_CONTROL & 0xFFFF;
237        P0.H = DMEM_CONTROL >> 16;
238        R0 = [P0];
239        BITSET(R0, 12);
240        BITCLR(R0, 13);
241        [P0] = R0;
242        CSYNC;
243#endif
244
245        // Reinitialise data areas in RAM from ROM, if MemInit's
246        // been used.
247        // CALL.X _mi_initialize;
248
249#if defined(__ADSPLPBLACKFIN__)
250#if SET_CLOCK_SPEED == 1
251
252#if 0
253        // Check if this feature is enabled, i.e. ___clk_ctrl is defined to non-zero
254        P0.L = ___clk_ctrl;
255        P0.H = ___clk_ctrl;
256        R0 = MAX_IN_STARTUP;
257        R1 = [P0];
258        R0 = R0 - R1;
259        CC = R0;
260        IF CC JUMP L$clock_is_set;
261#endif
262
263        // Investigate whether we are a suitable revision
264        // for boosting the system clocks.
265        // speed.
266        P0.L = DSPID & 0xFFFF;
267        P0.H = DSPID >> 16;
268        R0 = [P0];
269        R0 = R0.L (Z);
270        CC = R0 < 2;
271        IF CC JUMP L$clock_is_set;
272
273        // Set the internal Voltage-Controlled Oscillator (VCO)
274        R0 = SET_CLK_MSEL (Z);
275        R1 = SET_CLK_DF (Z);
276        R2 = SET_CLK_LOCK_COUNT (Z);
277        CALL.X __pll_set_system_vco;
278
279        // Set the Core and System clocks
280        R0 = SET_CLK_CSEL (Z);
281        R1 = SET_CLK_SSEL (Z);
282        CALL.X __pll_set_system_clocks;
283
284L$clock_is_set:
285#endif
286#endif /* ADSPLPBLACKFIN */
287
288#if defined(__ADSPBF561__) || defined(__ADSPBF566__) || defined(__ADSPBF606__) || defined(__ADSPBF607__) || defined(__ADSPBF608__) || defined(__ADSPBF609__)
289
290        // Initialise the multi-core data tables.
291        // A dummy function will be called if we are not linking with
292        // -multicore
293        // CALL.X __mc_data_initialise;
294#endif
295
296#if 0
297        // Write the cplb exception handler to the EVT if approprate and
298        // initialise the CPLBs if they're needed. couldn't do
299        // this before we set up the stacks.
300        P2.H = ___cplb_ctrl;
301        P2.L = ___cplb_ctrl;
302        R0 = CPLB_ENABLE_ANY_CPLBS;
303        R6 = [P2];
304        R0 = R0 & R6;
305        CC = R0;
306        IF !CC JUMP L$no_cplbs;
307#if !defined(_ADI_THREADS)
308        P1.H = __cplb_hdr;
309        P1.L = __cplb_hdr;
310        P0.H = IVBh;
311        P0.L = IVBl;
312        [P0+12] = P1;   // write exception handler
313#endif /* _ADI_THREADS */
314        R0 = R6;
315        CALL.X __cplb_init;
316#endif
317L$no_cplbs:
318        //  Enable interrupts
319        STI R4;         // Using the mask from default handlers
320        RAISE 15;
321
322        // Move the processor into user mode.
323        P0.L=L$still_interrupt_in_ipend;
324        P0.H=L$still_interrupt_in_ipend;
325        RETI=P0;
326
327L$still_interrupt_in_ipend:
328        rti;    // keep doing 'rti' until we've 'finished' servicing all
329                // interrupts of priority higher than IVG15. Normally one
330                // would expect to only have the reset interrupt in IPEND
331                // being serviced, but occasionally when debugging this may
332                // not be the case - if restart is hit when servicing an
333                // interrupt.
334                //
335                // When we clear all bits from IPEND, we'll enter user mode,
336                // then we'll automatically jump to supervisor_mode to start
337                // servicing IVG15 (which we will 'service' for the whole
338                // program, so that the program is in supervisor mode.
339                //
340                // Need to do this to 'finish' servicing the reset interupt.
341
342L$supervisor_mode:
343        [--SP] = RETI;  // re-enables the interrupt system
344
345        R0.L = UNASSIGNED_VAL;
346        R0.H = UNASSIGNED_VAL;
347#if UNASSIGNED_FILL
348        R2=R0;
349        R3=R0;
350        R4=R0;
351        R5=R0;
352        R6=R0;
353        R7=R0;
354        P0=R0;
355        P1=R0;
356        P2=R0;
357        P3=R0;
358        P4=R0;
359        P5=R0;
360#endif
361        // Push a RETS and Old FP onto the stack, for sanity.
362        [--SP]=R0;
363        [--SP]=R0;
364        // Make sure the FP is sensible.
365        FP = SP;
366
367        // And leave space for incoming "parameters"
368        SP += -12;
369
370#ifdef PROFCRT
371        CALL.X monstartup; // initialise profiling routines
372#endif  /* PROFCRT */
373
374#if !defined(__ADSPBF561_COREB__) && !defined(__ADSPBF60x_CORE1__)
375        CALL.X __init;
376
377        R0.L = __fini;
378        R0.H = __fini;
379        CALL.X _atexit;
380#endif
381
382#if !defined(_ADI_THREADS)
383#ifdef FIOCRT
384        // FILE IO provides access to real command-line arguments.
385        CALL.X __getargv;
386        r1.l=__Argv;
387        r1.h=__Argv;
388#else
389        // Default to having no arguments and a null list.
390        R0=0;
391#ifdef __ADSPBF561_COREB__
392        R1.L=L$argv_coreb;
393        R1.H=L$argv_coreb;
394#elif defined(__ADSPBF60x_CORE1__)
395        R1.L=L$argv_core1;
396        R1.H=L$argv_core1;
397#else
398        R1.L=L$argv;
399        R1.H=L$argv;
400#endif
401#endif /* FIOCRT */
402#endif /* _ADI_THREADS */
403
404        // At long last, call the application program.
405#ifdef __ADSPBF561_COREB__
406        CALL.X _coreb_main;
407#elif defined(__ADSPBF60x_CORE1__)
408        CALL.X _core1_main;
409#else
410        CALL.X _main;
411#endif
412
413#if !defined(_ADI_THREADS)
414#if !defined(__ADSPBF561_COREB__) && !defined(__ADSPBF60x_CORE1__)
415        CALL.X _exit;   // passing in main's return value
416#endif
417#endif
418
419#ifdef __ADSPBF561_COREB__
420        .size   __coreb_start, .-__coreb_start
421#elif defined(__ADSPBF60x_CORE1__)
422        .size   __core1_start, .-__core1_start
423#else
424        .size   __start, .-__start
425#endif
426
427        .align 2
428        .type __unknown_exception_occurred, STT_FUNC;
429__unknown_exception_occurred:
430        // This function is invoked by the default exception
431        // handler, if it does not recognise the kind of
432        // exception that has occurred. In other words, the
433        // default handler only handles some of the system's
434        // exception types, and it does not expect any others
435        // to occur. If your application is going to be using
436        // other kinds of exceptions, you must replace the
437        // default handler with your own, that handles all the
438        // exceptions you will use.
439        //
440        // Since there's nothing we can do, we just loop here
441        // at what we hope is a suitably informative label.
442        IDLE;
443        CSYNC;
444        JUMP __unknown_exception_occurred;
445        RTS;
446        .size __unknown_exception_occurred, .-__unknown_exception_occurred
447
448#if defined(__ADSPLPBLACKFIN__)
449#if SET_CLOCK_SPEED == 1
450
451/*
452** CLKIN == 27MHz on the EZ-Kits.
453** D==0 means CLKIN is passed to PLL without dividing.
454** MSEL==0x16 means VCO==27*0x16 == 594MHz
455** CSEL==0 means CCLK==VCO == 594MHz
456** SSEL==5 means SCLK==VCO/5 == 118MHz
457*/
458
459// int pll_set_system_clocks(int csel, int ssel)
460// returns 0 for success, -1 for error.
461
462        .align 2
463        .type __pll_set_system_clocks, STT_FUNC;
464__pll_set_system_clocks:
465        P0.H = PLL_DIV >> 16;
466        P0.L = PLL_DIV & 0xFFFF;
467        R2 = W[P0] (Z);
468
469        // Plant CSEL and SSEL
470        R0 <<= 16;
471        R0.L = (4 << 8) | 2;    // 2 bits, at posn 4
472        R1 <<= 16;
473        R1.L = 4;               // 4 bits, at posn 0
474        R2 = DEPOSIT(R2, R0);
475
476#if defined(__WORKAROUND_DREG_COMP_LATENCY)
477        // Work around anomaly 05-00-0209 which affects the DEPOSIT
478        // instruction (and the EXTRACT, SIGNBITS, and EXPADJ instructions)
479        // if the previous instruction created any of its operands
480        NOP;
481#endif
482
483        R2 = DEPOSIT(R2, R1);
484
485        W[P0] = R2;
486        SSYNC;
487        RTS;
488        .size __pll_set_system_clocks, .-__pll_set_system_clocks
489
490// int pll_set_system_vco(int msel, int df, lockcnt)
491        .align 2
492        .type __pll_set_system_vco, STT_FUNC;
493__pll_set_system_vco:
494        P0.H = PLL_CTL >> 16;
495        P0.L = PLL_CTL & 0xFFFF;
496        R3 = W[P0] (Z);
497        P2 = R3;                // Save copy
498        R3 >>= 1;               // Drop old DF
499        R1 = ROT R1 BY -1;      // Move DF into CC
500        R3 = ROT R3 BY 1;       // and into ctl space.
501        R0 <<= 16;              // Set up pattern reg
502        R0.L = (9<<8) | 6;      // (6 bits at posn 9)
503        R1 = P2;                // Get the old version
504        R3 = DEPOSIT(R3, R0);
505        CC = R1 == R3;          // and if we haven't changed
506        IF CC JUMP L$done;      // Anything, return
507
508        CC = R2 == 0;           // Use default lockcount if
509        IF CC JUMP L$wakeup;    // user one is zero.
510        P2.H = PLL_LOCKCNT >> 16;
511        P2.L = PLL_LOCKCNT & 0xFFFF;
512        W[P2] = R2;             // Set the lock counter
513L$wakeup:
514        P2.H = SIC_IWR >> 16;
515        P2.L = SIC_IWR & 0xFFFF;
516        R2 = [P2];
517        BITSET(R2, 0);          // enable PLL Wakeup
518        [P2] = R2;
519
520        W[P0] = R3;             // Update PLL_CTL
521        SSYNC;
522
523        CLI R2;                 // Avoid unnecessary interrupts
524        IDLE;                   // Wait until PLL has locked
525        STI R2;                 // Restore interrupts.
526
527L$done:
528        RTS;
529        .size __pll_set_system_vco, .-__pll_set_system_vco
530#endif
531#endif /* ADSPLPBLACKFIN */
532
533#if defined(__ADSPBF561_COREB__) || defined(__ADSPBF60x_CORE1__)
534#ifdef __ADSPBF561_COREB__
535        .section        .b.text,"ax",@progbits
536        .type __coreb_memset, STT_FUNC
537__coreb_memset:
538#else
539        .section        .1.text,"ax",@progbits
540        .type __core1_memset, STT_FUNC
541__core1_memset:
542#endif
543        P0 = R0 ;              /* P0 = address */
544        P2 = R2 ;              /* P2 = count   */
545        R3 = R0 + R2;          /* end          */
546        CC = R2 <= 7(IU);
547        IF CC JUMP  .Ltoo_small;
548        R1 = R1.B (Z);         /* R1 = fill char */
549        R2 =  3;
550        R2 = R0 & R2;          /* addr bottom two bits */
551        CC =  R2 == 0;             /* AZ set if zero.   */
552        IF !CC JUMP  .Lforce_align ;  /* Jump if addr not aligned. */
553
554.Laligned:
555        P1 = P2 >> 2;          /* count = n/4        */
556        R2 = R1 <<  8;         /* create quad filler */
557        R2.L = R2.L + R1.L(NS);
558        R2.H = R2.L + R1.H(NS);
559        P2 = R3;
560
561        LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1;
562.Lquad_loop:
563        [P0++] = R2;
564
565        CC = P0 == P2;
566        IF !CC JUMP .Lbytes_left;
567        RTS;
568
569.Lbytes_left:
570        R2 = R3;                /* end point */
571        R3 = P0;                /* current position */
572        R2 = R2 - R3;           /* bytes left */
573        P2 = R2;
574
575.Ltoo_small:
576        CC = P2 == 0;           /* Check zero count */
577        IF CC JUMP .Lfinished;    /* Unusual */
578
579.Lbytes:
580        LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2;
581.Lbyte_loop:
582        B[P0++] = R1;
583
584.Lfinished:
585        RTS;
586
587.Lforce_align:
588        CC = BITTST (R0, 0);  /* odd byte */
589        R0 = 4;
590        R0 = R0 - R2;
591        P1 = R0;
592        R0 = P0;                    /* Recover return address */
593        IF !CC JUMP .Lskip1;
594        B[P0++] = R1;
595.Lskip1:
596        CC = R2 <= 2;          /* 2 bytes */
597        P2 -= P1;              /* reduce count */
598        IF !CC JUMP .Laligned;
599        B[P0++] = R1;
600        B[P0++] = R1;
601        JUMP .Laligned;
602#ifdef __ADSPBF561_COREB__
603.size __coreb_memset,.-__coreb_memset
604#else
605.size __core1_memset,.-__core1_memset
606#endif
607#endif
608
609#ifdef __ADSPBF561_COREB__
610        .section        .b.bss,"aw",@progbits
611        .align 4
612        .type   L$argv_coreb, @object
613        .size   L$argv_coreb, 4
614L$argv_coreb:
615        .zero   4
616#elif defined(__ADSPBF60x_CORE1__)
617        .section        .1.bss,"aw",@progbits
618        .align 4
619        .type   L$argv_core1, @object
620        .size   L$argv_core1, 4
621L$argv_core1:
622        .zero   4
623#else
624        .local  L$argv
625        .comm   L$argv,4,4
626#endif
627
Note: See TracBrowser for help on using the repository browser.