.global _load_application;
.extern command;
.extern _app_offset;
#define reset 0x8C003
.extern final_init_loop;
.extern ___lib_RSTI;

#include <def21469.h>


.SECTION/PM     seg_ldr;    // the kernel must reside in a single input_section

 _load_application:
 
    Call user_init (DB);
    IMASK = 0;             // mask all interrupts since this code executes from within
    IRPTL = 0;             // the interrupt vector table.
    BIT SET MODE1 IRPTEN;  //Enable Global Interrupts

    L0=0;   L4=0;          //Zero L's so I-registers can be used without wrap
    L8=0;   L12=0;  L15=0;
    M5=0;   M6=1;   M13=0;  M14=1;

    R11=DM(SYSCTL);        // Read current SYSCTL setting
    R12=PASS R11;           // Hold Initial SYSCTL setting => restored in final init
    I4=SYSCTL;






// ==========================  READ_BOOT_INFO  ================================
// Read in section header (3 spi words that contain Data TAG, ADDRESS and COUNT)
// Places TAG in R8, Count in R2, and Destination Address in R3.  This code also
// analyzes the TAG and branches to the appropriate initialization code.
//
// Possible TAGS (the 'L' in each tag name signifying that the address and
// count are LOGICAL values, not physical):
//
//              0x0 FINAL_INIT
//              0x1 ZERO_LDATA
//              0x2 ZERO_L48
//              0x3 INIT_L16
//              0x4 INIT_L32
//              0x5 INIT_L48
//              0x6 INIT_L64
//              0x7 ZERO_EXT8
//              0x8 ZERO_EXT16
//              0x9 INIT_EXT8
//              0xA INIT_EXT16
//------------------------------------------------------------------------------
READ_BOOT_INFO:

    call READ_THREEx32;     // fetch three word header via SPI DMA

    R8=dm(0x92003);         //r8 passes data-type tag
    R2=dm(0x92004);         //r2 passes count
    R3=dm(0x92005);         //r3 passes destination address

    R0=PASS R8;             // check TAG

    IF EQ JUMP final_init;  r0=r0-1;    // jump if fetched tag was 0, else tag--
    IF EQ JUMP ZERO_LDATA;  r0=r0-1;    // jump if fetched tag was 1, else tag--
    IF EQ JUMP ZERO_L48;    r0=r0-1;    // jump if fetched tag was 2, else tag--
    IF EQ JUMP INIT_L16;    r0=r0-1;    // jump if fetched tag was 3, else tag--
    IF EQ JUMP INIT_L32;    r0=r0-1;    // jump if fetched tag was 4, else tag--
    IF EQ JUMP INIT_L48;    r0=r0-1;    // jump if fetched tag was 5, else tag--
    IF EQ JUMP INIT_L64;    r0=r0-1;    // jump if fetched tag was 6, else tag--
    IF EQ JUMP ZERO_EXT8;   r0=r0-1;    // jump if fetched tag was 7, else tag--
    IF EQ JUMP ZERO_EXT16;  r0=r0-1;    // jump if fetched tag was 8, else tag--
    IF EQ JUMP INIT_EXT8;   r0=r0-1;    // jump if fetched tag was 9, else tag--
    IF EQ JUMP INIT_EXT16;  jump(pc,0); // jump if fetched tag was A, else it
                                        // was an invalid TAG, so trap for debug
//==============================================================================

//============================== SPI_ISR =====================================
// This is the first instruction run after the kernel is booted. It returns to
// 0x90005 and starts the kernel. Instructions added or removed may require
// adding "NOP" instructions to ensure this instruction resolves to 0x90030.
// Check map file (kernel.map) to verify location.
//------------------------------------------------------------------------------
x30_SPI_ISR:            rti;
//==============================================================================

//============================== READ_Nx32 =====================================
// Load either one or three 32-bit words (via DMA) into scratch locations listed
// below for core access. For 32-bit accesses, the three words will be at
// 0x98003, 0x98004, and 0x98005.  For 48-bit accesses two words will be
// available at 0x90002 and 0x90003.
//------------------------------------------------------------------------------
READ_THREEx32:
    USTAT4 = 0x3;
    jump START_DMA;         //skip over next instruction

