TMS320C6455入门实践(二)——中断相关

本文主要介绍TMS320C6455的中断相关的内容,主要的的参考文档有:

  上面的第一个文档就是TMS320C6455的数据手册,是内容最全面的,但对各个外设都是粗略的介绍,详细的介绍需要从另外的专门的文档中找。在数据手册的2.8.2.2 Documentation Support中介绍了其它的参考文档,便于大家查阅。

中断控制器

  SPRU871的第7章对C6455的中断控制器有详细的介绍。以下是中断控制器的框图。

diagram

  我理解的中断控制器的主要功能就是将128个系统事件映射到CPU的12个中断输入上。
  事件标识:总共有124个从INTC外输入的系统事件,和四个事件标志寄存器(Event flag registers,, EVTFLAGx),每个事件都对应都和寄存器中的一个bit相对应。其中EVTFLAG0中的低4位没有和任何事件对应。这样每个事件就都有了对应的标识,与之配套的分别还有四个标识清除寄存器(Clear flag registers, EVTCLRx)和标识置位寄存器(Set flag registers, EVTSETx)。

evtconbine

  事件组合:采用“或”逻辑,将多个事件组合起来产生一个新的事件。如上图所示,EVT0~EVT3就是组合事件。这四个事件加上原有的124个事件一同送入中断选择器。在事件组合过程中,可以用EVTMASKx(Event Mask Register)屏蔽一些不关心的事件,然后在MEVTFLAGx(Masked Event Flag Register)中就可以看到最终的组合事件的标识。

intselect

  中断选择器:128个事件都可以映射到12个CPU中断输入中的任意一个,在INTMUXn (Interrupt Mux Registers) 中进行配置。总共有三个INTMUX寄存器,寄存器中总共有12个INTSEL字段,每个字段为7bit,字段值表示事件号。由此将12个中断控制器的中断输出和128个事件输入相对应。

excecomb

  异常组合:事件标识除了构成组合事件,还可以通过Exception combiner将不同的事件组合起来构成一个异常输出,送给CPU。和事件组合类似,异常组合也有两种寄存器EXPMASKx(Exception Mask Register)和MEXPFLAGx(Masked Exception Flag Register)。不同的是,这里是将124个事件都“或”起来组合成一个异常输出,当然要考虑EXPMASK的作用。默认情况下,所有事件都是被屏蔽的,需要用户对EXPMASK寄存器做修改才能让一些事件产生异常信号。在异常组合器这里被屏蔽的一些事件可以继续用作中断源,而不会相互影响。

  复位是最高优先级的,始终使能。不可屏蔽事件(NMIEVT)直接送入CPU的NMI中断。在没有使能异常(使能interrupt task register中的global exception enable字段)时,NMI输入是作为中断进行响应的,NMI信号直接作用于中断标识寄存器(IFR);而使能异常后,IFR中不再产生相应的NMI标识,而是在异常标识寄存器中产生标识。

idrop

  中断异常主要指CPU在中断还未响应结束时又收到新的中断,就像是“落下(Drop)”了一个中断。中断控制器中有相应的中断异常状态寄存器(INTXSTAT)、中断异常清除寄存器(INTXSTAT)和遗漏中断屏蔽寄存器(INTDMASK)。每次有这类异常产生就会产生编号96的外部事件送入中断控制器。值得注意的是,每次有中断产生时,应当及时清除事件标识,因为如果没有清除事件标识时又产生新的同样的事件,那么CPU是检测不到的,CPU只能检测到在CPU输入端落下的中断。

CPU中断

  SPRU732中的第5章和第6章分别介绍了CPU对中断和异常的处理。异常这部分我还没有仔细看,主要讲讲中断这部分;中断这部分很多也都讲得很细节,所以主要挑一些我看得懂的进行介绍ORZ。

  C6455有一个比较特别的地方,就是它的中断向量表的位置不是特定的。大多数处理器总是固定的中断向量表,一般中断向量表的第一个就是复位,程序也从这里开始执行。文档中都说在具体设备的手册中找默认的中断向量表,但是我一直都没有找到。

