返回> 网站首页 

[转载]ICF文件解析与实验

yoours2012-11-02 11:33:47 阅读 1576

简介一边听听音乐,一边写写文章。

ICF文件如下:

// Define a memory region that covers the entire 4 GB addressible space of the processor.
define memory mem with size = 4G;
// Define a region for the on-chip flash.
define symbol ROM_START = 0x00000000;
define symbol ROM_END   = 0x0003ffff;
define region INTVECT = mem:[from ROM_START to ROM_START+0x000003ff];
define region PARSEG  = mem:[from ROM_START+0x00000400 to ROM_START+0x000007ff];
define region FLASH = mem:[from ROM_START+0x00000800 to ROM_END];

// Define a region for the on-chip SRAM.
define region SRAM = mem:[from 0x20000000 to 0x2000ffff];
// Define a block for the heap.  The size should be set to something other than zero if things in the C library that require the heap are used.
define block HEAP with alignment = 8, size = 0x00000000 { };
// Indicate that the read/write values should be initialized by copying from flash.
initialize by copy { readwrite };
// Initicate that the noinit values should be left alone.  This includes the stack, which if initialized will destroy the return address from the initialization code, causing the processor to branch to zero and fault.
do not initialize { section .noinit };
// Place the interrupt vectors at the start of flash.
//place at start of FLASH { readonly section .intvec };
place at start of INTVECT { readonly section .intvec };
place at start of PARSEG { readonly section SPARSEG };
// Place the remainder of the read-only items into flash.
place in FLASH { readonly };
// Place all read/write items into SRAM.
place at start of SRAM {readwrite section VTABLE};
place in SRAM { readwrite, block HEAP };

一、解析: 
1.
define symbol ROM_START = 0x00000000;
define symbol ROM_END   = 0x0003ffff;//定义ROM即flash的起始地址,(根据芯片的实际情况,共256K)
 
2.
define region INTVECT = mem:[from ROM_START to ROM_START+0x000003ff];
define region PARSEG  = mem:[from ROM_START+0x00000400 to ROM_START+0x000007ff];
define region FLASH = mem:[from ROM_START+0x00000800 to ROM_END];
 
上述将flash空间分成三部分
"mem:[from ROM_START to ROM_START+0x000003ff];"共1KB的空间,用来存储中断向量
"mem:[from ROM_START+0x00000400 to ROM_START+0x000007ff];"1KB空间,用来存储一些系统参数
"mem:[from ROM_START+0x00000800 to ROM_END];"其余的flash空间用来存放我们的代码。
 
3.
define region SRAM = mem:[from 0x20000000 to 0x2000ffff];//定义RAM地址空间(根据实际情况,共64KB)
 
4.
initialize by copy { readwrite };
do not initialize { section .noinit };//说明区域的初始化方式。
 
5.比较重要的一点:
place at start of INTVECT { readonly section .intvec };//将.intvec区域放在INTVECT中,.intvec.将在下面的startup.c中初始化
place at start of PARSEG { readonly section SPARSEG };//参数区放在PARSEG 中。
place in FLASH { readonly };//将其他的只读区放在FLASH中(上面定义的from ROM_START+0x00000800 to ROM_END)
 
place at start of SRAM {readwrite section VTABLE};//RAM中的中断向量表
place in SRAM { readwrite, block HEAP };//其他全局变量等所用的内存空间。

由上我们可以看到,flash共分成三块:中断向量表,参数区,代码区
RAM分成中断向量表及其他区。

二、再打开工程中的startup.c文件:

#pragma language=extended
// Forward declaration of the default fault handlers.
static void NmiSR(void);
static void FaultISR(void);
static void IntDefaultHandler(void);
extern void Timer0IntHandle(void);

