龙芯开源社区

 找回密码
 注册新用户(newuser)
查看: 3136|回复: 11

问个关于中断的问题

[复制链接]
发表于 2007-2-28 10:07:48 | 显示全部楼层 |阅读模式
已经看了好多关于中断的资料,但还没有搞定中断的处理。要问一下大家了。
先把我目前的情况说一下:
1、只处理0x80000180中断。
2、拷贝中断处理程序实现了。
3、使用BREAK来测试中断。
4、运行BREAK已经可以中断,并且进入相应中断处理函数,并看到串口有输出。
5、退出中断,恢复现场。(这个有问题,无论我怎么样设置,中断还是不断地产生,好像关不了中断的样子,直到栈溢出,CPU运行其它指令才停止。)

相关源程序如下:

/*
保存所有现场寄存器,以便中断处理后可以返回。
蔡军生  2007/02/26
*/
LEAF(exception_handler)
        .set        noat
       
        /* 取得栈空间,并按8字节对齐.  */       
        subu        k0, sp, 1024
        srl                k0, 3
        sll                k0, 3
       
        /* 保存所有现场寄存器 */
        STORE        AT, AST * RSIZE(k0)
        STORE        v0, V0 * RSIZE(k0)
        STORE        v1, V1 * RSIZE(k0)
        STORE        a0, A0 * RSIZE(k0)
        STORE        a1, A1 * RSIZE(k0)
        STORE        a2, A2 * RSIZE(k0)
        STORE        a3, A3 * RSIZE(k0)
        STORE        t0, T0 * RSIZE(k0)
        STORE        t1, T1 * RSIZE(k0)
        STORE        t2, T2 * RSIZE(k0)
        STORE        t3, T3 * RSIZE(k0)
        STORE        t4, T4 * RSIZE(k0)
        STORE        t5, T5 * RSIZE(k0)
        STORE        t6, T6 * RSIZE(k0)
        STORE        t7, T7 * RSIZE(k0)
        STORE        s0, S0 * RSIZE(k0)
        STORE        s1, S1 * RSIZE(k0)
        STORE        s2, S2 * RSIZE(k0)
        STORE        s3, S3 * RSIZE(k0)
        STORE        s4, S4 * RSIZE(k0)
        STORE        s5, S5 * RSIZE(k0)
        STORE        s6, S6 * RSIZE(k0)
        STORE        s7, S7 * RSIZE(k0)
        STORE        t8, T8 * RSIZE(k0)
        STORE        t9, T9 * RSIZE(k0)
        STORE        k1, K1 * RSIZE(k0)
        STORE        gp, GP * RSIZE(k0)
        STORE        sp, SP * RSIZE(k0)
        STORE        s8, S8 * RSIZE(k0)
        STORE        ra, RA * RSIZE(k0)

        .set        at

        mfhi        v0
        mflo        v1
        STORE        v0, MULHI * RSIZE(k0)
        STORE        v1, MULLO * RSIZE(k0)

        mfc0        a0, COP_0_STATUS_REG
        mfc0        v1, COP_0_CAUSE_REG
        STORE        a0, SR * RSIZE(k0)
        MFC0        v0, COP_0_BAD_VADDR
        STORE        v1, CAUSE * RSIZE(k0)
        MFC0        v1, COP_0_EXC_PC
        STORE        v0, BADVADDR * RSIZE(k0)
        STORE        v1, PC * RSIZE(k0)

        MFC0        v0, COP_0_TLB_CONTEXT
        MFC0        v1, COP_0_TLB_XCONTEXT
        STORE        v0, CONTX * RSIZE(k0)
        STORE        v1, XCONTX * RSIZE(k0)
        MFC0        v0, COP_0_TLB_HI
        MFC0        v1, COP_0_TLB_LO0
        STORE        v0, ENTHI * RSIZE(k0)
        MFC0        v0, COP_0_TLB_LO1
        STORE        v1, ENTLO0 * RSIZE(k0)
        STORE        v0, ENTLO1 * RSIZE(k0)

        MFC0        t0, COP_0_WATCH_LO
        MFC0        t1, COP_0_WATCH_HI
        STORE        t0, WATCHLO * RSIZE(k0)
        MFC0        t0, COP_0_PRID
        STORE        t1, WATCHHI * RSIZE(k0)
        MTC0        zero, COP_0_WATCH_LO
        MTC0        zero, COP_0_WATCH_HI
        srl        t1, t0, 8
        bne        t1, MIPS_RM7000, 1f
        STORE        t0, PRID * RSIZE(k0)

        mfc0        t0, COP_0_WATCH_1
        mfc0        t1, COP_0_WATCH_2
        STORE        t0, WATCH1 * RSIZE(k0)
        mfc0        t0, COP_0_WATCH_M
        STORE        t1, WATCH2 * RSIZE(k0)
        mfc0        t1, COP_0_PC_COUNT
        STORE        t0, WATCHM * RSIZE(k0)
        mfc0        t0, COP_0_PC_CTRL
        STORE        t1, PCOUNT * RSIZE(k0)
        mfc0        t1, COP_0_ICR
        STORE        t0, PCTRL * RSIZE(k0)
        STORE        t1, ICR * RSIZE(k0)