READ_ONEx32:
    USTAT4=M14;        //DMA count = one 32-bit word

START_DMA:
    DM(IMSPI)=M14;       // Internal DMA modify = 1
    USTAT1=0x92003;      // 0x98003, 0x98004, 0x98005 2-col = 0x90002, 0x90003 3-col
    DM(IISPI)=USTAT1;    // Setup DMA destination address.
    
    DM(CSPI)=USTAT4;     //DMA count = three 32 bit words (two 48-bit words)


    //-------- Wait for SPI DMA to complete using polling------
POLL_SPIDMAS:   
    ustat1=dm(SPIDMAC);
    bit tst ustat1 SPIDMAS; // Check SPI DMA Status bit
    IF TF jump POLL_SPIDMAS;     // SPIDMAS = 1 when DMA in progress
    //---------------------------------------------------------

    r8=dm(0x92003);         //place 32-bit word in R8
    rts;
//==============================================================================



// ============================== ZERO_LDATA ===================================
// Use core to init 16/32/64-bit internal buffers to zero (saves space in LDR)
//------------------------------------------------------------------------------
ZERO_LDATA:

    I0=R3;      //R3 passes destination address (LW, NW, or SW)
    R0=0;       //Value used to write zero's to memory
    R1=0;       //neighbor register used to write upper 32 bits if LW accesses

    LCNTR=R2, DO ZERO_WRITE_END UNTIL lce;      // R2 passes logical word count
ZERO_WRITE_END: DM(I0,M6)=R0;               // write zero to x16, x32, or x64 memory

    JUMP READ_BOOT_INFO;// fetch next section-header
//==============================================================================



//================================  ZERO_L48 ===================================
// Use core to initialize 48/40-bit internal memory to zero
//------------------------------------------------------------------------------
ZERO_L48:
    I0=R3;        //R3 passes destination address
    PX=0;
    LCNTR=R2, do L48_WRITE_END until lce;
L48_WRITE_END: dm(i0,m6)=PX;
    JUMP READ_BOOT_INFO;   // fetch next section-header
//==============================================================================


//===============================  INIT_L16 ====================================
// Initialize Internal Short-word (16-bit) Memory
//------------------------------------------------------------------------------
INIT_L16:

    I0=R3;                  //R3 passes destination address
    ustat2=r2;              //R2 passes 16-bit word count

    r6=r2-1;                //If count==1 don't use loop
    if EQ jump LAST_16;

    //divide count by 2 since each pass through the loop init's two 16-bit words
    r2= lshift r2 by -1;
    lcntr = r2, do READ_WRITE_END until lce;
        call READ_ONEx32;
        r6=dm(0x124006);    //SW equivalent of NW address 0x92003 (two LSBs)
        r7=dm(0x124007);    //SW equivalent of NW address 0x92003 (two MSBs)
        dm(i0,m6)=r6;
READ_WRITE_END: dm(i0,m6)=r7;
    bit tst ustat2 1;       // count odd or even? (0x1 = mask, not bit number)
    if NOT TF JUMP READ_BOOT_INFO;  //if bit0 of count was NOT 0x1 then the
                                    //count's even, so fetch next section-header

LAST_16:call READ_ONEx32;       //else fetch and init last x16 word of this section
        r6=dm(0x124006);
        dm(i0,m6)=r6;
        JUMP READ_BOOT_INFO;    // fetch next section-header
//==============================================================================


//==============================  INIT_L32 =====================================
// initialize 32-bit internal memory
//------------------------------------------------------------------------------
INIT_L32:
    I0=R3;              //R3 passes destination address
    LCNTR=R2, DO L32_CALL_LOOP_END UNTIL LCE;
        CALL READ_ONEx32(DB);
        NOP;            // Branches such as CALLs cannot be in the last three
        NOP;            // instructions of a loop
L32_CALL_LOOP_END: DM(I0,M6)=R8;
    JUMP READ_BOOT_INFO;// fetch next section-header
//==============================================================================


