打印
[S3C2440]

汇编启动代码中调用C函数出问题

[复制链接]
1558|4
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lr2131|  楼主 | 2014-4-18 15:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 lr2131 于 2014-4-18 15:09 编辑

最近有些小空闲,想学学bootloader,在MDK + JLINK + S3C2440这样的配置下,我写了些简单的代码,出了些问题,实在不知道怎么进行下去。

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;startup.s     汇编启动代码;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SVC_STACK_LEGTH        EQU        0   
FIQ_STACK_LEGTH        EQU        0  
IRQ_STACK_LEGTH        EQU        256   
ABT_STACK_LEGTH        EQU        0   
UND_STACK_LEGTH        EQU        0   

NoInt    EQU        0x80
NoFIQ    EQU        0x40

USR32Mode    EQU    0x10
SVC32Mode    EQU    0x13
SYS32Mode    EQU    0x1f
IRQ32Mode    EQU    0x12
FIQ32Mode    EQU    0x11

;    IMPORT __use_no_semihosting_swi
;    IMPORT  FIQ_Exception

;    IMPORT  __main
    IMPORT  SystemInit
    IMPORT    LowLevelInit
   
    EXPORT  bottom_of_heap  
    EXPORT  StackUsr
    EXPORT  Reset
    EXPORT __user_initial_stackheap
   
    PRESERVE8
    ;CODE32
    AREA    os,CODE,READONLY
    ARM
  ;      ENTRY