// External declaration for the interrupt handler used by the application.
//extern void UARTIntHandler(void);
// The entry point for the application startup code.
extern void __iar_program_start(void);
// Reserve space for the system stack.
static unsigned long pulStack[64] @ ".noinit";
// A union that describes the entries of the vector table.  The union is needed since the first entry is the stack pointer and the remainder are function pointers.
typedef union
{
    void (*pfnHandler)(void);
    unsigned long ulPtr;
}
uVectorEntry;
// The vector table.  Note that the proper constructs must be placed on this to ensure that it ends up at physical address 0x0000.0000.
__root const uVectorEntry __vector_table[] @ ".intvec" =
{
    { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },
                                            // The initial stack pointer
    __iar_program_start,                    // The reset handler
    NmiSR,                                  // The NMI handler
    FaultISR,                               // The hard fault handler
    IntDefaultHandler,                      // The MPU fault handler
    IntDefaultHandler,                      // The bus fault handler
    IntDefaultHandler,                      // The usage fault handler
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    0,                                      // Reserved
    IntDefaultHandler,                      // SVCall handler
    IntDefaultHandler,                      // Debug monitor handler
    0,                                      // Reserved
    IntDefaultHandler,                      // The PendSV handler
    IntDefaultHandler,                      // The SysTick handler
    IntDefaultHandler,                      // GPIO Port A
    IntDefaultHandler,                      // GPIO Port B
    IntDefaultHandler,                      // GPIO Port C
    IntDefaultHandler,                      // GPIO Port D
    IntDefaultHandler,                      // GPIO Port E
    IntDefaultHandler,                      // UART0 Rx and Tx
    IntDefaultHandler,                      // UART1 Rx and Tx
    IntDefaultHandler,                      // SSI0 Rx and Tx
    IntDefaultHandler,                      // I2C0 Master and Slave
    IntDefaultHandler,                      // PWM Fault
    IntDefaultHandler,                      // PWM Generator 0
    IntDefaultHandler,                      // PWM Generator 1
    IntDefaultHandler,                      // PWM Generator 2
    IntDefaultHandler,                      // Quadrature Encoder 0
    IntDefaultHandler,                      // ADC Sequence 0
    IntDefaultHandler,                      // ADC Sequence 1
    IntDefaultHandler,                      // ADC Sequence 2
    IntDefaultHandler,                      // ADC Sequence 3
    IntDefaultHandler,                      // Watchdog timer
    IntDefaultHandler,                      // Timer 0 subtimer A
    IntDefaultHandler,                      // Timer 0 subtimer B
    IntDefaultHandler,                      // Timer 1 subtimer A
    IntDefaultHandler,                      // Timer 1 subtimer B
    IntDefaultHandler,                      // Timer 2 subtimer A
    IntDefaultHandler,                      // Timer 2 subtimer B
    IntDefaultHandler,                      // Analog Comparator 0
    IntDefaultHandler,                      // Analog Comparator 1
    IntDefaultHandler,                      // Analog Comparator 2
    IntDefaultHandler,                      // System Control (PLL, OSC, BO)
    IntDefaultHandler,                      // FLASH Control
    IntDefaultHandler,                      // GPIO Port F
    IntDefaultHandler,                      // GPIO Port G
    IntDefaultHandler,                      // GPIO Port H
    IntDefaultHandler,                      // UART2 Rx and Tx
    IntDefaultHandler,                      // SSI1 Rx and Tx
    IntDefaultHandler,                      // Timer 3 subtimer A
    IntDefaultHandler,                      // Timer 3 subtimer B
    IntDefaultHandler,                      // I2C1 Master and Slave
    IntDefaultHandler,                      // Quadrature Encoder 1
    IntDefaultHandler,                      // CAN0
    IntDefaultHandler,                      // CAN1
    IntDefaultHandler,                      // CAN2
    IntDefaultHandler,                      // Ethernet
    IntDefaultHandler                       // Hibernate
};

// This is the code that gets called when the processor receives a NMI.  This simply enters an infinite loop, preserving the system state for examination by a debugger.
static void NmiSR(void)
{
    // Enter an infinite loop.
    while(1)
    {
    }
}