//==============================  INIT_L48 =====================================
// Initialize instructions and 40-bit data
//------------------------------------------------------------------------------
INIT_L48:
    I0=R3;                  //R3 passes destination address
    ustat2=r2;              //R2 passes 16-bit word count

    r6=r2-1;                //If count==1 don't use loop
    if EQ jump LAST_48;

     r2= lshift r2 by -1;   //divide count by 2 since each pass through the loop
                            // initializes two 48-bit words
    LCNTR=R2, DO L48_CALL_LOOP_END UNTIL LCE;
        CALL READ_THREEx32;         // fetch two 48-bit words (3x32)
        PX=dm(0x8c002);
        dm(i0,M6)=PX;
        PX=dm(0x8c003);
L48_CALL_LOOP_END: dm(i0,M6)=PX;

    bit tst ustat2 1;       // count odd or even? (0x1 = mask, not bit number)
    if NOT TF JUMP READ_BOOT_INFO;  //if bit0 of count was NOT 0x1 then the
                                    //count's even, so fetch next section-header

LAST_48:
    CALL READ_THREEx32;     //Else fetch and init last 48-bit word of section.
    //NOTE: Since DMA moves 32-bit words, the minimum number of instructions
    //accessible by DMA is 2 (3x32=2x48).  If there are an odd number of 48-bit
    //words, the loader inserts a dummy 48-bit word into the stream.  As one can
    //see below, only the first of the last 2 instructions is initialized: the
    //dummy word is ignored. (Specifically, it's left at the scratch location
    //0x8c003 and is overwritten by subsequent data.
    PX=dm(0x8c002);
    dm(i0,M6)=PX;
    JUMP READ_BOOT_INFO;            // fetch next section-header
//==============================================================================


//================================  INIT_L64 ===================================
INIT_L64:
    I0=R3;  //R3 passes destination address (LW, NW, or SW)
    LCNTR=R2, DO L64_CALL_LOOP_END UNTIL LCE;
        CALL READ_ONEx32;   // read 32 lsbs of 64-bit word
        PX1=R8;
        CALL READ_ONEx32;   // read 32 msbs of 64-bit word
        PX2=R8;
        nop;                // Call prohibited from last 3 loop instr's
L64_CALL_LOOP_END: DM(I0,M6)=PX (lw);  // write all 64-bits to longword address location
    JUMP READ_BOOT_INFO;               // fetch next section-header
//==============================================================================

// ============================== ZERO_EXT ===================================

// ============================== ZERO_EXT ===================================
// Use core to init external buffers to zero (saves space in LDR)
//------------------------------------------------------------------------------
ZERO_EXT8:
ZERO_EXT16:
      JUMP ZERO_LDATA;       // Initilalizing the external memory with zero is same as initializing the internal memory with zero for external port




//==============================================================================

//==============================  INIT_EXT =====================================
// initialize external memory
//------------------------------------------------------------------------------
INIT_EXT:
INIT_EXT8:
INIT_EXT16:
     JUMP INIT_L32;   // initializing external memory is same as initializing internal memory for external port



//============================ FINAL_INIT ======================================
// This code is the very last piece run in the kernel.  It is self-modifying
// code.  It uses a DMA to overwrite itself; initializing the 256 instructions
// that reside in the interrupt vector table. (Additional explanation below)
//------------------------------------------------------------------------------
final_init:

    //---- Setup for IVT instruction patch -------------------------------------
    I8=0x8c030;             // Point to SPI vector to patch from PX
    R9=0xb16b0000;          // Load opcode for "PM(0,I8)=PX" into R9
    PX=pm(0x8c003);         // User-instruction destined for 0x90030 is passed
                            // in the section-header for FINAL_INIT. That instr.
                            // is initialized upon completion of this DMA (see
                            // comments below) using the PX register.
    R11=BSET R11 BY 9;      // Set IMDW to 1 for inst write
    DM(SYSCTL)=R11;         // Set IMDW to 1 for inst write


    //---- Setup loop for self-modifying instruction ---------------------------
    I12=0x8c004;             // Point to 0x90004 for self modifing code inserted
                             // by the loader at 0x90004 in bootstream
    R9=pass R12, R11=R9;     // Clear AZ, copy power-on value of SYSCTL to R11
    DO  ___lib_RSTI UNTIL EQ;    // Set bottom-of-loop address (loopstack) to 0x90004
                            // and top-of-loop address (PC Stack) to the address
                            // of the next instruction.
    PCSTK=reset;          // Change top-of-loop value from the address of
                            // this instruction to 0x90003.

    //---- Enable SPI interrupt ------------------------------------------------
    bit clr IRPTL SPIHI;    // clear any pending SPI interrupt latch
    bit set IMASK SPIHI;    // enable SPI receive interrupt
    bit set MODE1 IRPTEN;   // enable global interrupts

    FLUSH CACHE;            // Remove any kernel instr's from cache
    
    //---- Setup final DMA parameters ------------------------------------------
    R1=0x92000; DM(IISPI)=R1;// Setup DMA to load over ldr
                DM(IMSPI)=M6;// Set to increment internal ptr
    R2=0x180;   DM(CSPI)=R2; // Load internal count
                    
    //---- Initiate self-modifying sequence ------------------------------------
    JUMP reset (DB);      // Causes 0x8c003 to be the return address when this
                            // DMA completes and the RTI at 0x8c030 is executed.
        IDLE;               // After IDLE, patch then start
        IMASK=0;            // clear IMASK on way to 0x8c003


//==============================================================================
// When this final DMA completes, the high-priority SPI interrupt is latched,
// which triggers the following chain of events:
//
//  1) The IDLE in the delayed branch to completes
//  2) IMASK is cleared
//  3) The PC (now 0x8c003 due to the "JUMP RESET (db)") is pushed on the
//      PC-Stack and the DSP vectors to 0x8c030 to service the interrupt.
//
//      - Meanwhile, the loader (anticipating this sequence) has automatically
//      inserted an "RTI" instruction at 0x8c030. The user-instruction intended
//      for that address is instead placed in the FINAL_INIT section-header, and
//      was loaded into PX before the DMA was initiated.)
//
// 4) The DSP executes the RTI at 0x8c030, and vectors to the address stored
//      on the PC-stack (0x8c003).
//
//      - Again, the loader has inserted an instruction into the boot stream and
//      has placed it at 0x8c004:
//
//          R0=R0-R0, DM(I4,M5)=R9, PM(I12,M13)=R11;   //opcode: 0x39732D802000
//
//      The loader has also placed a NOP at location 0x8c003, opcode 0x000000000000
//      Locations 0x8c000 - 0x8c004 are reserved and should never be used in any user
//      application. Because of this, the two locations used in final init are never 
//      restored to the value set forth in the executable generated by the tools.
//
//
// 5) This instruction does three things:
//
//      A) Restores the power-up value of SYSCTL (held in R11).
//      B) It overwrites itself with the instruction "PM(0,I8)=PX;"
//          (The first instruction of FINAL_INIT places the opcode for this
//          new instruction, 0xB16B00000000, into R9.)
//      C) R0=R0-R0 causes the AZ flag to be set.
//
//      This satisfies the loop termination-condition of the loop set up
//      in FINAL_INIT ("DO final_init_loop UNTIL EQ;").  When a loop condition is
//      achieved within the last three instructions of a loop, the DSP branches
//      to the top-of-loop address (PCSTK) one final time.
//
// 6) We manually changed this top-of-loop address to 0x8c003, and so to conclude
//      the kernel, the DSP executes the instructions at 0x8c003 and 0x8c004 *again*.
//
// 7) Now, there's a new instruction at 0x8c004: "PM(0,I8)=PX;".  This
//      initializes the user-intended instruction at 0x8c030 (the vector for
//      the High-Priority-SPI interrupt). //
//
//  At this point, the kernel is finished, and execution continues at 0x8c005.
//==============================================================================









//==============================  USER_INIT  ===================================
// This space is provided for the user to insert code. This is only required
// when a system requires a custom configuration for the DSP.  

