⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 161_spi.asm

📁 ADI SHARC DSP系统启动源码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
/* ==============================================================================

		161_spi.asm

		Serial Peripheral Interface compatible port based boot loader for the
		ADSP21161 processor

		Copyright (c) 2002 Analog Devices Inc.  All rights reserved.

		version 0.1 6/21/01 - Zero initializations and external memory sections
		have not been tested.  Check for newest version of the SPI kernel at
		ftp.analog.com/pub/dsp/211xx/dev_tools/loader.

		version 0.2 8/1/01 - All sections of kernel have been tested.

		version 1.0 10/17/01 - R14 = 0xA001F81; was improperly initialized to
		R14 = 0xA801F81; in the previous version of the kernel.

		version 1.1 1/14/02 - changed some comments and fixed wait state init in
		SDRAM init section

		version 2.0 05.Sept.02  MSW
			- Added initialization of all external memory types
			-Added code to patch SPI IVT entry in final init
			- Added final-init comments
			- Added comments regarding tag info for each section

		version 2.1 17.Oct.02 MSW
	        - Added comments regarding spi overflow errors possible during zero
	          initialization sections
	        - Added code to trap on spi overflow

	    version 2.2 20.DEC.2002 - M.Walsh
			- Changed #define SDRAM 1 to #define SDRAM 0

		SPI Feedback version 1.0 24.FEB.2003 - B.Mitchell
			- Included feedback scheme described in EE-177

==============================================================================*/


#include <def21161.h>
#define SDRAM 1

.SECTION/PM	seg_ldr;

		NOP;NOP;NOP;NOP;		// Reserved interrupt

reset: 	nop;	// - Instruction specified here is never executed.  The core implicitly executes
                // an IDLE instruction here until 256 instructions are booted.  Once the kernel
                // is booted, execution resumes at 0x40040 (the SPI Rx ISR).  This address
                // (0x40005) and the next (0x40006) are also used as a temporary buffer to DMA-in
                // words from the SPI port

        nop;	// scratch memory2

//turn off SPI dma while kernel is executing
		ustat1=dm(SPICTL);
		bit clr ustat1 RDMAEN;	//clear DMA bit in SPICTL
		dm(SPICTL)=ustat1;

        call user_init;         // call subroutine at end of kernel in which users can insert
                                // initalization code, such as SDRAM, waitstates, etc.

        R5=2;                   // used to decrement tag by two during loading.

		L0=0; L1=0; L4=0;	    // Zero out L-registers so they	can be used without wrap
		L8=0; L12=0;L15=0;    	// ie. no circular buffering

		M5=0;M6=1;		        // Setup M-registers to use for various memory transfers
		M13=0; M14=1; M15=3;    // use to load count in read_dma_info

		I15 = 0x40006;			// scratch DMA destination address for 32 bit words;
		R14 = 0xA001F83;		// sets up and enables SPI port with DMA, this is also the default setting

		R11=DM(SYSCON);			// Read current SYSCON setting
		R12=PASS R11;			// Hold Initial SYSCON setting
		I12 = SYSCON;			// Address of SYSCON



// ==========================  READ_BOOT_INFO  =======================================
// Places TAG in R8, Word Count in R2, and Destination Address in R3
// -----------------------------------------------------------------------------------
read_boot_info:
        call read_dma_info;     // place two 48-bit words into 0x40004 and 0x40005
                                // equivalent to placing three 32-bit words into 0x40006,7,& 8
		R2=dm(0x40006);		//r2 passes section length
		R3=dm(0x40007);		//r3 passes destination address
		R8=dm(0x40008);     //r8 passes data-type tag
// -----------------------------------------------------------------------------------



// ========================== SPI Overflow Detect ====================================
// Monitor the SPI Status register to ensure that no overflow has ocurred.  The RBSY
// (receiver busy) bit in SPI is set to 1 when the SPI port receive buffer is full and
// another word is clocked into the shift register.  This may happen if the core is
// performing a zero-initialization section, and the SPI-master device continues to
// send data. RBSY is a sticky bit, so it will stay set until the spi port is
// disabled.
//
// If an overflow is detected the kernel will trap in an infinite loop so that user
// intervention can determine the problem.  If this problem occurs, the SPI-master
// device must be configured to pause while the DSP performs the zero initializations.
// This can be done in software by looking at the .LDR section headers, or in hardware
// by configuring the kernel to set a DSP flag pin while it is performing zero-
// initializations. More information can be found in an EE note on the ADI website
// titled "21161 SPI Booting".  http://www.analog.com/dsp
// -----------------------------------------------------------------------------------
        USTAT1=DM(SPISTAT);
        bit tst USTAT1 RBSY;
        if tf JUMP (pc,0);
        jump start_loader;
// -----------------------------------------------------------------------------------