// This is the code that gets called when the processor receives a fault interrupt.  This simply enters an infinite loop, preserving the system state for examination by a debugger.
static void FaultISR(void)
{
    // Enter an infinite loop.
    while(1)
    {
    }
}
// This is the code that gets called when the processor receives an unexpected interrupt.  This simply enters an infinite loop, preserving the system state for examination by a debugger.
static void IntDefaultHandler(void)
{
    // Go into an infinite loop.
    while(1)
    {
    }
}

其中最最重要的就是中断向量表,而其中最最重要的是向量表的第一行和第二行:
__root const uVectorEntry __vector_table[] @ ".intvec" =
{
    { .ulPtr = (unsigned long)pulStack + sizeof(pulStack) },
     .........
}
先看第一行,最后一个词".intvec"是不是见过?对,就是place at start of INTVECT { readonly section .intvec };中的".intvec",而此词之前的'@',就是'at'的意思了。。。也就是说向量表是放在INTVECT中的,而INTVECT是放在flash的最开始的,------>中断向量表放在地址空间的0x00000000处了!!!!
第二行,根据CM3的知识,大家都知道这个是堆栈地址了。

__iar_program_start是编译器自带的引导程序到main函数的一段代码,在编辑阶段我们无法看到,只有在Debug单步执行的时候我们才可以看到。。此时我们只需要知道它可以引导到我们的main函数。
 
然后开始Debug调试,在执行main函数之前,我们可以看到:
flash地址空间中,0x0000 0000-0x0000 03FF是中断向量表,0x0000 0400-0x0000 07FF地址空间竟没有用,因为我现在还没有往其中定义数据。0x0000 0800-0x0003FFF中与我们用UE打开编译形成的bin文件一样----------->对,这就是我们的代码区。
 
 
RAM地址空间中,起始的0x2000 0000-0x2000 0117地址是空的,再往下0x2000 0118-0x2000 0218也是空的,为什么呢???
 
再数数,startup.c的中断向量表中只有60的中断地址,现在打开库文件中的interrupt.c的最开始的一段找到这么一行:
static __no_init void (*g_pfnRAMVectors[NUM_INTERRUPTS])(void) @ "VTABLE";
这里对VTABLE进行了分配,而且宏定义NUM_INTERRUPTS=70,70*4=0x118,也就是说RAM中的中断向量表的大小是0x118.(0x2000 0000-0x2000 0117)
接着往下的空间就是系统堆栈区,堆栈的大小在startup.c中进行了定义:
static unsigned long pulStack[64] @ ".noinit";
64*4=256Byte->0x2000 0118-0x2000 0228地址空间了。
 
现在中断向量表还在flash中,还没有拷到RAM中,但我们调用一次中断向量注册函数:IntRegister(U0Int, U0IntHandle); 注册中断向量后,再查看RAM空间时,中断向量表基本一样了吧(当然还是有一点差别的,就是刚才注册的中断向量已经在RAM的中断向量表中了,而flash中的中断向量表不会变)。
 
这又是什么时候拷到RAM中去的呢???
 
找到IntRegister的函数体,会发现其中的秘密:
if(HWREG(NVIC_VTABLE) != (unsigned long)g_pfnRAMVectors)
    {
        // Copy the vector table from the beginning of FLASH to the RAM vector table.
        ulValue = HWREG(NVIC_VTABLE);
        for(ulIdx = 0; ulIdx < NUM_INTERRUPTS; ulIdx++)
        {
            g_pfnRAMVectors[ulIdx] = (void (*)(void))HWREG((ulIdx * 4) +
                                                     ulValue);
        }

        // Point NVIC at the RAM vector table.
        HWREG(NVIC_VTABLE) = (unsigned long)g_pfnRAMVectors;
    }
系统正是通过这段代码实现了flash中中断向量表向RAM中的拷贝。
 
到此,整个过程差不多完成了,但其中还有好多的东西值得去学习,比如我们可以看一些变量存储的地址是在0x2000 0118-0x2000 0228还是在0x2000 0228以后的地址空间,便知道这个变量是什么类型的变量等等。。
微信小程序扫码登陆

文章评论

1576人参与,0条评论