分支到 Microblaze CPU 上的中断处理程序,汇编语言

发布于 2024-12-01 20:00:06 字数 4471 浏览 0 评论 0原文

我对汇编语言和 microblaze cpu 非常陌生,并且在中断处理工作方面遇到问题。

我被迫编写自己的启动和初始化例程。 (通常包含在 crt0 中的东西)我想我在分支到指定地址的中断处理程序时做错了。在文档中据说,从代码地址 0x10 分支到中断处理程序,但是在我的测试程序中它不起作用。

<一href="http://www.google.de/url?q=http://www.xilinx.com/support/documentation/sw_manuals/mb_ref_guide.p df&sa=U&ei=gb9YTrjeJsnwsga5x6XcCg&ved=0CBcQFjAD&usg=AFQjCNGxQYRu8WZdrbEuKhsAAGMpR-rzcQ" rel="nofollow">在这里您可以找到 microblaze 文档。我指的是p。 102(中断和异常处理)

在这里您可以看到“my_crt0_intc.asm”的代码,

bri _start
nop
bri _exception_handler
nop
bri _interrupt_handler
nop
bri _hw_exception_handler
nop

/* Starting Point */
    .global _start
_start:     
    brlid   r15, _init_routine
    nop

/* Exception Handler *
    .global _exception_handler
_exception_handler:
/**/

/* Interrupt Handler */
    .global _interrupt_handler
_interrupt_handler:

    /* set led 0010 */
    ori r20, r20, 0x00000002
    swi r20, r0, 0x81400000

    rtid    r14, 8
    nop

/* HW Exception Handler *
    .global _hw_exception_handler
_hw_exception_handler:
/**/

/* Init Routine */
    .global _init_routine
_init_routine:
    /*** Initialize Stack Pointer ***/
    addi    r1, r0, 0x00004000
    /*** ***/

    /*** Initialize Interrupts ***/
    /** GPIO **/
    /* enable interrupts in GIE */
    addi    r19, r0, 0x80000000
    swi r19, r0, 0x8146011C

    /* enable interrupts in channel 1 (and 2, not) in IER */
    addi    r19, r0, 0x00000003
    swi r19, r0, 0x81460128

    /** INTC **/
    /* enable HW interrupts in INTC */
    addi    r19, r0, 0x00000003
    swi r19, r0, 0x8180001C

    /* enable interrupts in INTC IER */
    addi    r19, r0, 0xffffffff
    swi r19, r0, 0x81800008

    /** CPU, enable interrupts in MSR **/
    msrset  r19, 0x00000002
    /*** ***/

    /* Initialize Constants */
    /* r11 = word size, for increment and decrement stack pointer */
    /* addi r11, r0, 4 */

    /*** call main function ***/
    brlid   r15, main
    nop
    /*** ***/

    /*** halting loop ***/
_halting:
    bri _halting
    /*** ***/

    /* Return */
    rtsd    r15, 8
    nop

我的测试程序“test_interrupt_cpu_intc_gpio.asm”旨在通过地址0x81400000处的LED发出中断信号,

/* Main */
    .global main
main:
    addi    r20, r0, 0x0
_loop:

    /* set/unset alive led 0001 */
    andi    r21, r20, 0x00000001
    bnei    r21, _unset_alive
_set_alive:

    ori r20, r20, 0x1
    swi r20, r0, 0x81400000
    bri _no_alive

_unset_alive:

    andi    r20, r20, 0xfffffffe 
    swi r20, r0, 0x81400000
_no_alive:

    /* if gpio isr is set, set led 0100 */
    lwi r21, r0, 0x81460120
    beqi    r21, _unset_gpio
_set_gpio:
    ori r20, r20, 0x4
    swi r20, r0, 0x81400000
    bri _noset_gpio
_unset_gpio:
    andi    r20, r20, 0xfffffffb
    swi r20, r0, 0x81400000
_noset_gpio:

    /* if intc isr is set, set led 1000 */
    lwi r21, r0, 0x81800000
    beqi    r21, _unset_intc
