diff options
Diffstat (limited to 'libgloss/bfin/basiccrt.S')
-rw-r--r-- | libgloss/bfin/basiccrt.S | 586 |
1 files changed, 586 insertions, 0 deletions
diff --git a/libgloss/bfin/basiccrt.S b/libgloss/bfin/basiccrt.S new file mode 100644 index 000000000..d57a38cc8 --- /dev/null +++ b/libgloss/bfin/basiccrt.S @@ -0,0 +1,586 @@ +/* + * Basic startup code for Blackfin processor + * + * Copyright (C) 2008 Analog Devices, Inc. + * + * The authors hereby grant permission to use, copy, modify, distribute, + * and license this software and its documentation for any purpose, provided + * that existing copyright notices are retained in all copies and that this + * notice is included verbatim in any distributions. No written agreement, + * license, or royalty fee is required for any of the authorized uses. + * Modifications to this software may be copyrighted by their authors + * and need not follow the licensing terms described here, provided that + * the new terms are clearly indicated on the first page of each file where + * they apply. + */ + +// basic startup code which +// - turns the cycle counter on +// - loads up FP & SP (both supervisor and user) +// - initialises the device drivers (FIOCRT) +// - calls monstartup to set up the profiling routines (PROFCRT) +// - calls the C++ startup (CPLUSCRT) +// - initialises argc/argv (FIOCRT/normal) +// - calls _main +// - calls _exit (which calls monexit to dump accumulated prof data (PROFCRT)) +// - defines dummy IO routines (!FIOCRT) + +#include <sys/platform.h> +#include <cplb.h> +#include <sys/anomaly_macros_rtl.h> + +#define IVBh (EVT0 >> 16) +#define IVBl (EVT0 & 0xFFFF) +#define UNASSIGNED_VAL 0 +#define UNASSIGNED_FILL 0 +// just IVG15 +#define INTERRUPT_BITS 0x400 +#if defined(_ADI_THREADS) || \ + !defined(__ADSPLPBLACKFIN__) || defined(__ADSPBF561__) || defined(__ADSPBF566__) +#define SET_CLOCK_SPEED 0 +#else +#define SET_CLOCK_SPEED 1 +#endif + +#if SET_CLOCK_SPEED == 1 +#include <sys/pll.h> +#define SET_CLK_MSEL 0x16 +#define SET_CLK_DF 0 +#define SET_CLK_LOCK_COUNT 0x300 +#define SET_CLK_CSEL 0 +#define SET_CLK_SSEL 5 + +/* +** CLKIN == 27MHz on the EZ-Kits. +** D==0 means CLKIN is passed to PLL without dividing. +** MSEL==0x16 means VCO==27*0x16 == 594MHz +** CSEL==0 means CCLK==VCO == 594MHz +** SSEL==5 means SCLK==VCO/5 == 118MHz +*/ + +#endif + +#ifdef __ADSPBF561_COREB__ + .section .b.text,"ax",@progbits + .align 2; + .global __coreb_start; + .type __coreb_start, STT_FUNC; +__coreb_start: +#else + .text; + .align 2; + .global __start; + .type __start, STT_FUNC; +__start: +#endif +#if WA_05000109 + // Avoid Anomaly ID 05000109. +# define SYSCFG_VALUE 0x30 + R1 = SYSCFG_VALUE; + SYSCFG = R1; +#endif +#if WA_05000229 + // Avoid Anomaly 05-00-0229: DMA5_CONFIG and SPI_CTL not cleared on reset. + R1 = 0x400; +#if defined(__ADSPBF538__) || defined(__ADSPBF539__) + P0.L = SPI0_CTL & 0xFFFF; + P0.H = SPI0_CTL >> 16; + W[P0] = R1.L; +#else + P0.L = SPI_CTL & 0xFFFF; + P0.H = SPI_CTL >> 16; + W[P0] = R1.L; +#endif + P0.L = DMA5_CONFIG & 0xFFFF; + P0.H = DMA5_CONFIG >> 16; + R1 = 0; + W[P0] = R1.L; +#endif + // Zap loop counters to zero, to make sure that + // hw loops are disabled - it could be really baffling + // if the counters and bottom regs are set, and we happen + // to run into them. + R7 = 0; + LC0 = R7; + LC1 = R7; + + // Clear the DAG Length regs too, so that it's safe to + // use I-regs without them wrapping around. + L0 = R7; + L1 = R7; + L2 = R7; + L3 = R7; + + // Zero ITEST_COMMAND and DTEST_COMMAND + // (in case they have crud in them and + // does a write somewhere when we enable cache) + I0.L = (ITEST_COMMAND & 0xFFFF); + I0.H = (ITEST_COMMAND >> 16); + I1.L = (DTEST_COMMAND & 0xFFFF); + I1.H = (DTEST_COMMAND >> 16); + R7 = 0; + [I0] = R7; + [I1] = R7; + // It seems writing ITEST_COMMAND from SDRAM with icache enabled + // needs SSYNC. +#ifdef __BFIN_SDRAM + SSYNC; +#else + CSYNC; +#endif + + // Initialise the Event Vector table. + P0.H = IVBh; + P0.L = IVBl; + + // Install __unknown_exception_occurred in EVT so that + // there is defined behaviour. + P0 += 2*4; // Skip Emulation and Reset + P1 = 13; + R1.L = __unknown_exception_occurred; + R1.H = __unknown_exception_occurred; + LSETUP (L$ivt,L$ivt) LC0 = P1; +L$ivt: [P0++] = R1; + // Set IVG15's handler to be the start of the mode-change + // code. Then, before we return from the Reset back to user + // mode, we'll raise IVG15. This will mean we stay in supervisor + // mode, and continue from the mode-change point., but at a + // much lower priority. + P1.H = L$supervisor_mode; + P1.L = L$supervisor_mode; + [P0] = P1; + + // Initialise the stack. + // Note: this points just past the end of the section. + // First write should be with [--SP]. +#ifdef __BFIN_SDRAM + SP.L = __end + 0x400000 - 12; + SP.H = __end + 0x400000 - 12; +#else +#ifdef __ADSPBF561_COREB__ + SP.L=__coreb_stack_end - 12; + SP.H=__coreb_stack_end - 12; +#else + SP.L=__stack_end - 12; + SP.H=__stack_end - 12; +#endif +#endif + usp = sp; + + // We're still in supervisor mode at the moment, so the FP + // needs to point to the supervisor stack. + FP = SP; + + // And make space for incoming "parameters" for functions + // we call from here: + SP += -12; + + // Zero out bss section +#ifdef __BFIN_SDRAM + R0.L = ___bss_start; + R0.H = ___bss_start; + R1.L = __end; + R1.H = __end; +#else +#ifdef __ADSPBF561_COREB__ + R0.L = __coreb_bss_start; + R0.H = __coreb_bss_start; + R1.L = __coreb_bss_end; + R1.H = __coreb_bss_end; +#else + R0.L = __bss_start; + R0.H = __bss_start; + R1.L = __bss_end; + R1.H = __bss_end; +#endif +#endif + R2 = R1 - R0; + R1 = 0; +#ifdef __ADSPBF561_COREB__ + CALL.X __coreb_memset; +#else + CALL.X _memset; +#endif + + R0 = INTERRUPT_BITS; + R0 <<= 5; // Bits 0-4 not settable. + // CALL.X __install_default_handlers; + R4 = R0; // Save modified list + + R0 = SYSCFG; // Enable the Cycle counter + BITSET(R0,1); + SYSCFG = R0; + +#if WA_05000137 + // Avoid anomaly #05000137 + + // Set the port preferences of DAG0 and DAG1 to be + // different; this gives better performance when + // performing dual-dag operations on SDRAM. + P0.L = DMEM_CONTROL & 0xFFFF; + P0.H = DMEM_CONTROL >> 16; + R0 = [P0]; + BITSET(R0, 12); + BITCLR(R0, 13); + [P0] = R0; + CSYNC; +#endif + + // Reinitialise data areas in RAM from ROM, if MemInit's + // been used. + // CALL.X _mi_initialize; + +#if defined(__ADSPLPBLACKFIN__) +#if SET_CLOCK_SPEED == 1 + +#if 0 + // Check if this feature is enabled, i.e. ___clk_ctrl is defined to non-zero + P0.L = ___clk_ctrl; + P0.H = ___clk_ctrl; + R0 = MAX_IN_STARTUP; + R1 = [P0]; + R0 = R0 - R1; + CC = R0; + IF CC JUMP L$clock_is_set; +#endif + + // Investigate whether we are a suitable revision + // for boosting the system clocks. + // speed. + P0.L = DSPID & 0xFFFF; + P0.H = DSPID >> 16; + R0 = [P0]; + R0 = R0.L (Z); + CC = R0 < 2; + IF CC JUMP L$clock_is_set; + + // Set the internal Voltage-Controlled Oscillator (VCO) + R0 = SET_CLK_MSEL (Z); + R1 = SET_CLK_DF (Z); + R2 = SET_CLK_LOCK_COUNT (Z); + CALL.X __pll_set_system_vco; + + // Set the Core and System clocks + R0 = SET_CLK_CSEL (Z); + R1 = SET_CLK_SSEL (Z); + CALL.X __pll_set_system_clocks; + +L$clock_is_set: +#endif +#endif /* ADSPLPBLACKFIN */ + +#if defined(__ADSPBF561__) || defined(__ADSPBF566__) + // Initialise the multi-core data tables. + // A dummy function will be called if we are not linking with + // -multicore + // CALL.X __mc_data_initialise; +#endif + +#if 0 + // Write the cplb exception handler to the EVT if approprate and + // initialise the CPLBs if they're needed. couldn't do + // this before we set up the stacks. + P2.H = ___cplb_ctrl; + P2.L = ___cplb_ctrl; + R0 = CPLB_ENABLE_ANY_CPLBS; + R6 = [P2]; + R0 = R0 & R6; + CC = R0; + IF !CC JUMP L$no_cplbs; +#if !defined(_ADI_THREADS) + P1.H = __cplb_hdr; + P1.L = __cplb_hdr; + P0.H = IVBh; + P0.L = IVBl; + [P0+12] = P1; // write exception handler +#endif /* _ADI_THREADS */ + R0 = R6; + CALL.X __cplb_init; +#endif +L$no_cplbs: + // Enable interrupts + STI R4; // Using the mask from default handlers + RAISE 15; + + // Move the processor into user mode. + P0.L=L$still_interrupt_in_ipend; + P0.H=L$still_interrupt_in_ipend; + RETI=P0; + +L$still_interrupt_in_ipend: + rti; // keep doing 'rti' until we've 'finished' servicing all + // interrupts of priority higher than IVG15. Normally one + // would expect to only have the reset interrupt in IPEND + // being serviced, but occasionally when debugging this may + // not be the case - if restart is hit when servicing an + // interrupt. + // + // When we clear all bits from IPEND, we'll enter user mode, + // then we'll automatically jump to supervisor_mode to start + // servicing IVG15 (which we will 'service' for the whole + // program, so that the program is in supervisor mode. + // + // Need to do this to 'finish' servicing the reset interupt. + +L$supervisor_mode: + [--SP] = RETI; // re-enables the interrupt system + + R0.L = UNASSIGNED_VAL; + R0.H = UNASSIGNED_VAL; +#if UNASSIGNED_FILL + R2=R0; + R3=R0; + R4=R0; + R5=R0; + R6=R0; + R7=R0; + P0=R0; + P1=R0; + P2=R0; + P3=R0; + P4=R0; + P5=R0; +#endif + // Push a RETS and Old FP onto the stack, for sanity. + [--SP]=R0; + [--SP]=R0; + // Make sure the FP is sensible. + FP = SP; + + // And leave space for incoming "parameters" + SP += -12; + +#ifdef PROFCRT + CALL.X monstartup; // initialise profiling routines +#endif /* PROFCRT */ + +#ifndef __ADSPBF561_COREB__ + CALL.X __init; + + R0.L = __fini; + R0.H = __fini; + CALL.X _atexit; +#endif + +#if !defined(_ADI_THREADS) +#ifdef FIOCRT + // FILE IO provides access to real command-line arguments. + CALL.X __getargv; + r1.l=__Argv; + r1.h=__Argv; +#else + // Default to having no arguments and a null list. + R0=0; +#ifdef __ADSPBF561_COREB__ + R1.L=L$argv_coreb; + R1.H=L$argv_coreb; +#else + R1.L=L$argv; + R1.H=L$argv; +#endif +#endif /* FIOCRT */ +#endif /* _ADI_THREADS */ + + // At long last, call the application program. +#ifdef __ADSPBF561_COREB__ + CALL.X _coreb_main; +#else + CALL.X _main; +#endif + +#if !defined(_ADI_THREADS) +#ifndef __ADSPBF561_COREB__ + CALL.X _exit; // passing in main's return value +#endif +#endif + +#ifdef __ADSPBF561_COREB__ + .size __coreb_start, .-__coreb_start +#else + .size __start, .-__start +#endif + + .align 2 + .type __unknown_exception_occurred, STT_FUNC; +__unknown_exception_occurred: + // This function is invoked by the default exception + // handler, if it does not recognise the kind of + // exception that has occurred. In other words, the + // default handler only handles some of the system's + // exception types, and it does not expect any others + // to occur. If your application is going to be using + // other kinds of exceptions, you must replace the + // default handler with your own, that handles all the + // exceptions you will use. + // + // Since there's nothing we can do, we just loop here + // at what we hope is a suitably informative label. + IDLE; + CSYNC; + JUMP __unknown_exception_occurred; + RTS; + .size __unknown_exception_occurred, .-__unknown_exception_occurred + +#if defined(__ADSPLPBLACKFIN__) +#if SET_CLOCK_SPEED == 1 + +/* +** CLKIN == 27MHz on the EZ-Kits. +** D==0 means CLKIN is passed to PLL without dividing. +** MSEL==0x16 means VCO==27*0x16 == 594MHz +** CSEL==0 means CCLK==VCO == 594MHz +** SSEL==5 means SCLK==VCO/5 == 118MHz +*/ + +// int pll_set_system_clocks(int csel, int ssel) +// returns 0 for success, -1 for error. + + .align 2 + .type __pll_set_system_clocks, STT_FUNC; +__pll_set_system_clocks: + P0.H = PLL_DIV >> 16; + P0.L = PLL_DIV & 0xFFFF; + R2 = W[P0] (Z); + + // Plant CSEL and SSEL + R0 <<= 16; + R0.L = (4 << 8) | 2; // 2 bits, at posn 4 + R1 <<= 16; + R1.L = 4; // 4 bits, at posn 0 + R2 = DEPOSIT(R2, R0); + +#if defined(__WORKAROUND_DREG_COMP_LATENCY) + // Work around anomaly 05-00-0209 which affects the DEPOSIT + // instruction (and the EXTRACT, SIGNBITS, and EXPADJ instructions) + // if the previous instruction created any of its operands + NOP; +#endif + + R2 = DEPOSIT(R2, R1); + + W[P0] = R2; + SSYNC; + RTS; + .size __pll_set_system_clocks, .-__pll_set_system_clocks + +// int pll_set_system_vco(int msel, int df, lockcnt) + .align 2 + .type __pll_set_system_vco, STT_FUNC; +__pll_set_system_vco: + P0.H = PLL_CTL >> 16; + P0.L = PLL_CTL & 0xFFFF; + R3 = W[P0] (Z); + P2 = R3; // Save copy + R3 >>= 1; // Drop old DF + R1 = ROT R1 BY -1; // Move DF into CC + R3 = ROT R3 BY 1; // and into ctl space. + R0 <<= 16; // Set up pattern reg + R0.L = (9<<8) | 6; // (6 bits at posn 9) + R1 = P2; // Get the old version + R3 = DEPOSIT(R3, R0); + CC = R1 == R3; // and if we haven't changed + IF CC JUMP L$done; // Anything, return + + CC = R2 == 0; // Use default lockcount if + IF CC JUMP L$wakeup; // user one is zero. + P2.H = PLL_LOCKCNT >> 16; + P2.L = PLL_LOCKCNT & 0xFFFF; + W[P2] = R2; // Set the lock counter +L$wakeup: + P2.H = SIC_IWR >> 16; + P2.L = SIC_IWR & 0xFFFF; + R2 = [P2]; + BITSET(R2, 0); // enable PLL Wakeup + [P2] = R2; + + W[P0] = R3; // Update PLL_CTL + SSYNC; + + CLI R2; // Avoid unnecessary interrupts + IDLE; // Wait until PLL has locked + STI R2; // Restore interrupts. + +L$done: + RTS; + .size __pll_set_system_vco, .-__pll_set_system_vco +#endif +#endif /* ADSPLPBLACKFIN */ + +#ifdef __ADSPBF561_COREB__ + .section .b.text,"ax",@progbits + .type __coreb_memset, STT_FUNC +__coreb_memset: + P0 = R0 ; /* P0 = address */ + P2 = R2 ; /* P2 = count */ + R3 = R0 + R2; /* end */ + CC = R2 <= 7(IU); + IF CC JUMP .Ltoo_small; + R1 = R1.B (Z); /* R1 = fill char */ + R2 = 3; + R2 = R0 & R2; /* addr bottom two bits */ + CC = R2 == 0; /* AZ set if zero. */ + IF !CC JUMP .Lforce_align ; /* Jump if addr not aligned. */ + +.Laligned: + P1 = P2 >> 2; /* count = n/4 */ + R2 = R1 << 8; /* create quad filler */ + R2.L = R2.L + R1.L(NS); + R2.H = R2.L + R1.H(NS); + P2 = R3; + + LSETUP (.Lquad_loop , .Lquad_loop) LC0=P1; +.Lquad_loop: + [P0++] = R2; + + CC = P0 == P2; + IF !CC JUMP .Lbytes_left; + RTS; + +.Lbytes_left: + R2 = R3; /* end point */ + R3 = P0; /* current position */ + R2 = R2 - R3; /* bytes left */ + P2 = R2; + +.Ltoo_small: + CC = P2 == 0; /* Check zero count */ + IF CC JUMP .Lfinished; /* Unusual */ + +.Lbytes: + LSETUP (.Lbyte_loop , .Lbyte_loop) LC0=P2; +.Lbyte_loop: + B[P0++] = R1; + +.Lfinished: + RTS; + +.Lforce_align: + CC = BITTST (R0, 0); /* odd byte */ + R0 = 4; + R0 = R0 - R2; + P1 = R0; + R0 = P0; /* Recover return address */ + IF !CC JUMP .Lskip1; + B[P0++] = R1; +.Lskip1: + CC = R2 <= 2; /* 2 bytes */ + P2 -= P1; /* reduce count */ + IF !CC JUMP .Laligned; + B[P0++] = R1; + B[P0++] = R1; + JUMP .Laligned; +.size __coreb_memset,.-__coreb_memset +#endif + +#ifdef __ADSPBF561_COREB__ + .section .b.bss,"aw",@progbits + .align 4 + .type L$argv_coreb, @object + .size L$argv_coreb, 4 +L$argv_coreb: + .zero 4 +#else + .local L$argv + .comm L$argv,4,4 +#endif + |