历史上的今天
返回首页

历史上的今天

今天是:2024年09月03日(星期二)

正在发生

2021年09月03日 | 【S3C2440】第14课、异常与中断之学习笔记

2021-09-03 来源:eefocus

1、异常向量表


    /******下面这些就是异常向量表*****/

    .globl _start

    _start: b   reset

        ldr pc, _undefined_instruction

        ldr pc, _software_interrupt

        ldr pc, _prefetch_abort

        ldr pc, _data_abort

        ldr pc, _not_used

        ldr pc, _irq

        ldr pc, _fiq


    _undefined_instruction: .word undefined_instruction

    _software_interrupt:    .word software_interrupt

    _prefetch_abort:    .word prefetch_abort

    _data_abort:        .word data_abort

    _not_used:      .word not_used

    _irq:           .word irq

    _fiq:           .word fiq


手册异常向量表定义

在这里插入图片描述

2、程序


.text

.global _start


_start:

b reset  /*vector 0 一上电复位,是从0地址开始执行,跳到reset*/

b do_und /*vector 4 如果发生未定义指令异常,硬件就会在自动跳转0x04地址未定义指令异常处,执行do_und*/

/*假设一上电从0地址开始执行,reset,做一系列初始化之后

     *故意加入一条未定义指令

     */


do_und:


    /* 执行到这里之前:

* 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

* 2. SPSR_und保存有被中断模式的CPSR

* 3. CPSR中的M4-M0被设置为11011, 进入到und模式

* 4. 跳到0x4的地方执行程序 

*/

/*需要从新设置sp栈,指向某一块没有使用的地址*/  

/* sp_und未设置, 先设置它 */

ldr sp,=0x34000000  /*指向SDRAM的一块内存上*/

    /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

    /* 发生异常时,当前被中断的地址会保存在lr寄存器中 先减后存*/

    /* lr是异常处理完后的返回地址, 也要保存 */


stmdb sp!,{r0-r12,lr}  /*先减后存*/


/* 1、保存现场 */

/* 2、处理und异常 */

mrs r0,cpsr

ldr r1,=und_string


bl printException

/* 3、恢复现场 */

ldmia sp!,{r0-r12,pc}^  /* ^ 会把und_spsr的值恢复到cpsr里 */

und_string:

  .string "undefined instruction exception"


如何定义字符串,可以百度搜索 arm-linux-gcc 汇编 定义字符串

官方的说明文档

http://web.mit.edu/gnu/doc/html/as_7.html


.string "str"   /*汇编代码定义字符串*/


und_string:

  .string "undefined instruction exception"

reset:


/* 关闭看门狗 */

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]   /* 恢复原来的值 */

    /*初始化SDRAM*/

bl sdram_init

/*初始化UART0*/

bl uart0_init

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

bl copy2sdram


/*清除BSS段*/


bl clean_bss


bl print1

und_code:

.word 0xff123456  /*未定义指令*/


    bl print2

    

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

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


halt:

b halt


如何处理这个异常呢?


直接print打印一句话,新建一个exception.c文件


    #include "uart.h"


    void printException(unsigned int cpsr, char *str) //cpsr打印相应的寄存器,str打印一个字符串

    {

        puts("Exception! cpsr = ");\打印cpsr

        printHex(cpsr);//输出cpsr的值

        puts(" ");//输出空格

        puts(str);//输出str值

        puts("nr");//回车,换行

    }


我们打开之前编译过的程序的反汇编文件


