DSP

C6000 DSP技术深度探索(3)-中断向量表

2019-07-13 10:01发布

DSP 作为一款处理器,它也支持中断处理,对于中断机制的引入,这里就不多说了,下面仍然以C6000系列DSP为例,探讨一下中断向量表,在前一篇文章中,
提到了汇编文件中存在一种特殊的文件,该文件通常命名为vectors.asm,这个文件就是中断向量表的定义,那么这个文件是从何而来,与DSP硬件之间的联系
在哪呢,这就要提到CPU的中断,在讨论中断之前,我先把一个中断向量表文件的内容列举如下:
==========================================vectors.asm==============================================
    .ref    _c_int00
.ref _my_isr        
  
.sect "vectors"


; tell assembler not to use 16-bit compact instructions
; or else the vectors will not reside properly in memory
; (applies to entire section in which it is contained)
.nocmp


RESET_RST:   
   mvkl .S2 _c_int00, B0
   mvkh .S2 _c_int00, B0
   B    .S2 B0
NOP
NOP
NOP
NOP
   NOP
NMI_RST:    
   NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


RESV1:
   NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


RESV2:
   NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT4:
b _my_isr
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT5:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
                   
INT6:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT7:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT8:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT9:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT10:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT11:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT12:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT13:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT14:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP


INT15:
NOP
NOP
NOP
NOP
NOP
NOP
NOP
NOP
==========================================vectors.asm end============================================
从上面可以看出,上面都是使用汇编语言实现的,看到汇编不要头疼,我们先放下这个不谈,而是先从中断说起,DSP在正常工作状态下,不可避免的腰被外部
事件(GPIO、串口、EDMA等等)打断,这些事件就是DSP的中断源头,产生这些事件后,DSP就要先记录当前的工作状态(保护现场),然后放下手头的工作,转
而去执行相应事件的处理程序(跳转到中断服务程序),对于C6000系列DSP,主要有四种类型的中断:
[1]复位中断
[2]不可屏蔽中断(NMI)
[3]可屏蔽中断(INT4-INT15)
[4]异常(仅C64x+内核支持)
对于前面三种中断,从上到下,优先级依次降低,其中复位中断的中断源就是DSP的reset复位信号,对于第四种是只有C64x+内核支持的异常,当异常使能时,
NMI输入是用作异常的。对于可屏蔽中断(INT4-INT15),从INT4到INT15,它们的中断优先级是依次降低的,因此INT4优先级最高,INT15优先级最低。由于任何
一个中断服务例程都可能是原子(atomic)类型的,因此这里的优先级并不是说高优先级中断可以抢占低优先级中断(中断嵌套),而是说中断的阻塞,即两个中断
同时到来时,高优先级中断会优先得到支持,低优先级中断将被阻塞不被处理,当然通过软件的方式,可以实现中断的嵌套,这是后话。
     有了中断,问题就来了,DSP怎么知道某一个事件来临时,执行哪一段代码呢,这就引出了中断服务表(Interrupt Service Table(IST)),DSP在收到中断后
会查取这个表,通过这个表跳到相应的中断服务程序,既然这是一个表,它肯定就需要按一个既定的格式定义,其格式如下:
===========================
中断向量表(IST)
===========================
   地址          中断取指包
===========================
xxxx 000h       RESET ISFP
xxxx 020h NMI ISFP
xxxx 040h Reserved
xxxx 060h Reserved
xxxx 080h INT4 ISFP
xxxx 0A0h INT5 ISFP
xxxx 0C0h INT6 ISFP
xxxx 0E0h INT7 ISFP
xxxx 100h INT8 ISFP
xxxx 120h INT9 ISFP
xxxx 140h INT10 ISFP
xxxx 160h INT11 ISFP
xxxx 180h INT12 ISFP
xxxx 1A0h INT13 ISFP
xxxx 1C0h INT14 ISFP
xxxx 1E0h INT15 ISFP
===========================
Program memory

为了理解上面的表,需要先引入一个概念-中断取指包(interrupt service fetch packet,ISTP),每个中断取指包在内存中固定的占用32字节空间,每个
取指包最多可包含14条指令(这里是指压缩指令,对于非压缩指令,只能存储8条),一个中断向量表就由16个这样的取指包依次连续排列而成,上表左侧即标示了
中断取指包之间的相对内存位置关系,后面就是各个地址需要存放的中断取指包,不同的地址固定的对应前面提到的中断,只是第三个和第四个为保留中断,有了这
个表,我们就可以大致的和上面的vectors.asm文件进行对比,可以看出vectors.asm中,.sect "vectors"之后,就是定义的16条中断取指包。
由于一个中断取指包只能存储8个32bit指令,即使是压缩指令也只能存储14条因此出现了两种情况,一种情况是,中断服务例程足够小,能够存储在一条中断
取指包中完成,另一种情况就是,我们知道,实际的中断服务程序通常远远大于这个限制,这时我们通常是在取指包中加入一条跳转指令,通过跳转指令跳转到实际
的中断服务例程,如上面vectors.asm中的中断4的的取值包,它就是通过 “b _my_isr”跳转到中断服务程序,这个中断服务程序通常是在C语言中定义的,它的
定义如下:
interrupt void my_isr()
{
asm(" NOP");
asm(" NOP");
asm(" NOP");
}
    上面除了中断4挂接了中断,我们还看到第一个复位中断的中断取指包如下:
RESET_RST:   
   mvkl .S2 _c_int00, B0
   mvkh .S2 _c_int00, B0
   B    .S2 B0
NOP
NOP
NOP
NOP
   NOP
这条指令包的作用与中断4指令包的作用一样,也是跳到一个中断服务函数,(但是为什么这条指令包不能直接使用 B _c_int00,我目前的想法是此时C语言的运行时
环境尚未建立,这一点需要进一步验证),_c_int00的作用就比较特殊,它就是用于建立C语言的运行时环境,建立完成后,该函数就会调用我们C语言中常见的main函数
,下一节,我们将对_c_int00进行详细的探讨。