// These External Port and PLL settings are for the ADSP-21469 EZkit.
// Update the settings below to match the requirements for the target board.
//------------------------------------------------------------------------------
user_init:
		r0=TUNF|ROVF;
		dm(SPISTAT)=r0;
		
		r0=TXFLSH|RXFLSH;
		dm(SPICTL)=r0;
		
		r0=0x80;
		dm(SPIDMAC)=r0;
	
		r0=0x64;
		dm(SPIBAUD)=r0;
		
		
		r0=0xb8000;
		dm(IISPI)=r0;
		
		r0=1;
		dm(IMSPI)=r0;
		
		r0=1;
		dm(CSPI)=r0;
		
		r0=0xFF01;
		dm(SPIFLG)=r0;
		
		r0=SPIEN|SPIMS|WL32|SENDZ|CLKPL|CPHASE|TIMOD2;
		dm(SPICTL)=r0;

		r0=dm(_app_offset);
		
		r1=0x03000600;
		
		r0=r0 OR r1;
		
		i0=r0;
		
		bitrev(i0,0);
		
		r0=i0;
		dm(TXSPI)=r0;
	
		r0=0xFE01;
		dm(SPIFLG)=r0;
		
		r0=0x00000007;
		dm(SPIDMAC)=r0;
	
		ustat1=dm(SPIDMAC);
    	bit tst ustat1 SPIDMAS; // Check SPI DMA Status bit
    	IF TF jump (pc,-2);     // SPIDMAS = 1 when DMA in progress

//#define DEBUG   // insert this definition in case you want to debug the kernel
#define EXT_MEMORY // insert this definition to initialize external memory
 
        // ------------------ DEBUG BOOTING USING ICE? ----------------
        // Include this "trap" instruction by using the -D switch on the commandline when building
        // (for example: 	easm21k.exe -21469 -o 46x_spi.doj 46x_spi.asm -DDEBUG ) or by uncommenting the 
        // #define DEBUG line in the program just after the USER_INIT label
        // Attach emulator/debugger and hit run.  While running, reset board to trigger the SPI master boot.
        // Now, when you hit halt with the emulator, you'll be at the following instruction. Change
        // the instruction to a NOP; and you'll be able to single-step through the kernel.
        #ifdef DEBUG
          kdebug:         jump (pc,0);    // do not completely execute kernel - allows ICE to break in.
        #endif
        // (Note: to make debugging the kernel more simple, you can load the LABEL's using the
        // following TCL command in the IDDE console:
        //
        //                  dspload "C:\\<path>\\46x_spi.DXE" -symbols
        //
        // --------------------------------------------------
        
       
        // Include this External Memory initialization by using the -D switch on the commandline when building
        // (for example: 	easm21k.exe -21469 -o 46x_spi.doj 46x_spi.asm -DEXT_MEMORY ) or by uncommenting the 
        // #define EXT_MEMORY line in the program just after the USER_INIT label

#ifdef EXT_MEMORY
/* Set the PLL based on the clock rate */

// For the EZ-kit CLKIN = 16.384MHz 

InitPLL:
#define CCLK_400_DDR_200
// CLKIN= 25 MHz, Multiplier= 18, Divisor= 2, CCLK_SDCLK_RATIO 2.
// Fcclk = (CLKIN * 2 * M) / (N * D)
// VCO max frequency = 1000 GHz
// M = 1 to 64, N = 2,4,8,16 and D = 1 if INDIV = 0, D = 2 if INDIV = 1


#ifdef CCLK_450_DDR_225
// Core clock = (25MHz * 2* 18) /(2 * 1) = 450 MHz
// DDR2 clock = 450 / 2 = 225 MHz.

    ustat3 = PLLM18|PLLD1|DDR2CKR2|LPCKR3|MLBCKR4;
#endif
#ifdef CCLK_400_DDR_200
// Core clock = (25MHz * 2* 16) /(2 * 1) = 400 MHz
// DDR2 clock = 400 / 2 = 200 MHz.

	ustat3 = PLLM16|PLLD1|DDR2CKR2|LPCKR3|MLBCKR4;
#endif
changePLL:

    bit set ustat3 DIVEN;
    dm(PMCTL) = ustat3;
    
    bit set ustat3 PLLBP; //Place the PLL in bypass mode.
	bit clr ustat3 DIVEN; //Clear the DIVEN bit while placing the PLL in bypass mode.
    dm(PMCTL) = ustat3;

     // Wait for at least 4096 cycles for the pll to lock
    lcntr = 5000, do loopend2 until lce;