1:
        addu        sp, k0, -64                /* Get a new stack */

        and     t0, a0, ~(SR_COP_1_BIT | SR_EXL | SR_KSU_MASK | SR_INT_ENAB)
        mtc0        t0, COP_0_STATUS_REG
       
        nop
        nop
        nop
        nop
       
        nop
        nop
        nop
        nop
       
       
        /* 跳到C函数里运行。 */
        la                gp, _gp
       
        jal                InterruptHandler
        move        a0, k0

        /* 没有返回 */
END(exception_handler)

/*
中断处理完成,返回中断位置。

蔡军生  2007/02/26
*/
LEAF(Exception_Finish)
        .set        noreorder
       
        move        k0, a0

        li        v0, ~SR_EXL                /* Precaution */
        mtc0        v0, COP_0_STATUS_REG
               
        LOAD        t0, WATCHLO * RSIZE(k0)
        LOAD        t1, WATCHHI * RSIZE(k0)
        MTC0        t0, COP_0_WATCH_LO
        mfc0        t0, COP_0_PRID
        MTC0        t1, COP_0_WATCH_HI
        srl        t1, t0, 8
        bne        t1, MIPS_RM7000, 1f
        LOAD        t0, WATCH1 * RSIZE(k0)
       
        /* RM7000 specific */
        LOAD        t1, WATCH2 * RSIZE(k0)
        mtc0        t0, COP_0_WATCH_1
        LOAD        t0, WATCHM * RSIZE(k0)
        mtc0        t1, COP_0_WATCH_2
        LOAD        t1, PCOUNT * RSIZE(k0)
        mtc0        t0, COP_0_WATCH_M
        LOAD        t0, PCTRL * RSIZE(k0)
        mtc0        t1, COP_0_PC_COUNT
        LOAD        t1, ICR * RSIZE(k0)
        mtc0        t0, COP_0_PC_CTRL
        mtc0        t1, COP_0_ICR