_set_intc:
    ori r20, r20, 0x8
    swi r20, r0, 0x81400000
    bri _noset_intc
_unset_intc:
    andi    r20, r20, 0xfffffff7
    swi r20, r0, 0x81400000
_noset_intc:

    /* begin time loop */
    addi    r21, r0, 0x004af080
_loop_time:
    addi    r21, r21, -1
    bnei    r21, _loop_time
    /* end time loop*/

    bri _loop
    /* return 0*/
    addi    r3, r0, 0
    rtsd    r15, 8
    nop

错误症状是:如果我没有在MSR,LED 0001 闪烁,LED 1000 和如果按下相应的按钮触发中断,0100 就会被激活。然而,在这种情况下,CPU 当然不会处理中断,也不会分支到中断处理程序例程。

但是:如果我在 MSR 中启用中断以启用中断处理,则 led 0001 在开始时会闪烁。触发中断后,led 0001 被永久设置(或者如果中断发生时 led 0001 已取消设置,则取消设置)。 led 1000 和 0100 保持不活动状态,这看起来像是 cpu 停止工作。

我使用 mb-gcc 工具编译代码如下:

mb-as test_interrupt_cpu_intc_gpio.o -o test_interrupt_cpu_intc_gpio.o
mb-as my_crt0_intc.asm -o my_crt0_intc.o

mb-ld my_crt0_intc.o test_interrupt_cpu_intc_gpio.o -o ../executable.elf -N

任何帮助都会很棒。这个问题真的很烦人,我已经为此工作了好几天。我确信我错过了代码中的一些本质内容。如果您需要任何其他信息,请告诉我。

更新:

据我所知,我的程序从地址 0x50 开始。如果这是真的,这就解释了为什么我的分支操作从未被执行。

我尝试了几种方法来确保将基本说明放在正确的位置 (1)

    .org    0x0
brai    _start
    .org    0x8
brai    _exception_handler
    .org    0x10
brai    _interrupt_handler
    .org    0x20
brai    _hw_exception_handler

(2) 我尝试与 mb-gcc 和选项 x1-mode-xmdstub 链接(正如文档中所述,标准 crt0.o 未使用此选项链接)->但是,在这种情况下,我收到错误,

我尝试了 _start (3) 的多重定义 mb-ld test_interrupt_cpu_intc_gpio.o my_crt0_intc.o -o ../executable.elf -N

这样,行为发生了变化,但仍然不正确,因为现在 test_interrupt_cpu_intc_gpio.asm 从地址 0x50 开始。

谢谢, 塞玛

i'm pretty new to assembly language and microblaze cpus and i have a problem getting interrupt handling working.

i'm forced to write my own startup and init routines. (stuff that is usually contained in crt0) and i guess i'm doing something wrong with branching to the interrupt handler at the specified address. in the documentation it is said, to branch from code address 0x10 to the interrupt handler, however in my test program it doesn't work.

here you can find the microblaze doc. i'm referring to p. 102 (Interrupt and Exception Handling)

here you can see the code for 'my_crt0_intc.asm'

bri _start
nop
bri _exception_handler
nop
bri _interrupt_handler
nop
bri _hw_exception_handler
nop

/* Starting Point */
    .global _start
_start:     
    brlid   r15, _init_routine
    nop

/* Exception Handler *
    .global _exception_handler
_exception_handler:
/**/

/* Interrupt Handler */
    .global _interrupt_handler
_interrupt_handler:

    /* set led 0010 */
    ori r20, r20, 0x00000002
    swi r20, r0, 0x81400000

    rtid    r14, 8
    nop

/* HW Exception Handler *
    .global _hw_exception_handler
_hw_exception_handler:
/**/

/* Init Routine */
    .global _init_routine