里面一定包含了保存恢复


    30000084 :

    30000084:   e1a0c00d    mov ip, sp

    30000088:   e92dd800    stmdb   sp!, {fp, ip, lr, pc} //保存 d是减 b是存

    3000008c:   e24cb004    sub fp, ip, #4  ; 0x4

    30000090:   e24dd004    sub sp, sp, #4  ; 0x4

    30000094:   e50b0010    str r0, [fp, #-16]

    30000098:   e51b3010    ldr r3, [fp, #-16]

    3000009c:   e2433001    sub r3, r3, #1  ; 0x1

    300000a0:   e50b3010    str r3, [fp, #-16]

    300000a4:   e51b3010    ldr r3, [fp, #-16]

    300000a8:   e3730001    cmn r3, #1  ; 0x1

    300000ac:   0a000000    beq 300000b4

    300000b0:   eafffff8    b   30000098

    300000b4:   e89da808    ldmia   sp, {r3, fp, sp, pc}//恢复,先读后加


上传编译


修改makefile添加文件


objs := start.o led.o main.o uart.o init.o exception.o


all:$(objs)

arm-none-linux-gnueabi-ld -T sdram.lds $^ -o main.elf

arm-none-linux-gnueabi-objcopy -O binary -S main.elf main.bin

arm-none-linux-gnueabi-objdump -D main.elf > main.dis

%.o:%.c

arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $<

%.o:%.S

arm-none-linux-gnueabi-gcc -g -nostdlib -c -o $@ $<

clean:

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


编译成功烧写


没有输出我们想要的字符串


很多同学想学会如何调试程序


这里我们演示


    sdram:

        bl print1 //添加print1

        /* 故意加入一条未定义指令 */

    und_code:

        .word 0xdeadc0de  /* 未定义指令 */

        bl print2 //添加print2,实现这两个函数,来打印


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

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


    halt:

        b halt


实现print1 print2这两个打印函数,在uart.c这个文件里


    void print1(void)

    {

        puts("abcnr");

    }


    void print2(void)

    {

        puts("123nr");

    }


上传代码烧写,发现print1、print2并未执行成功


发现在start.S并未初始化 uart0_init(),删除main.c中的uart0_init()初始化函数


        ldr pc, =sdram

    sdram:

        bl uart0_init    /*串口初始化代码添加*/


        bl print1

        /* 故意加入一条未定义指令 */

    und_code:

        .word 0xff123456  /* 未定义指令 */

        bl print2


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

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


    halt:

        b halt


加上uart0_init,再次编译烧写


程序正常运行,print1 print2全部打印,表明未定义指令并未运行,难道这个地址是一个已经定义的地址


打开2440芯片手册,找到ARM指令集

在这里插入图片描述

发现竟然是SWI指令,CPU可以识别出来,他不是一条未定义指令


我们得找到一条CPU不能识别的指令,定义为0x03000000


        ldr pc, =sdram

    sdram:

        bl uart0_init


        bl print1

        /* 故意加入一条未定义指令 */

    und_code:

        .word 0x03000000  /* 未定义指令 */

        bl print2


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

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


    halt:

        b halt


编译烧写执行


打印了未定义指令异常CPSR地址,打印了字符串,最后执行main函数


.word 0xdeadcode /* 也是一条未定义指令 只要指令地址对不上上表就是未定义指令*/


我们查看下cpsr是否处于未定义模式


bit[4:0]表示CPU模式 11011,果然处于und模式


我们看看这个程序做了什么事情


    .text

    .global _start

/*一上电复位,从0地址开始执行

跳到   reset:

做了一系列初始化

当执行到0xdeadc0de这条指令时候,CPU根本就不知道这条指令什么意思

    und_code:

        .word 0xdeadc0de  /* 未定义指令 */

        bl print2

让后就发生未定义指令异常,他会把下一条指令的地址保存到异常模式的LR寄存器


        /* 执行到这里之前已经发生了很多事情

         * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

         * 2. SPSR_und保存有被中断模式的CPSR

         * 3. CPSR中的M4-M0被设置为11011, 进入到und模式

         * 4. 跳到0x4的地方执行程序 

         * 

         * 设置栈 sp是指und的地址

         * sp_und未设置, 先设置它

         *  /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

         * lr是异常处理完后的返回地址, 也要保存 */

         * 保存现场 */

         * 处理und异常 */

         * 恢复sp

         * cpu就会切换到之前的模式

         */

*/    

.text

.global _start


_start:

    b reset  /* vector 0 : reset */

    b do_und /* vector 4 : und */


    und_addr:

        .word do_und


    do_und:

        /* 执行到这里之前:

         * 1. lr_und保存有被中断模式中的下一条即将执行的指令的地址

         * 2. SPSR_und保存有被中断模式的CPSR

         * 3. CPSR中的M4-M0被设置为11011, 进入到und模式

         * 4. 跳到0x4的地方执行程序 

         */


        /* sp_und未设置, 先设置它 */

        ldr sp, =0x34000000


        /* 在und异常处理函数中有可能会修改r0-r12, 所以先保存 */

        /* lr是异常处理完后的返回地址, 也要保存 */

        stmdb sp!, {r0-r12, lr}  


        /* 保存现场 */

        /* 处理und异常 */

        mrs r0, cpsr

        ldr r1, =und_string

        bl printException


        /* 恢复现场 */

        ldmia sp!, {r0-r12, pc}^  /* ^会把spsr的值恢复到cpsr里 */

推荐阅读

史海拾趣

Elytone Electronics Co Ltd公司的发展小趣事

进入XXXX年代,随着电子技术的飞速发展,Elytone公司意识到技术创新是企业持续发展的关键。公司投入大量资金引进先进设备和研发人才,成功开发出一系列具有竞争力的电子产品。这些产品在市场上获得了良好的口碑,为公司的快速发展奠定了坚实基础。

协顺电子(Finecables)公司的发展小趣事

经过多年的发展,协顺电子已经成为中国电子连接器行业的领军企业之一。展望未来,公司将继续坚持“以顾客为中心”的经营理念,不断提升产品质量和技术水平;同时,公司也将积极探索新的业务领域和市场机会,推动公司的持续发展。此外,协顺电子还将加强与国际知名企业的合作与交流,共同推动电子行业的发展和进步。

请注意,以上故事框架仅供参考,具体的故事内容需要根据协顺电子(Finecables)公司的实际情况和发展历程进行创作和补充。

BELDEN公司的发展小趣事

在20世纪初,BELDEN公司在技术创新方面取得了显著突破。公司不仅将塑料绝缘材料应用于电线和电缆制造,还着眼于精密和高质量产品的需求,致力于高附加值的绝缘材料、电缆、防护和护套材料的生产。这些技术创新使得BELDEN的产品在性能和质量上都有了显著提升,进一步巩固了公司在市场中的地位。同时,公司还不断扩大产品线,增加了橡胶绝缘材料等多种新产品,满足了不同客户的需求。

FUJI公司的发展小趣事

随着市场的不断发展和竞争的加剧,BELDEN公司开始通过并购来扩大规模和提升竞争力。2004年7月,BELDEN公司与CDT公司合并,这次合并使得BELDEN成为了全球最大的通讯线缆和网络产品生产厂家之一。合并后的BELDEN不仅拥有了更丰富的产品线和更强大的技术实力,还进一步提升了在全球市场中的竞争地位。此后,BELDEN继续通过并购等方式不断扩大规模,逐步成为了电子行业的领军企业。

顺芯(Everest-semi)公司的发展小趣事

近年来,随着5G、物联网等技术的快速发展,电子行业面临着巨大的变革。顺芯公司及时调整战略方向,加大在5G通信芯片、物联网安全芯片等领域的研发力度。同时,公司还积极探索新的商业模式和市场机会,如与汽车制造商合作开发车载芯片等。这些举措使顺芯公司在行业变革中保持了竞争优势。

骅讯(Cmedia)公司的发展小趣事

随着技术的不断发展,骅讯公司进一步扩大了其业务范围,成功开发了PC主板AC97。这一成果是英特尔高清晰度音频应用的重要发展,标志着骅讯在音频技术领域的进一步突破。通过AC97的开发,骅讯进一步巩固了其在音频芯片设计领域的领先地位。

问答坊 | AI 解惑

MCGS组态软件设计及其应用

一、引言     过去工业控制计算机系统的软件功能都靠软件人员编程实现。工作量大,软件通用性差,且易产生错误。随着工业控制要求的不断提高,专门用于工业控制的组态软件应运而生,它是一套功能齐全的组态生成工具软件,通用性强,而 ...…

查看全部问答>

ARM c程序的问题

_irqHandler PROC    1. STMFD   sp!,{r0-r4,r12,lr}    2. mov     r4,#0x80000000  //中断控制寄存器首地址(假设的)    3. ldr     r0,[r4,#0] ...…

查看全部问答>

给论坛的建议

我希望论坛能够在下载扣金币方面可以放松点,比如每次只扣一个或者在某个贴上下载只扣若干个就好了,因为有些文件确实比较大,要下好几个压缩文件才能行的,而每下一个就扣好几,很多人都有些不舍得,毕竟金币有比较难得,特别是新手就更麻烦了,我 ...…

查看全部问答>

wince 桌面快捷方式

请问: wince中的文件夹有没有后缀名? 我想把一个名为NandFlash的文件夹,放到桌面快捷方式, 我在WINCE500\\PLATFORM\\SMDK2440\\FILES创建了一个NandFlash.LNK文件,里面写上22#\\windows\\NandFlash 我又在Project.bib 里面加上 NandFlash ...…

查看全部问答>

PCI设备识别不正常

首先我的程序在某些主板上是可以正常工作的(具体型号我也搞不懂),设置的是从设备,内部只有从设备状态机。没有接入奇偶检验,仲裁和热插拔。 问题是在一些主板上发现设置为从设备时无法找到设备,设置为主设备可以找到,但是通过软件读取配置信 ...…

查看全部问答>

0

居然要全部下完才能都打开?这个有点不厚道…

查看全部问答>

LM3S程序求教

//————————————————头文件————————————————————#include \"inc/hw_ints.h\"//硬件中断#include \"inc/hw_memmap.h\"#include \"inc/hw_types.h\"//硬件类型#include \"driverlib/gpio.h\"//GPIO#include \"dri ...…

查看全部问答>

中断究竟是个怎么回事?

今天听单片机老师讲课讲中断,说分了好几种,被他弄得一头雾水,还是没明白他说的中断都有什么,怎么配置,查了查2553手册,愣是没找到讲解终端的地方,球大神指点123!不胜感激。…

查看全部问答>

DCDC电源中的电流检测

文章介绍了7中电流检测的办法,可以作为电流检测的入门读物 …

查看全部问答>