第十四课(3)Thumb指令集程序示例

1、修改原先的代码

原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指令集的参数:

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

改进Makefile文件:

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:

.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  /* 为什么加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

注意:thunb指令不能直接
ldr pc, =main

2、编译后的使用了memcpy出错的解决方法

上传代码编译测试

出现错误,如下
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;
}

/*下面函数使用了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++;
    }
}

内部使用memcpy将数据段的数据复制到栈上,因此我们将其修改为静态变量,这些数据就会放在数据段中,最终重定位时会把数据类拷贝到对应的arr地址里面去。
还有一种解决办法是我们自己实现memcpy函数。

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
        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++;
    }

}

查看文件大小可以看出原先的bin文件有2K左右,用thumb编译的文件1.4K.

查看反汇编代码:

sdram.elf:     file format elf32-littlearm

Disassembly of section .text:

/*前面这些ARM指令还是占用4个字节*/
30000000 <_start>:
30000000:   e3a00453    mov r0, #1392508928 ; 0x53000000
30000004:   e3a01000    mov r1, #0  ; 0x0
30000008:   e5801000    str r1, [r0]
3000000c:   e3a00313    mov r0, #1275068416 ; 0x4c000000
30000010:   e3e01000    mvn r1, #0  ; 0x0
30000014:   e5801000    str r1, [r0]
30000018:   e59f005c    ldr r0, [pc, #92]   ; 3000007c <.text+0x7c>
3000001c:   e3a01005    mov r1, #5  ; 0x5
30000020:   e5801000    str r1, [r0]
30000024:   ee110f10    mrc 15, 0, r0, cr1, cr0, {0}
30000028:   e3800103    orr r0, r0, #-1073741824    ; 0xc0000000
3000002c:   ee010f10    mcr 15, 0, r0, cr1, cr0, {0}
30000030:   e59f0048    ldr r0, [pc, #72]   ; 30000080 <.text+0x80>
30000034:   e59f1048    ldr r1, [pc, #72]   ; 30000084 <.text+0x84>
30000038:   e5801000    str r1, [r0]
3000003c:   e3a01000    mov r1, #0  ; 0x0
30000040:   e5910000    ldr r0, [r1]
30000044:   e5811000    str r1, [r1]
30000048:   e5912000    ldr r2, [r1]
3000004c:   e1510002    cmp r1, r2
30000050:   e59fd030    ldr sp, [pc, #48]   ; 30000088 <.text+0x88>
30000054:   03a0da01    moveq   sp, #4096   ; 0x1000
30000058:   05810000    streq   r0, [r1]
3000005c:   e28f0004    add r0, pc, #4  ; 0x4
30000060:   e2800001    add r0, r0, #1  ; 0x1
30000064:   e12fff10    bx  r0

30000068 <thumb_func>:
30000068:   f94ef000    bl  30000308 <sdram_init>
3000006c:   f9fef000    bl  3000046c <copy2sdram>
30000070:   fa24f000    bl  300004bc <clean_bss>
/**下面的thumb指令占据2个字节**/
30000074:   4805        ldr r0, [pc, #20]   (3000008c <.text+0x8c>)
30000076:   4687        mov pc, r0

30000078 <halt>:
30000078:   e7fe        b   30000078 <halt>
3000007a:   0000        lsl r0, r0, #0
3000007c:   0014        lsl r4, r2, #0
3000007e:   4c00        ldr r4, [pc, #0]    (30000080 <.text+0x80>)
30000080:   0004        lsl r4, r0, #0
30000082:   4c00        ldr r4, [pc, #0]    (30000084 <.text+0x84>)
30000084:   c011        stmia   r0!,{r0, r4}
30000086:   0005        lsl r5, r0, #0
30000088:   1000        asr r0, r0, #0
3000008a:   4000        and r0, r0
3000008c:   04fd        lsl r5, r7, #19
3000008e:   3000        add r0, #0

如果你的flash很小的话可以考虑使用Thumb指令集

烧写进去看是否可以运行

测试结果没有任何问题

Thumb指令集后面没有任何作用,只是简单作为介绍

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CSDN IT狂飙上传的代码均可运行,功能ok的情况下才上传的,直接替换数据即可使用,小白也能轻松上手 【资源说明】 基于MATLAB实现的有限差分法实验报告用MATLAB中的有限差分法计算槽内电位;对比解析法和数值法的异同点;选取一点,绘制收敛曲线;总的三维电位图+使用说明文档 1、代码压缩包内容 主函数:main.m; 调用函数:其他m文件;无需运行 运行结果效果图; 2、代码运行版本 Matlab 2020b;若运行有误,根据提示GPT修改;若不会,私信博主(问题描述要详细); 3、运行操作步骤 步骤一:将所有文件放到Matlab的当前文件夹中; 步骤二:双击打开main.m文件; 步骤三:点击运行,等程序运行完得到结果; 4、仿真咨询 如需其他服务,可后台私信博主; 4.1 期刊或参考文献复现 4.2 Matlab程序定制 4.3 科研合作 功率谱估计: 故障诊断分析: 雷达通信:雷达LFM、MIMO、成像、定位、干扰、检测、信号分析、脉冲压缩 滤波估计:SOC估计 目标定位:WSN定位、滤波跟踪、目标定位 生物电信号:肌电信号EMG、脑电信号EEG、心电信号ECG 通信系统:DOA估计、编码译码、变分模态分解、管道泄漏、滤波器、数字信号处理+传输+分析+去噪、数字信号调制、误码率、信号估计、DTMF、信号检测识别融合、LEACH协议、信号检测、水声通信 5、欢迎下载,沟通交流,互相学习,共同进步!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值