_init_routine:
    /*** Initialize Stack Pointer ***/
    addi    r1, r0, 0x00004000
    /*** ***/

    /*** Initialize Interrupts ***/
    /** GPIO **/
    /* enable interrupts in GIE */
    addi    r19, r0, 0x80000000
    swi r19, r0, 0x8146011C

    /* enable interrupts in channel 1 (and 2, not) in IER */
    addi    r19, r0, 0x00000003
    swi r19, r0, 0x81460128

    /** INTC **/
    /* enable HW interrupts in INTC */
    addi    r19, r0, 0x00000003
    swi r19, r0, 0x8180001C

    /* enable interrupts in INTC IER */
    addi    r19, r0, 0xffffffff
    swi r19, r0, 0x81800008

    /** CPU, enable interrupts in MSR **/
    msrset  r19, 0x00000002
    /*** ***/

    /* Initialize Constants */
    /* r11 = word size, for increment and decrement stack pointer */
    /* addi r11, r0, 4 */

    /*** call main function ***/
    brlid   r15, main
    nop
    /*** ***/

    /*** halting loop ***/
_halting:
    bri _halting
    /*** ***/

    /* Return */
    rtsd    r15, 8
    nop

my test program 'test_interrupt_cpu_intc_gpio.asm' is intended to signal interrupts via leds at address 0x81400000

/* Main */
    .global main
main:
    addi    r20, r0, 0x0
_loop:

    /* set/unset alive led 0001 */
    andi    r21, r20, 0x00000001
    bnei    r21, _unset_alive
_set_alive:

    ori r20, r20, 0x1
    swi r20, r0, 0x81400000
    bri _no_alive

_unset_alive:

    andi    r20, r20, 0xfffffffe 
    swi r20, r0, 0x81400000
_no_alive:

    /* if gpio isr is set, set led 0100 */
    lwi r21, r0, 0x81460120
    beqi    r21, _unset_gpio
_set_gpio:
    ori r20, r20, 0x4
    swi r20, r0, 0x81400000
    bri _noset_gpio
_unset_gpio:
    andi    r20, r20, 0xfffffffb
    swi r20, r0, 0x81400000
_noset_gpio:

    /* if intc isr is set, set led 1000 */
    lwi r21, r0, 0x81800000
    beqi    r21, _unset_intc
_set_intc:
    ori r20, r20, 0x8
    swi r20, r0, 0x81400000
    bri _noset_intc
_unset_intc:
    andi    r20, r20, 0xfffffff7
    swi r20, r0, 0x81400000
_noset_intc:

    /* begin time loop */
    addi    r21, r0, 0x004af080
_loop_time:
    addi    r21, r21, -1
    bnei    r21, _loop_time
    /* end time loop*/

    bri _loop
    /* return 0*/
    addi    r3, r0, 0
    rtsd    r15, 8
    nop

the error symptoms are: if i do not enable interrupts in the MSR, led 0001 blinks and leds 1000 and 0100 are active if trigger the interrupt by pushing the appropriate button. however, in this situation of course the cpu doesn't handle interrupts and doesn't branch to the interrupt handler routine.

BUT: if i enable interrupts in the MSR to enable interrupt handling, led 0001 blinks in the beginning. after triggering the interrupt led 0001 is permanently set (or resp. unset if led 0001 is already unset when the interrupt occurs). led 1000 and 0100 stay inactive, which seems like the cpu stops working.

i compiled the code as follows with the mb-gcc tools:

mb-as test_interrupt_cpu_intc_gpio.o -o test_interrupt_cpu_intc_gpio.o
mb-as my_crt0_intc.asm -o my_crt0_intc.o

mb-ld my_crt0_intc.o test_interrupt_cpu_intc_gpio.o -o ../executable.elf -N

any help would be great. this problem is really annoying and i'm working on this for days. i'm sure i miss something essentially in the code. if you need any additional information, please let me know.

UPDATE:

as far as i can trust mb-gdb my program starts at address 0x50. if this is true, this explains why my branch operations are never executed.

i tried several things to ensure placing the essential instructions at the correct positions
(1)

    .org    0x0
brai    _start
    .org    0x8
brai    _exception_handler
    .org    0x10