// ============================= FINAL_INIT =========================================
// This code is the very last piece run in the kernel.  It uses a DMA to initialize the
// 256 instructions that reside in the interrupt vector table.
// -----------------------------------------------------------------------------------
final_init:	R9=0xb16b0000;          /* Load instruction PM(0,I8)=PX; 	*/

			R11=BSET R11 BY 9;      /* Set IMDW to 1 for inst write  	*/
			DM(SYSCON)=R11;         /* Setup for instruction write     	*/

			I4=0x40004;            /* Point to 0x040004 for self modifing code*/

            PX=pm(0x40004);         /* Load instruction to be patched into 0x40040*/
			I8=0x40040;            /* Point to DMA8 vector to patch 	*/

			R9=pass R9, R11=R12;	/* Clear AZ, hold initial SYSCON 	*/
			DO reset UNTIL EQ;      /* set top of loop value to 0x40004 (see comments below)*/
			PCSTK=0x40004;			/* Set top of PC-stack, so RTI after final DMA goes to 0x40004;*/

            //setup DMA parameters
			            DM(IMSRX)=M6;            /* Set to increment internal ptr 	*/
            R1=0x40000; DM(IISRX)=R1;             /* Setup DMA to load over ldr   	*/
			R2=0x180;   DM(CSRX)=R2;				/* Load internal count				*/

			bit clr LIRPTL SPIRI;	    // clear pending SPIRX interrupt latch 	*/
			bit set IMASK LPISUMI;		// enable LPISUMI interrupt
			bit set LIRPTL SPIRMSK;		// enable SPI receive interrupt
            bit set mode1 IRPTEN;       // enable global interrupts

            FLUSH CACHE;			/* Flush cache for kernel overwrite	*/

            DM(SPICTL)=R14;			/* Start DMA transfer				*/

            JUMP 0x40004 (DB);      /* Jump to start                	*/
				IDLE;					/* After IDLE, patch then start		*/
                IMASK=0;                // clear IMASK on way to 0x40004

// When this final DMA completes, IDLE in the delayed branch completes, IMASK is cleared,
// and then the DSP executes the instruction at 0x40004. The loader automatically places the following
// instruction at that address:
//
//          R0=R0-R0, DM(I4,M5)=R9, PM(I12,M13)=R11;   //opcode: x39732D802000
//
// Executing this instruction performs the three things:
// 1) It sets the AN flag ("until EQ" now evaluates as true)
// 2) It restores the power-up value of SYSCON (held in R11).
// 3) It overwrites itself with the instruction PM(0,I8)=PX; (held in R9)
//
// Because the termination condition (EQ) is achieved within the last three instructions
// of the loop, the DSP jumps to the top-of-loop address one last time.  We manually changed this
// top-of-loop address (PCSTK) to x40004, so, to conclude the kernel, the DSP executes the instruction
// at 0x40004 again.  The new instruction there resets the DMA10 interrupt vector (x40050) to it's
// user-intended final value. At this point, the kernel is finished, and execution continues at
// 0x40005 as if nothing happened!
//
// ========================== END FINAL_INIT ==============================







// ==========================================================================
// ========================== SPI Recieve DMA ISR ===========================
// This code must resolve to 0x40 in the interrupt vector table. If any code
// is added or removed prior to this without padding with "NOP's", then this
// kernel will not function.
            nop;nop;nop;nop;// added nop's to resolve RTI to correct address
            nop;nop;
x40040:     nop; RTI;	// return to 0x40006 and begin executing kernel
// ========================== END SPI Recieve DMA ISR ======================



// =============================  START LOAD   ========================================
// The following instructions analyze the TAG for each data section and initialize
// accordingly.  READ_BOOT_INFO places the TAG in R8, Word Count in R2, and Destination
// Address in R3.
//
// Notes:
// - Several tags are initialized with common code to save space.
// - These instructions must execute sequentially because the tag value
// is decremented after each false test.
// -----------------------------------------------------------------------------------
start_loader:
                R0=PASS R8;
                IF EQ jump final_init;  // jump if tag = 0

//--------------- 1 0x0001 ZERO DM16 ---------------
//--------------- 2 0x0002 ZERO DM32 ---------------
test_dm_zero:	R0=R0-R5;   	        // R5=2
			    IF GT JUMP (PC, test_dm40_zero);
dm_zero:
				bit set mode2 0x8000;	//Set FLAG0 as an Output
				bit clr flags 0x1;		//Clear FLAG0 to pause SPI Host
				R0=R0-R0, I0=R3;        //clears r0 and sets I0 to R3 which is the address information
				LCNTR=R2, DO dm_zero.end UNTIL LCE;
dm_zero.end:		DM(I0,M6)=R0; 	    // writes zeros to dm memory; M6=1
				bit set flags 0x1;		//Set FLAG0 to continue boot data
    			JUMP read_boot_info;
// ---------------------------------------------------


//--------------- 3 0x0003 ZERO DM40 ---------------
test_dm40_zero: R0=R0-1;	// checks for tag zero dm40
                IF NE JUMP (PC, test_dm_init);
dm40_zero:
				bit set mode2 0x8000;	//Set FLAG0 as an Output
				bit clr flags 0x1;		//Clear FLAG0 to pause SPI Host
				PX1=0;
    			PX2=0;	// clears px
	    		R0=R0-R0, I0=R3;
		    	LCNTR=R2, DO dm40_zero.end UNTIL LCE;
dm40_zero.end:		DM(I0,M6)=PX;	// writes px out to correct memory locations
				bit set flags 0x1;		//Set FLAG0 to continue boot data
    			JUMP read_boot_info;
// -------------------------------------------------------


//--------------- 4 0x0004 INIT DM16 ---------------
//--------------- 5 0x0005 INIT DM32 ---------------
test_dm_init:   R0=R0-r5;	// checks for tag init dm16
			    IF GT JUMP (PC, test_dm40_init);
dm_init:        B0=R3;
    			LCNTR=R2, DO dm16_init.end UNTIL LCE;
	        	CALL read_SPI_word;
				DM(I0,M6)=R8;
				NOP;
dm16_init.end:	NOP; //a call can't be in the last 3 instructions
    			JUMP read_boot_info;
// -------------------------------------------------------

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -