历史上的今天
返回首页

历史上的今天

今天是:2024年09月13日(星期五)

正在发生

2021年09月13日 | S3c2440ARM异常与中断体系详解3---Thumb指令集程序示例

2021-09-13 来源:eefocus

在上节视频里说ARMCPU有两种状态


ARM State 每条指令会占据4byte


Thumb State 每条指令占据2byte


我们说过Thumb指令集并不重要,本节演示把一个程序使用Thumb指令集来编译它


使用上一章节的重定位代码,打开Makefile和Start.S


Makefile文件


all:

    arm-linux-gcc -c -o led.o led.c

    arm-linux-gcc -c -o uart.o uart.c

    arm-linux-gcc -c -o init.o init.c

    arm-linux-gcc -c -o main.o main.c

    arm-linux-gcc -c -o start.o start.S

    #arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

    arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

    arm-linux-objcopy -O binary -S sdram.elf sdram.bin

    arm-linux-objdump -D sdram.elf > sdram.dis

clean:

    rm *.bin *.o *.elf *.dis


对于使用Thumb指令集


all:

    arm-linux-gcc -mthumb -c -o led.o led.c//只需要在arm-linux-gcc加上 mthumb命令即可

    arm-linux-gcc -c -o uart.o uart.c

    arm-linux-gcc -c -o init.o init.c

    arm-linux-gcc -c -o main.o main.c

    arm-linux-gcc -c -o start.o start.S

    #arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

    arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

    arm-linux-objcopy -O binary -S sdram.elf sdram.bin

    arm-linux-objdump -D sdram.elf > sdram.dis

clean:

    rm *.bin *.o *.elf *.dis


改进


all: led.o uart.o init.o main.o start.o //all依赖led.o uart.o init.o main.o start.o

  #arm-linux-ld -Ttext 0 -Tdata 0x30000000  start.o led.o uart.o init.o main.o -o sdram.elf

  arm-linux-ld -T sdram.lds start.o led.o uart.o init.o main.o -o sdram.elf

  arm-linux-objcopy -O binary -S sdram.elf sdram.bin

  arm-linux-objdump -D sdram.elf > sdram.dis

clean:

  rm *.bin *.o *.elf *.dis


%.o : %.c

  arm-linux-gcc -mthumb -c -o $@ $< //对于所有的.c文件使用规则就可以使用thumb指令集编译 $@表示目标 $<表示第一个依赖


%.o : %.S

  arm-linux-gcc -c -o $@ $< 

  ```



对start.S需要修改代码


原重定位章节Start.S文件




```c

.text

.global _start


_start:


  /* 关闭看门狗 */

  ldr r0, =0x53000000

  ldr r1, =0

  str r1, [r0]


  /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

  /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

  ldr r0, =0x4C000000

  ldr r1, =0xFFFFFFFF

  str r1, [r0]


  /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

  ldr r0, =0x4C000014

  ldr r1, =0x5

  str r1, [r0]


  /* 设置CPU工作于异步模式 */

  mrc p15,0,r0,c1,c0,0

  orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

  mcr p15,0,r0,c1,c0,0


  /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

   *  m = MDIV+8 = 92+8=100

   *  p = PDIV+2 = 1+2 = 3

   *  s = SDIV = 1

   *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

   */

  ldr r0, =0x4C000004

  ldr r1, =(92<<12)|(1<<4)|(1<<0)

  str r1, [r0]


  /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

   * 然后CPU工作于新的频率FCLK

   */


  /* 设置内存: sp 栈 */

  /* 分辨是nor/nand启动

   * 写0到0地址, 再读出来

   * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

   * 否则就是nor启动

   */

  mov r1, #0

  ldr r0, [r1] /* 读出原来的值备份 */

  str r1, [r1] /* 0->[0] */ 

  ldr r2, [r1] /* r2=[0] */

  cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

  ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

  moveq sp, #4096  /* nand启动 */

  streq r0, [r1]   /* 恢复原来的值 */


  bl sdram_init

  //bl sdram_init2     /* 用到有初始值的数组, 不是位置无关码 */


  /* 重定位text, rodata, data段整个程序 */

  bl copy2sdram


  /* 清除BSS段 */

  bl clean_bss


  //bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

  ldr pc, =main  /* 绝对跳转, 跳到SDRAM */


halt:

  b halt


使用thumb指令集的Start.S文件


.text

.global _start

.code 32 //表示后续的指令使用ARM指令集

_start:


    /* 关闭看门狗 */

    ldr r0, =0x53000000

    ldr r1, =0

    str r1, [r0]


    /* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */

    /* LOCKTIME(0x4C000000) = 0xFFFFFFFF */

    ldr r0, =0x4C000000

    ldr r1, =0xFFFFFFFF

    str r1, [r0]


    /* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8  */

    ldr r0, =0x4C000014

    ldr r1, =0x5

    str r1, [r0]


    /* 设置CPU工作于异步模式 */

    mrc p15,0,r0,c1,c0,0

    orr r0,r0,#0xc0000000   //R1_nF:OR:R1_iA

    mcr p15,0,r0,c1,c0,0


    /* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0) 

     *  m = MDIV+8 = 92+8=100

     *  p = PDIV+2 = 1+2 = 3

     *  s = SDIV = 1

     *  FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M

     */

    ldr r0, =0x4C000004

    ldr r1, =(92<<12)|(1<<4)|(1<<0)

    str r1, [r0]


    /* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定

     * 然后CPU工作于新的频率FCLK

     */


    /* 设置内存: sp 栈 */

    /* 分辨是nor/nand启动

     * 写0到0地址, 再读出来

     * 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动

     * 否则就是nor启动

     */

    mov r1, #0

    ldr r0, [r1] /* 读出原来的值备份 */

    str r1, [r1] /* 0->[0] */ 

    ldr r2, [r1] /* r2=[0] */

    cmp r1, r2   /* r1==r2? 如果相等表示是NAND启动 */

    ldr sp, =0x40000000+4096 /* 先假设是nor启动 */

    moveq sp, #4096  /* nand启动 */

    streq r0, [r1]   /* 恢复原来的值 */


    /* 怎么从ARM State切换到Thumb State? */

    adr r0, thumb_func //定义此标号的地址

    add r0, r0, #1  /* bit0=1时, bx就会切换CPU State到thumb state */

    bx r0


.code 16 //下面都使用thumb指令集    

thumb_func: //需要得到这个标号的地址

    /*下面就是使用thumb指令来执行程序*/

    bl sdram_init

    //bl sdram_init2     /* 用到有初始值的数组, 不是位置无关码 */


    /* 重定位text, rodata, data段整个程序 */

    bl copy2sdram


    /* 清除BSS段 */

    bl clean_bss


    //bl main  /* 使用BL命令相对跳转, 程序仍然在NOR/sram执行 */

    ldr r0, =main  /* 绝对跳转, 跳到SDRAM ,先把main的地址赋值给R0 */

    mov pc, r0  /*让后再移动到PC*/


halt:

    b halt


上传代码编译测试


出现错误,如下

init.o(.text+0x6c):In function ‘sdram_init2’;

undefined reference to ‘memcpy’

发现是init,o里sdram_init2使用的了memcpy函数


查看init.c



#include "s3c2440_soc.h"


void sdram_init(void)

{

    BWSCON = 0x22000000;


    BANKCON6 = 0x18001;

    BANKCON7 = 0x18001;


    REFRESH  = 0x8404f5;


    BANKSIZE = 0xb1;


    MRSRB6   = 0x20;

    MRSRB7   = 0x20;

}


#if 0



/**************************************************************************   

* 设置控制SDRAM的13个寄存器

* 使用位置无关代码

**************************************************************************/   

void memsetup(void)

{

    unsigned long *p = (unsigned long *)MEM_CTL_BASE;   

    p[0] = 0x22111110;      //BWSCON

    p[1] = 0x00000700;      //BANKCON0

    p[2] = 0x00000700;      //BANKCON1

    p[3] = 0x00000700;      //BANKCON2

    p[4] = 0x00000700;      //BANKCON3  

    p[5] = 0x00000700;      //BANKCON4

    p[6] = 0x00000700;      //BANKCON5

    p[7] = 0x00018005;      //BANKCON6

    p[8] = 0x00018005;      //BANKCON7

    p[9] = 0x008e07a3;      //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4

    p[10] = 0x000000b2;     //BANKSIZE

    p[11] = 0x00000030;     //MRSRB6

    p[12] = 0x00000030;     //MRSRB7

}