loopend2:     nop;

    ustat3 = dm(PMCTL);	//Reading the PMCTL register will return the DIVEN bit value as zero.
    bit clr ustat3 PLLBP; //Take the PLL out of bypass mode.
    dm(PMCTL) = ustat3;
    
    lcntr = 14, do loopend3 until lce;
loopend3:     nop;


InitDDR2:
// FPGA code - D9HNZ
// DDR2 memory on BUB - MT47H64M16HR-3:E
//3.0ns @ CL = 5 (DDR2-667) -3
// Parameters 
// Config - 128M x 16(16M x 16 x 8)
// Speed -        400/533/667 MHz
// CAS Latency -   3/4/5
// Row addressing - 8K(A0-A12)
// Column addressing - 1K(A0-A9)
// No of Banks - 8

//tRCD - 15ns
//tRP - 15ns
//tRC - 60ns
//tRRD - 10ns
//tRASmin - 45ns
//tRFC - 127.5ns
//tFAW - 50ns
//tRTP - 7.5ns
//tWR - 15ns
//tWTR - 7.5ns
// tREFI - 7.8ns

//For the case, tDDR2CLK = 1/225 MHz = 4.4ns 
// CAS Latency = 4
// tRCD = 15 / 4.4 = 4(3.4)
// tRP = 15 / 4.4 = 4(3.4)
// tRC = 60 / 4.4 = 14(13.6)
// tRRD = 10/4.4 = 3(2.27)
// tRAS = 40/ 4.4 = 9(9.0)
// tRFC = 127.5/4.4 = 29(28.9) = 0x1D
// tFAW = 50/4.4 = 12(11.36)
// tRTP = 7.5 / 4.4 = 2(1.70)
// tWR = 15 / 4.4 = 4(3.4)
// tWTR = 7.5 / 4.4 = 2(1.70)

// RDIV = ((f DDCLK X t REFI)) - (t RAS + t RP)
// RDIV = (225 X 10^6 x 7.8 x 10^-6) - (11 + 4)
// RDIV = 1740 = 0x6CC

//For the case, tDDR2CLK = 1/200 MHz = 5ns 
// CAS Latency = 3
// tRCD = 15 / 5 = 3
// tRP = 15 / 5 = 3
// tRC = 60 / 5 = 12
// tRRD = 10/5 = 2
// tRAS = 40/ 5 = 8
// tRFC = 127.5/5 = 26 
// tFAW = 50/5 = 10
// tRTP = 7.5 / 5 = 2(1.5)
// tWR = 15 / 5 = 3
// tWTR = 7.5 / 5 = 2(1.5)

// RDIV = ((f DDCLK X t REFI)) - (t RAS + t RP)
// RDIV = (200 X 10^6 x 7.8 x 10^-6) - (8 + 3)
// RDIV = 1546 = 0x60A

#ifdef CCLK_450_DDR_225
	#define DDR2TRFC29 (0x1D << 21)
	#define RDIV	(0x6CC)
#endif

#ifdef CCLK_400_DDR_200
	#define DDR2TRFC26 (0x1A << 21)
	#define RDIV	(0x60D)
#endif

/********************************************************************/
/* On chip DLL reset. (Not required if frequency is not changed) */
/* DLL locks to new frequency after this reset */
/********************************************************************/
	USTAT1 = dm(DLL0CTL1);
	BIT SET USTAT1 0xE00; // RESETDLL, RESETDAT, RESETCAL
	dm(DLL0CTL1) = USTAT1; // DLL0 reset

	USTAT1 = dm(DLL1CTL1);
	BIT SET USTAT1 0xE00; // RESETDLL, RESETDAT, RESETCAL
	dm(DLL1CTL1) = USTAT1; // DLL1 reset
	// Wait for DLL to get reset
	lcntr = 8, do(PC,dll_reset) until lce;
	dll_reset: nop;
/********************************************************************/
/* Wait until DLL locks to new frequency */
/********************************************************************/
	// Wait for a fixed period of time