brai    _interrupt_handler
    .org    0x20
brai    _hw_exception_handler

(2) i tried linking with mb-gcc and option x1-mode-xmdstub (as it is said in the documentation, that the standard crt0.o is not linked using this option) -> however, in this case i get the error, mutliple defintions of _start

(3) i tried
mb-ld test_interrupt_cpu_intc_gpio.o my_crt0_intc.o -o ../executable.elf -N

this way, the behavior changes, but is still uncorrect since now test_interrupt_cpu_intc_gpio.asm starts at address 0x50.

THANKS,
sema

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

桃气十足 2024-12-08 20:00:06

仅供记录:

问题是该程序与起始地址 0x50 链接。然而,正如 microblaze 文档中所指定的,中断处理程序的分支(向量)必须位于地址 0x10。

'mb-ld --verbose '给出了这个问题的提示

ENTRY(_start) _TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50;

'mb-objdump -dexecutable.elf'显示

../executable.elf:     file format elf32-microblaze

Disassembly of section .text:

00000050 <_start-0x28>:
  50:   b0000000        imm     0
  54:   b8080078        brai    120     // 78 <_start>
  58:   b0000000        imm     0
  5c:   b80800cc        brai    204     // cc <_exception_handler>
  60:   b0000000        imm     0
  64:   b80800d4        brai    212     // d4 <_interrupt_handler>
  68:   b0000000        imm     0

问题是通过选项-Ttest 0x0解决的:

mb-ld $CRT_OBJ $OBJ -o ../executable.elf -Ttext 0x0

我还错过了在中断处理程序例程中清除中断状态寄存器的操作应如下所示(注意 rtid r14, 0 而不是 rtid r14,8):

    .global _interrupt_handler
_interrupt_handler:

    /* set led 0010 */
    ori r20, r20, 0x00000002
    swi r23, r0, 0x81400000
    /**/

    /* clear channel 1 in gpio isr */
    addi    r22, r0, 0x00000001
    swi r22, r0, 0x81460120

    /* acknowledge interrupts in intc from channel 1 of gpio 3b (bit 2) */
    addi    r22, r0, 0x00000002
    swi r22, r0, 0x8180000C

    /* return from interrupt */
    rtid    r14, 0
    nop

摘要:
OBJDUMP是非常有用的工具! (这对我来说是新的)

just for record:

the problem was that the program was linked with start address 0x50. however, as specified in the microblaze documentation, the branch (vector) to the interrupt handler must be located at address 0x10.

'mb-ld --verbose ' gave a hint to this problem

ENTRY(_start) _TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50;

'mb-objdump -d executable.elf' shows

../executable.elf:     file format elf32-microblaze

Disassembly of section .text:

00000050 <_start-0x28>:
  50:   b0000000        imm     0
  54:   b8080078        brai    120     // 78 <_start>
  58:   b0000000        imm     0
  5c:   b80800cc        brai    204     // cc <_exception_handler>
  60:   b0000000        imm     0
  64:   b80800d4        brai    212     // d4 <_interrupt_handler>
  68:   b0000000        imm     0

the problem is solved by option -Ttest 0x0:

mb-ld $CRT_OBJ $OBJ -o ../executable.elf -Ttext 0x0

i also missed the clearing the interrupt status registers in the interrupt handler routine which should be as follows (note rtid r14, 0 instead of rtid r14,8):

    .global _interrupt_handler
_interrupt_handler:

    /* set led 0010 */
    ori r20, r20, 0x00000002
    swi r23, r0, 0x81400000
    /**/

    /* clear channel 1 in gpio isr */
    addi    r22, r0, 0x00000001
    swi r22, r0, 0x81460120

    /* acknowledge interrupts in intc from channel 1 of gpio 3b (bit 2) */
    addi    r22, r0, 0x00000002
    swi r22, r0, 0x8180000C

    /* return from interrupt */
    rtid    r14, 0
    nop

SUMMARY:
OBJDUMP is very useful tool! (it was new to me)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文