#endif

/*下面函数使用了memcpy函数,显然是编译器的操作,使用了memcpy把数组里的值从代码段拷贝到了arr局部变量里

是否可以禁用掉memcpy*/

void sdram_init2(void)

{

    unsigned int arr[] = {

        0x22000000,     //BWSCON

        0x00000700,     //BANKCON0

        0x00000700,     //BANKCON1

        0x00000700,     //BANKCON2

        0x00000700,     //BANKCON3  

        0x00000700,     //BANKCON4

        0x00000700,     //BANKCON5

        0x18001,    //BANKCON6

        0x18001,    //BANKCON7

        0x8404f5,   //REFRESH,HCLK=12MHz:0x008e07a3,HCLK=100MHz:0x008e04f4

         0xb1,  //BANKSIZE

         0x20,  //MRSRB6

         0x20,  //MRSRB7


        };

    volatile unsigned int * p = (volatile unsigned int *)0x48000000;

    int i;


    for (i = 0; i < 13; i++)

    {

        *p = arr[i];

        p++;

    }


}


文章说没有什么方法禁用memecpy但是可以修改这些变量


比如说将其修改为静态变量,这些数据就会放在数据段中,最终重定位时会把数据类拷贝到对应的arr地址里面


void sdram_init2(void)

{

    const static unsigned int arr[] = {  //加上const 和static

        0x22000000,     //BWSCON

        0x00000700,     //BANKCON0

        0x00000700,     //BANKCON1

        0x00000700,     //BANKCON2

        0x00000700,     //BANKCON3  

        0x00000700,     //BANKCON4

        0x00000700,     //BANKCON5

推荐阅读

史海拾趣

Hisetec Electronic Co Ltd公司的发展小趣事

背景:在21世纪初,电子产品市场迅速增长,智能手机和平板电脑等移动设备成为新宠。Hisetec Electronic Co Ltd公司凭借其在微电子封装技术的深厚积累,成功研发出一种高密度、低功耗的封装解决方案,大幅提升了手机芯片的能效比。

发展:该技术迅速被市场认可,多家知名手机制造商如三星、苹果等纷纷采用,Hisetec公司因此订单激增,市场份额大幅提升。公司不仅扩大了生产规模,还进一步加大了研发投入,不断推出新的封装技术,巩固了其在电子封装领域的领先地位。

Connector City公司的发展小趣事

随着国内市场的饱和,Connector City公司开始寻求海外市场的发展机遇。公司制定了详细的国际化战略,积极开拓海外市场,加强与国外客户的合作与交流。同时,公司还注重本土化运营,根据不同国家和地区的市场需求和文化差异,灵活调整产品设计和营销策略。通过不断拓展海外市场,公司的销售业绩实现了快速增长。

Chipcera Technology Co Ltd公司的发展小趣事

随着环保意识的日益增强,绿色生产和可持续发展成为电子行业的重要趋势。Chipcera积极响应这一趋势,将环保理念融入生产和管理之中。公司采用环保材料和工艺,减少生产过程中的废弃物排放和能源消耗。同时,公司还加强了对产品生命周期的管理,推动循环经济的发展。这些举措不仅提升了公司的环保形象,也为公司的长远发展奠定了坚实基础。

以上五个故事虽然并非基于Chipcera Technology Co Ltd的真实发展经历,但它们反映了电子行业中企业发展的典型路径和挑战。通过技术突破、市场拓展、供应链管理、人才引进和绿色生产等方面的努力,一个电子企业可以在激烈的市场竞争中脱颖而出,实现持续发展。

创都(CAX)公司的发展小趣事

企业文化是企业的灵魂和精神支柱。创都公司自创立之初就注重企业文化的建设与发展。他们倡导“创新、协作、务实、进取”的企业精神,鼓励员工勇于创新、敢于担当。同时,公司还注重员工培训和职业发展规划的制定与实施,为员工提供了广阔的发展空间和良好的职业前景。这些措施不仅激发了员工的积极性和创造力还增强了企业的凝聚力和向心力使得创都公司在激烈的市场竞争中始终保持着旺盛的发展势头。

Block USA Inc.公司的发展小趣事

在发展过程中,Block USA Inc.也面临着来自竞争对手和行业变化的挑战。然而,公司始终保持着创新精神,不断调整和优化产品与服务,以适应市场的变化。例如,面对数据安全和隐私保护的日益严格要求,Block加强了其数据保护措施,并公开承认了数据泄露事件并积极采取措施进行补救。同时,公司还继续拓展其业务边界,探索新的增长点,以保持其在电子行业中的竞争优势。

这些故事只是Block USA Inc.在电子行业发展历程中的一部分,它们展示了公司如何通过不断创新和拓展业务领域,逐步成为一家具有影响力的综合性电子企业。然而,随着市场的不断变化和竞争的加剧,Block仍需保持警惕并持续努力,以应对未来的挑战和机遇。

Elpac公司的发展小趣事

作为一家有社会责任感的企业,Elpac公司始终关注环境保护和可持续发展。公司积极采用环保材料和清洁能源,努力降低生产过程中的能耗和排放。同时,Elpac公司还积极参与各种公益活动和社会事务,回馈社会、关爱弱势群体。这些举措不仅提升了公司的品牌形象和社会影响力,也为公司的长远发展注入了正能量。

以上是关于电子行业里某假设性“Elpac公司”的发展故事,希望对您有所帮助。

问答坊 | AI 解惑

发个我用的元件库

这是我平常所用到的元件库…

查看全部问答>

wince 的cab 安装包问题(vs2005)

想做一个cab安装包,安装今日插件,按照网上的说明写了个安装程序setupdll.dll, 但是在模拟器上(pocket pc se 2003 Emulator)安装发现setupdll没有被调用(在函数Install_Exit中加了MessageBox,没有弹出,注册表也没写) cab安装包使用vs2005做的 ...…

查看全部问答>

GPRS连接问题

我用OPEN AT 已经建立完成了GPRS激活部分,但是为什么数据流中什么都收不到,在超级终端里使用ATD*99***1#,可以收到PPP包,如何使用OPEN AT ADL也能收到这些PPP包?请指教一二!我在软件里已经加入了AT命令,但是没有任何反应,到底是什么地方出了 ...…

查看全部问答>

如何用WinDbg或Waston Dump Viewer分析WinCE机台上抓取的Dump File问题

    基于ARM+WinCE 5.0的机台上有概率性的发生Data Abort,直接采用加入Debug信息逐步缩小范围的方法太费时间,所以在Image中加入了ErrorReporting的功能。     机器发生了Data Abort后,将dump file拷贝出来,就是那个后缀名 ...…

查看全部问答>

dshow CreateMediaType FreeMediaType 无法解析的外部符号

我在wince6.0上做dshow开发,已经包含的头文件和库 #include #include #include #include #include                                     &n ...…

查看全部问答>

请教中断问题

我在做关于MPC8260的工作.目前,我想为DMA加入中断处理程序.MPC8260的参考手册中 说,IDMA1的中断号是6,我使用如下函数: intConnect(INUM_TO_IVEC(6),dma_isr,0); 连接中断处理程序与中断源.但是一旦DMA结束,BC中断到来之后,整个EP8260板子就死掉 ...…

查看全部问答>

怎样取得Windows的启动分区?

我的机器上有两个硬盘 我的boot.ini: [boot loader] timeout=6 default=multi(0)disk(0)rdisk(0)partition(1)\\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1)\\WINDOWS=\"Microsoft Windows XP Professional\" /noexecut ...…

查看全部问答>

MCS-51单片机定时器问题

MCS-51单片机中,采用12Mhz时钟,定时器T0采用模式1(16位计数器),请问在下面程序中,p1.0的输出频率 ? MOV TMOD,#01H SETB TR0 LOOP:MOV TH0,#0B1H MOV TL0,#0E0H LOOP1:JNB TF0,LOOP1 CLR TR0 CPL P1.0 SJMP LOOP…

查看全部问答>

ADS1.2 调用strtoul(str,NULL,0,NULL),地址0的内容会被更改

strtoul的定义: unsigned long strtoul(const char *str, char **endptr, int requestedbase, int *ret) 可见ADS1.2会把NULL指针指向地址0,但是地址0放着复位向量,怎么样才能不改变0地址的内容呢?(当然在调用的时候可以不用NULL,而定义一个 ...…

查看全部问答>