#ifdef CCLK_400_DDR_200
#define dll_lock_period 3000  // 512 DDCLK cycles
#endif
#ifdef CCLK_450_DDR_225
#define dll_lock_period 3000  // 512 DDCLK cycles
#endif
	lcntr = dll_lock_period, do(PC,dll_lock) until lce;
	dll_lock: nop;
	/* OR */
	// Wait until the lock status bit in both the DLL status registers get set
	/*
	wait_dll0_lock: USTAT1 = dm(DLL0STAT0);
	bit tst USTAT1 DLL_LOCKED; // Bit 30
	if not tf jump wait_dll0_lock;
	wait_dll1_lock: USTAT1 = dm(DLL1STAT0);
	bit tst USTAT1 DLL_LOCKED; // Bit 30
	if not tf jump wait_dll1_lock;
	*/
/********************************************************************/
/* Enable external bank(s) in DDR2 mode */
/********************************************************************/
	USTAT1 = 0x0;
	bit set USTAT1 B0SD | EPBRCORE | DMAPRCH0 | NOFRZDMA | NOFRZCR ;
	dm(EPCTL) = USTAT1;
/********************************************************************/
/* Program the control registers */
/********************************************************************/

	
	// Refresh rate control register
	USTAT1 = 0x0;
#ifdef CCLK_400_DDR_200	
	bit set USTAT1 DDR2TRFC26 | RDIV;
#endif	
#ifdef CCLK_450_DDR_225
	bit set USTAT1 DDR2TRFC29 | RDIV;
#endif
	dm(DDR2RRC) = USTAT1;
	// Timing parameter register
	USTAT1 = 0x0;
#ifdef CCLK_400_DDR_200
	bit set USTAT1 DDR2TFAW10 | DDR2TRRD2 | DDR2TRTP2 | DDR2TRCD3 | DDR2TWTR2 | DDR2TRP3 | DDR2TRAS8 ;
#endif
#ifdef CCLK_450_DDR_225
	bit set USTAT1 DDR2TFAW12 | DDR2TRRD3 | DDR2TRTP2 | DDR2TRCD4 | DDR2TWTR2 | DDR2TRP4 | DDR2TRAS9 ;
#endif
	dm(DDR2CTL1) = USTAT1;
	// Mode register
	USTAT1 = 0x0;
#ifdef CCLK_400_DDR_200
	bit set USTAT1 DDR2MR | DDR2TWR3 | DDR2CAS3 | DDR2BL4 ;
#endif
#ifdef CCLK_450_DDR_225
	bit set USTAT1 DDR2MR | DDR2TWR4 | DDR2CAS4 | DDR2BL4 ;
#endif
	dm(DDR2CTL2) = USTAT1;
	// Extended mode register
	USTAT1 = 0x0;
	bit set USTAT1 DDR2EXTMR1 | DDR2AL0 | DDR2ODTDIS | DDR2DLLEN;
	dm(DDR2CTL3) = USTAT1;
	// Extended mode register (2)
	USTAT1 = 0x0;
	bit set USTAT1 DDR2EXTMR2;
	dm(DDR2CTL4) = USTAT1;
	// Extended mode register (3)
	USTAT1 = 0x0;
	bit set USTAT1 DDR2EXTMR3;
	dm(DDR2CTL5) = USTAT1;
	// Main control register
	// DDR2 initialisation sequence starts after setting this register,
	// all other registers ( EPGCTL, DD2RRC, DD2CTL1-5 ) should be initialised
	// before setting this main control register
	USTAT1 = 0x0;
	bit set USTAT1 DDR2PSS | DDR2RAW13 | DDR2CAW10 | DDR2BC8 | DDR2WDTHx16 | DDR2OPT | DDR2MODIFY1;
	dm(DDR2CTL0) = USTAT1;
/********************************************************************/
/* Wait for DLL calibration to complete ( On chip DLL) */
/********************************************************************/
	wait_for_cal: USTAT1 = dm(DDR2STAT0);
	bit tst USTAT1 DDR2DLLCALDONE;
	if not tf jump wait_for_cal;
	// NOTE: If no banks are enabled in DDR2 mode calibration won't happen
	// and DD2CAL_DONE will never get set.
/********************************************************************/
/* Chip is now ready for DDR2 accesses */
/********************************************************************/

	r0 = dm(0x200000);
	nop;
	nop;
	nop;
	nop;
	

#endif //USE_EXT_MEMORY
	rts;
//==============================================================================/