1:
        LOAD        v0, PC * RSIZE(k0)
        LOAD        v1, CAUSE * RSIZE(k0)
       
        addu        v0, 4
        MTC0        v0, COP_0_EXC_PC
               
        LOAD        v0, SR * RSIZE(k0)
        MTC0        v1, COP_0_CAUSE_REG       
       
        and                v0, zero
        or                v0, SR_EXL                /* Keep Exeption level status */
        nop
        MTC0        v0, COP_0_STATUS_REG

        LOAD        v0, MULHI * RSIZE(k0)
        LOAD        v1, MULLO * RSIZE(k0)
        mthi        v0
        mtlo        v1

        .set        noat

        LOAD        AT, AST * RSIZE(k0)
        LOAD        v0, V0 * RSIZE(k0)
        LOAD        v1, V1 * RSIZE(k0)
        LOAD        a0, A0 * RSIZE(k0)
        LOAD        a1, A1 * RSIZE(k0)
        LOAD        a2, A2 * RSIZE(k0)
        LOAD        a3, A3 * RSIZE(k0)
        LOAD        t0, T0 * RSIZE(k0)
        LOAD        t1, T1 * RSIZE(k0)
        LOAD        t2, T2 * RSIZE(k0)
        LOAD        t3, T3 * RSIZE(k0)
        LOAD        t4, T4 * RSIZE(k0)
        LOAD        t5, T5 * RSIZE(k0)
        LOAD        t6, T6 * RSIZE(k0)
        LOAD        t7, T7 * RSIZE(k0)
        LOAD        s0, S0 * RSIZE(k0)
        LOAD        s1, S1 * RSIZE(k0)
        LOAD        s2, S2 * RSIZE(k0)
        LOAD        s3, S3 * RSIZE(k0)
        LOAD        s4, S4 * RSIZE(k0)
        LOAD        s5, S5 * RSIZE(k0)
        LOAD        s6, S6 * RSIZE(k0)
        LOAD        s7, S7 * RSIZE(k0)
        LOAD        t8, T8 * RSIZE(k0)
        LOAD        t9, T9 * RSIZE(k0)
        LOAD        k1, K1 * RSIZE(k0)
        LOAD        gp, GP * RSIZE(k0)
        LOAD        sp, SP * RSIZE(k0)
        LOAD        s8, S8 * RSIZE(k0)
        LOAD        ra, RA * RSIZE(k0)
        LOAD        k0, K0 * RSIZE(k0)

       
//        eret
        nop
loop:
        j loop       
        nop
       
        .set        at
        .set        reorder
END(Exception_Finish)

[ 本帖最后由 caimouse 于 2007-2-28 10:11 AM 编辑 ]

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册新用户(newuser)

x
发表于 2007-2-28 21:49:02 | 显示全部楼层
break?
eret前有没把EPC指向下一条指令? 延迟槽还要特殊处理
发表于 2007-2-28 23:18:59 | 显示全部楼层
原帖由 cray 于 2007-2-28 09:49 PM 发表
break?
eret前有没把EPC指向下一条指令? 延迟槽还要特殊处理


对,必须手工调整EPC,不然又回到break指令了
 楼主| 发表于 2007-3-1 10:09:02 | 显示全部楼层
原帖由 foxsen 于 2007-2-28 11:18 PM 发表


对,必须手工调整EPC,不然又回到break指令了

有试过,上面的代码,就硬性地添加了4字节。
addu        v0, 4
        MTC0        v0, COP_0_EXC_PC

好像在延迟槽里,还需要添加8个字节。
我都试过了,还是不断地中断。看来我得换一个SYSCALL来测试中断了。
 楼主| 发表于 2007-3-1 21:43:40 | 显示全部楼层

解决中断的问题

目前改短了中断运行代码,并改成简单的测试代码,已经可以使用中断了。
修改中断代码如下:
LEAF(exception_handler)
        .set        noat
       
        lui        v0,0xbfd0
        ori        v0,v0,0x3f8
busy:       
        lbu        v1,5(v0)
        andi        v1,v1,0x20
        beqz        v1,busy
        nop
        ori a0,zero,'A'
        sb        a0,0(v0)
        nop
       
        //这里固定添加8.
       
       
        mfc0        v1, COP_0_EXC_PC       
        addu        v1, 8
        mtc0        v1, COP_0_EXC_PC
       
        eret


运行的测试函数为:
//测试中断。
void CCnos::TestBreak(void)
{
        //
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");
       
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");

        asm volatile("break;");

        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");

        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");
        asm volatile("nop;");

        g_CNOS.DebugOut(L"\r\nBreak End\r\n");
}