Reset
        LDR     PC, ResetAddr
        LDR     PC, UndefinedAddr
        LDR     PC, SWI_Addr
        LDR     PC, PrefetchAddr
        LDR     PC, DataAbortAddr
        DCD     0xb9205f80
        LDR     PC, [PC, #-0xff0]
        LDR     PC, FIQ_Addr

ResetAddr            DCD        ResetInit
UndefinedAddr        DCD        Undefined
SWI_Addr            DCD        SoftwareInterrupt
PrefetchAddr        DCD        PrefetchAbort
DataAbortAddr        DCD        DataAbort
Nouse                DCD        0
IRQ_Addr            DCD        0
FIQ_Addr            DCD        FIQ_Handler

Undefined
        B       Undefined

SoftwareInterrupt                           
        CMP     R0, #4
        LDRLO   PC, [PC, R0, LSL #2]
        MOVS    PC, LR

SwiFunction
        DCD        IRQDisable    ;0
        DCD        IRQEnable    ;1
        DCD        FIQDisable    ;2
        DCD        FIQEnable    ;3

IRQDisable
        MRS     R0, SPSR
        ORR     R0, R0, #NoInt
        MSR     SPSR_c, R0
        MOVS    PC, LR

IRQEnable
        MRS   R0, SPSR
        BIC   R0, R0, #NoInt
        MSR   SPSR_c, R0
        MOVS    PC, LR
        
FIQDisable
        MRS     R0, SPSR
        ORR     R0, R0, #NoFIQ
        MSR     SPSR_c, R0
        MOVS    PC, LR

FIQEnable
        MRS   R0, SPSR
        BIC   R0, R0, #NoFIQ
        MSR   SPSR_c, R0
        MOVS    PC, LR
      
PrefetchAbort
        B       PrefetchAbort

DataAbort
        B       DataAbort

FIQ_Handler
        STMFD   SP!, {R0-R3, LR}
;        BL      FIQ_Exception    ;先简单的注释掉这个,不管了,以后再搞
        LDMFD   SP!, {R0-R3, LR}
        SUBS    PC,  LR,  #4

InitStack   
        MOV     R0, LR
        MSR     CPSR_c, #0xd3        
        LDR     SP, StackSvc   
        MSR     CPSR_c, #0xd2
        LDR     SP, StackIrq
        MSR     CPSR_c, #0xd1
        LDR     SP, StackFiq
        MSR     CPSR_c, #0xd7
        LDR     SP, StackAbt
        MSR     CPSR_c, #0xdb
        LDR     SP, StackUnd
        MSR     CPSR_c, #0xdf
        LDR     SP, =StackUsr-512
        MOV     PC, R0 ;BX R0;  不能使用LR返回,LR可能已经被修改了,所以借由R0中保存的LR原值返回   

ResetInit
        BL        LowLevelInit        
        BL        InitStack    ;在这之后,堆栈指针已初始化,可以调用C函数

        STMFD   SP!, {R0-R3, LR}
        BL        SystemInit
        LDMFD   SP!, {R0-R3, LR}
        B        .   
  
;        BL      TargetResetInit                                      
;        B       __main


__user_initial_stackheap   
    LDR   r0,=bottom_of_heap   
;    LDR   r1,=StackUsr  
    MOV   pc,lr      ; BX LR;

StackSvc           DCD     SvcStackSpace + (SVC_STACK_LEGTH - 1)* 4   
StackIrq           DCD     IrqStackSpace + (IRQ_STACK_LEGTH - 1)* 4   
StackFiq           DCD     FiqStackSpace + (FIQ_STACK_LEGTH - 1)* 4   
StackAbt           DCD     AbtStackSpace + (ABT_STACK_LEGTH - 1)* 4   
StackUnd           DCD     UndtStackSpace + (UND_STACK_LEGTH - 1)* 4   
   
        AREA    MyStacks, DATA, NOINIT, ALIGN=2
SvcStackSpace      SPACE   SVC_STACK_LEGTH * 4  ;Stack spaces for Administration Mode 管理模式堆栈空间
IrqStackSpace      SPACE   IRQ_STACK_LEGTH * 4  ;Stack spaces for Interrupt ReQuest Mode 中断模式堆栈空间
FiqStackSpace      SPACE   FIQ_STACK_LEGTH * 4  ;Stack spaces for Fast Interrupt reQuest Mode 快速中断模式堆栈空间
AbtStackSpace      SPACE   ABT_STACK_LEGTH * 4  ;Stack spaces for Suspend Mode 中止义模式堆栈空间
UndtStackSpace     SPACE   UND_STACK_LEGTH * 4  ;Stack spaces for Undefined Mode 未定义模式堆栈


        AREA    Heap, DATA, NOINIT
bottom_of_heap    SPACE   1

        AREA    Stacks, DATA, NOINIT
StackUsr

    END


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;LowLevelInit.s 底层初始化,在初始化各模式堆栈指针前调用;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

INTMSK        EQU        0x4A000008
INTSUBMSK    EQU        0X4A00001C
WTCON        EQU        0x53000000

    EXPORT LowLevelInit

    AREA    init,CODE,READONLY
LowLevelInit
;1.关闭全部中断
    MOV R0,#0
    LDR    R1,=INTMSK   
    LDR    R2,=INTSUBMSK
    STR    R0,[R1]
    STR    R0,[R2]

;2.关闭看门狗
    LDR    R1,=WTCON   
    STR    R0,[R1]
   
;3.关闭MMU

;4.关闭I-Cache

;5.关闭D-Cache

    MOV     PC, LR ;BX R0;
  
    END   


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////SystemInit.c    在初始化完各模式堆栈之后,在bl  __main之前,初始化某些部件///////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "SystemInit.h"

extern void SystemInit(void)
{
    // 1.初始化时钟,建议第一次初始化在加载运行域之前做,这样速度会快一些
    ClockInit();
    // 2.关闭一些不用的外设时钟源,如果可以关闭不用外设的供电就也关闭。只需要在模块初始化中自己开启。
//    PowerOffPeripherals();
    // 3.初始化中断系统,目前暂时不实现

    LedInit();//希望通过眼观Led在不同MPLL频率设置下运行时的闪烁频率差异来初步验证MPLL设置的正确

#if    1
    while(1){
       Delay(10);
        LedOn();
        Delay(10);
        LedOff();
    }   
#endif        
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////clock.c    ///////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "clock.h"

extern void ClockInit(void)
{
#if        0  // 本来是想验证系统时钟设置的,结果发现代码直接跑出问题了,就先把时钟初始化这段屏蔽掉,缩小和排查问题的范围
    unsigned long temp;
    S3C_CLOCK -> LOCKTIME     = 0xFFFFFFFF;
    S3C_CLOCK -> MPLLCON    = MPLLCON_VAULE;
    S3C_CLOCK -> UPLLCON    = S3C_CLOCK -> UPLLCON;
    S3C_CLOCK -> CLKCON        = 0;// 关闭全部外设
    temp                     = S3C_CLOCK -> CLKSLOW;
    temp &= (~(3<<4));
    temp |= (1<<7);
    S3C_CLOCK -> CLKSLOW    = temp;
    S3C_CLOCK -> CLKDIVN    = 0x02;
//    S3C_CLOCK -> CAMDIVN    = 0x00;
//    Delay(10);
   
//    temp = temp;
    return ;   
#else
    unsigned long test = 2;

//    test = S3C_CLOCK->LOCKTIME;//    test = _LOCKTIME;
//    S3C_CLOCK -> LOCKTIME = 0;//_LOCKTIME = 0;
//    test = test;
#endif
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////s3c2440.c    ///////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "s3c2440.h"

extern void Delay(int t)
{
    volatile int i,j,k;

    for(k = 0; k < t; k ++){
        for(i = 0; i < 0x100; i ++){
            for(j = 0; j < 0x100; j ++);
        }
    }
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////gpio.c    ///////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "gpio.h"

// LED0 -  GPB5
// LED1 -  GPB6
// LED2 -  GPB8
// LED3 -  GPB10

extern void LedInit(void)
{
    unsigned long temp;

    S3C_CLOCK -> CLKCON        = (1<<13);// 开启gpio时钟
    temp = S3C_GPIO -> GPBCON;
    temp &= (~( (3<<10) | (3<<12) | (3<<16) | (3<<20) ));
    temp |= ( (1<<10) | (1<<12) | (1<<16) | (1<<20) );
    S3C_GPIO -> GPBCON        = temp;   
    S3C_GPIO -> GPBDAT        &= (~( (1<<5) | (1<<6) | (1<<8) | (1<<10) ));
    S3C_GPIO -> GPBDAT        |= ( (1<<5) | (1<<6) | (1<<8) | (1<<10) );
//    S3C_GPIO -> GPBUP   
}

extern void LedOn(void)
{
    S3C_GPIO -> GPBDAT        &= (~( (1<<5) | (1<<6) | (1<<8) | (1<<10) ));        
}

extern void LedOff(void)
{
    S3C_GPIO -> GPBDAT        |= ( (1<<5) | (1<<6) | (1<<8) | (1<<10) );
}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;分散加载脚本;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ROM_LOAD 0x40000000
{
    ROM_EXEC 0x40000000
    {
        startup.o (os, +First)
        *(InRoot$$Sections)
        * (+RO)
    }
   
    IRAM 0x40000800
    {
        startup.o (MyStacks)
        .ANY (+RW,+ZI)  ; * (+RO)                                                                                                      
    }

    HEAP +0 UNINIT
    {
        startup.o (Heap)
    }

    STACKS 0x40001000 UNINIT
    {
        startup.o (Stacks)
    }   
}

初始化脚本:我去掉了时钟和SDRAM的初始化,只是需要系统在调试仿真时能跳转到0x40000000.
FUNC void SetupForStart (void) {

// <o> Program Entry Point
PC = 0x40000000;//0x30000000
}


FUNC void Init (void) {

}


// Reset chip with watchdog, because nRST line is routed on hardware in a way
// that it can not be pulled low with ULINK

_WDWORD(0x40000000, 0xEAFFFFFE);        // Load RAM addr 0 with branch to itself
CPSR = 0x000000D3;                      // Disable interrupts
PC   = 0x40000000;  //0x30000000        // Position PC to start of RAM
_WDWORD(0x53000000, 0x00000021);        // Enable Watchdog
g, 0                                    // Wait for Watchdog to reset chip

Init();                                 // Initialize memory
LOAD FL2440.axf INCREMENTAL         // Download program
SetupForStart();                        // Setup for Running
//g, main  


编译通过,没有错误,警告也是写无关紧要。
调试仿真环境我对着看汇编代码。
        BL        LowLevelInit        
        BL      InitStack   

这些都是没问题的,但是在BL  SystemInit后,紧接着就  BL  ClockInit。
这就有问题了,BL  SystemInit,会把这条指令的下一条地址保存到LR中,当然我这里是B   .,而且程序在SystemInit中需要死循环,按功能来说,不保存BL  SystemInit下一条指令是可以的,
但按照ATPCS的规则,编译器是需要在进到SystemInit函数后需要保存一些必要的寄存器值到栈中。而且接下来我看到程序确实是没有按照应有的顺序来执行,跑飞了。
代码量不多,倒腾了很久,也没发现运行正常,有一次倒是发现编译器编译代码,在 BL SystemInit后有保存LR,但还是会跑飞。另外,多数情况下编译器编译代码没有保存LR的指令,
我也不知道该怎么搞了,只知道编译器编译C代码成汇编的代码有问题,如果是设置的问题,我也都试着调了下,在ADS1.2下也试过,也会跑飞。代码的问题的话,我按ATPCS规则来写
也只是在函数调用的第一层做啊,到SystemInit函数里面,就是编译器的事,出了问题,该怎么解决呢?











相关帖子

沙发
jplzl| | 2014-4-18 17:38 | 只看该作者
大环境都没说清楚,表述问题很差,这么多代码谁想看
程序跑飞?在SDRAM地址里?还是SDRAM初始化没成功?
堆栈没设置?

使用特权

评论回复
板凳
xiaoyuan_ly| | 2014-4-19 14:48 | 只看该作者
看代码太累了,还不如给个你启动后内存的分布图来的直接。

使用特权

评论回复
地板
lr2131|  楼主 | 2014-4-20 16:45 | 只看该作者
xiaoyuan_ly 发表于 2014-4-19 14:48
看代码太累了,还不如给个你启动后内存的分布图来的直接。

有分散加载脚本啦

使用特权

评论回复
5
lr2131|  楼主 | 2014-4-21 14:12 | 只看该作者
问题已解决,结贴

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

11

主题

203

帖子

0

粉丝