ist

  上图中的IST(Interrupt Service Table)就是类似中断向量表的一个东西。它是由一个个ISFP(Interrupt Service Fetch Packet)组成的。因为C6455每次取指可以取8条32bit的指令,所以这一次性取指的8条指令被称为一个Fetch Packet。如果一个中断服务函数能在8条指令执行完,那当然最好,但是如果执行不完就要像上面这样在这8条指令中插入一条跳转的指令,从而执行一些额外的指令。
  这里的跳转指令都有5个delay slot,就是在执行跳转指令后,需要再执行5条指令才会真正跳转。所以上图中的跳转指令后还有5条指令,这些指令都是会被执行的!!很多时候在跳转指令后跟一条“NOP 5”也是出于这个目的。上面的“B IRP”指令就是专门用于中断返回的指令,IRP指的是Interrupt Return Pointer Register,专门用于可屏蔽中断服务函数的返回;而与之类似的还有一个NRP,是专门用于不可屏蔽中断的服务函数的范围地址。
  前面说到它的中断向量表位置不固定,这是因为有一个Interrupt Service Table Pointer Register(ISTP),这里的ISTB字段存的是IST的基地址,用户可以在程序中修改这个基地址从而绑定新的中断向量表的位置。对于IST有一个基本的要求就是它的基地址要满足1k字节边界对齐,也就是地址的低10bit均为0。因为在ISTB字段只有22bit,作为地址的高22位。
  这里还有一个字段是HPEINT,Highest priority enabled interrupt,在没有中断产生时,这部分字段为0;而有中断产生时,这部分字段就是最高优先级的中断的中断号,用户可以用这个去手动调用中断服务函数。
  有一个一直困惑我很久的问题就是这个重新定位的IST中的响应复位的ISFP是什么样子的?答案是没有这部分ISFP。复位后,ISTP寄存器中的ISTB字段也恢复默认值,甚至都找不到IST了,自然没有这部分代码;所以我现在认为复位就是硬件完成的,没有相关的代码,用户自己创建的IST里面直接把复位那部分当作Reserve处理就可以。

CSL的使用

  CSL与中断控制器相关的库是单独编译的,函数也不多,在这里做一些零散的总结。
  凡是用到这一中断控制器相关的工程,都需要在链接脚本命令文件中添加“.csl_vect”这一代码段,这里存放的就是IST。可以在“_csl_intcIsrDispatch.asm”文件中看到定义。可以看到它对复位那部分代码就是以Reserve处理的。而且声明了“.align 1024”,以1k字节的边界对齐。
  将用户定义的IST和ISTP中的ISTB字段绑定是在CSL_intcInit()函数中实现的,其中调用的_CSL_intcIvpSet()是用汇编写的,写在“_csl_intcIntrEnDisRes.asm”文件中。
  既然有了IST,那么在中断发生之后肯定就是从IST开始执行,每个中断服务函数只能包含8条指令。这8条指令是用一个宏写的,代码如下;这里的_CSL_intcpush和_CSL_intcpop也是宏,就是保护现场用的。

CALLDISP .macro intr
    _CSL_intcpush a0
    mvkl __CSL_intcCpuIntrTable, a0
    mvkh __CSL_intcCpuIntrTable, a0
    ldw *++a0[intr + 1], a0
    nop 2
    stw a0, *-a0[intr + 1]  
    _CSL_intcpop a0
    bnop a0, 5  
    .endm 

  这个有点难理解,但结合_CSL_intcCpuIntrTable这个结构体就好理解了。这个结构体是用C写的,并且用C在“_csl_intcResource.c”中声明,在汇编中调用就在前面多了一个下划线。这个结构体的第一个成员是Uint32类型的,虽然变量名是currentVectId,但其实是用来存放函数首地址的。上面的汇编代码先用“mvkl”和“mvkh”拿到这个结构体的首地址,然后用“ldw”从结构体中找到对应的服务函数的地址。“ldw”的delay slot是4条指令,所以这个函数地址不会马上到a0,而a0会马上自增变为指向函数首地址的地址。这时再用“stw”把相应的函数的地址存到currentVectId中。到“bnop a0, 5”时,load完成,就跳转到服务函数处了。

typedef struct CSL_IntcVect {
    Uint32 currentVect
    void (*resv0)();
    void (*nmiIsr)();
    void (*resv2)();
    void (*resv3)();
    void (*isr4)();
    void (*isr5)();
    void (*isr6)();
    void (*isr7)();
    void (*isr8)();
    void (*isr9)();
    void (*isr10)();
    void (*isr11)();
    void (*isr12)();
    void (*isr13)();
    void (*isr14)();
    void (*isr15)();
} CSL_IntcVect;

  在CSL_intcInit()函数中,_CSL_intcCpuIntrTable的几个服务函数也都初始化了,可屏蔽中断的服务函数都是_CSL_intcDispatcher(),这个函数中为了获得中断号,就是通过相对地址的关系计算的,代码如下:

Uint32  intrId = (_CSL_intcCpuIntrTable.currentVectId - (Uint32)(&_CSL_intcCpuIntrTable) - 4)/4;

  然后这个_CSL_intcDispatcher()实际在调用中断服务函数时调用的是_CSL_intcEventHandlerRecord这个结构体数组中存放的中断服务函数。
  CSL_intcPlugEventHandler()则是把具体的中断服务函数存到_CSL_intcEventHandlerRecord中。
  CSL_intcOpen()会调用CSL_intcHookIsr(),把初始化时的_CSL_intcDispatcher()替换为复合事件的dispacher,就是在“_csl_intcCombEventDispatcher.c”文件中定义的四种函数。
  如果只是用CSL_intcInit()之后的配置,也就是用_CSL_intcDispatcher()作为服务函数,那么中断只能响应那种一对一的绑定;而如果用CSL_intcOpen()之后,就可以响应那种EVT0~EVT3的复合中断,一旦有中断产生,程序会依次检查一系列的中断标识,响应多种中断。

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小裘HUST

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值