已经测试通过。
发表于 2007-3-2 09:11:16 | 显示全部楼层
如果能确定触发中断的是break指令 把它改成nop就行了。在延迟槽时 不一定是加8, 还要看是否转移成功
 楼主| 发表于 2007-3-2 10:13:38 | 显示全部楼层
原帖由 cray 于 2007-3-2 09:11 AM 发表
如果能确定触发中断的是break指令 把它改成nop就行了。在延迟槽时 不一定是加8, 还要看是否转移成功

按手册上说,当CAUSE的BD位为1时,就在延迟槽,为0时,就不在。
现在每次都发现为0,按手册里的说法应是添加4的。但实际添加4是不运行的,需要添加8才能运行通过。这样来,就运行到BREAK后面的第二条指令了。不知道BREAK后面紧跟的指令是怎么样运行?在BREAK发生时是否已经运行?如果没有运行,还是需要使用什么技术来运行后面那条指令?
 楼主| 发表于 2007-3-2 18:27:12 | 显示全部楼层
原帖由 cray 于 2007-3-2 09:11 AM 发表
如果能确定触发中断的是break指令 把它改成nop就行了。在延迟槽时 不一定是加8, 还要看是否转移成功

在延迟槽时,需要怎么样处理?具体一些。
 楼主| 发表于 2007-3-2 21:29:18 | 显示全部楼层
今晚又测试了一下,发现不仅是异常指令会改变cp0的EPC寄存器值,而运行其它指令也会改变EPC的值,所以导致结果怪怪的。不知道为什么非异常指令也会改变EPC值?
现在到中断时,就首先把EPC值保存下来,然后再运行其它指令,就不会影响EPC的值了。
当中断恢复时,也需要最后一条指令才把EPC写回去,否则,又出错,回不到原来位置了,因为其它指令又改变EPC的值。

经过这样修改后,只用加4字节,就跳到下一条指令执行了。
修改如下:
LEAF(exception_handler)
        .set        noat
        .set        noreorder       
       
        //先保存返回指令地址。
        mfc0        k1, COP_0_EXC_PC
       
        /* 取得栈空间,并按8字节对齐.  */       
        subu        k0, sp, 1024
        srl                k0, 3
        sll                k0, 3

        //保存所有寄存器。       
//        addiu        k1,4
        sw                k1,0(k0)
       
        sw                ra,4(k0)
        sw                sp,8(k0)
        sw                a0,12(k0)
        sw                a1,16(k0)


        addu        sp, k0, -64       
       
/* 跳到C函数里运行。 */
//        la                gp, _gp
       
        jal                InterruptHandler
        move        a0, k0

返回修改如下:
LEAF(Exception_Finish)
        .set        noreorder
                       
        lw                ra,4(k0)
        lw                sp,8(k0)
        lw                a0,12(k0)
        lw                a1,16(k0)
       
        lw                k1,0(k0)
        addiu        k1,4
        mtc0        k1, COP_0_EXC_PC
        nop
               
        eret
        nop
发表于 2007-3-7 18:06:30 | 显示全部楼层
看了一下,EPC只有在以下两种情况才会变。
1. 发生例外并且SR_EXL为0时;
2. mtc0写它时
你确定不会有其它的例外?

当例外发生在延迟槽时,EPC指向转移指令。这时发生例外的指令并没有执行,由于转移指令不会修改寄存器,
例外处理函数可以得到完整的运行环境(可以对这条转移指令进行译码,分析出指令类型以及它的操作数)。

如果你允许break放在延迟槽,而且不愿意把它改成nop,就只能用软件模拟分析转移的目标地址 再存入EPC来eret。

本版积分规则

Archiver|手机版|小黑屋|Lemote Inc.

GMT+8, 2021-1-24 20:34 , Processed in 0.157092 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表