Переход к обработчику прерываний на ЦП Microblaze, язык ассемблера

Я новичок в языке ассемблера и процессоре microblaze, и у меня возникла проблема с обработкой прерываний.

я вынужден писать свои собственные процедуры запуска и инициализации. (материал, который обычно содержится в crt0), и я предполагаю, что делаю что-то не так с переходом к обработчику прерывания по указанному адресу. в документации сказано, что нужно переходить от кодового адреса 0x10 к обработчику прерывания, однако в моей тестовой программе это не работает.

Отн. ="nofollow">здесь вы можете найти документацию по microblaze. я имею в виду стр. 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

/* 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, светодиод 0001 мигает, а светодиоды 1000 и 0100 активны, если вызвать прерывание нажатием соответствующей кнопки. однако в этой ситуации, конечно, процессор не обрабатывает прерывания и не переходит к процедуре обработки прерываний.

НО: если я разрешаю прерывания в MSR, чтобы включить обработку прерываний, светодиод 0001 сначала мигает. после срабатывания прерывания светодиод 0001 постоянно установлен (или, соответственно, не установлен, если светодиод 0001 уже не установлен, когда происходит прерывание). светодиоды 1000 и 0100 остаются неактивными, что похоже на то, что процессор перестает работать.

Я скомпилировал код с помощью инструментов 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

любая помощь будет здорово. эта проблема действительно раздражает, и я работаю над этим несколько дней. я уверен, что я пропустил что-то существенное в коде. если вам нужна дополнительная информация, пожалуйста, дайте мне знать.

ОБНОВИТЬ:

насколько я могу доверять mb-gdb, моя программа начинается с адреса 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.

СПАСИБО, сема


person sema    schedule 27.08.2011    source источник
comment
Вы пробовали смотреть на вывод mb-ld --verbose <options>?   -  person user786653    schedule 29.08.2011
comment
GNU ld version 2.16 Xilinx EDK 9.2.02 Build EDK_Jm_SP2.2 5 ноября 2007 г. Поддерживаемые эмуляции: elf32microblaze ... ENTRY(_start) _TEXT_START_ADDR = DEFINED(_TEXT_START_ADDR) ? _TEXT_START_ADDR : 0x50; ... начальный адрес 0x50 - это проблема, простой совет, но очень помог! :)   -  person sema    schedule 03.09.2011


Ответы (1)


просто для записи:

проблема заключалась в том, что программа была связана со стартовым адресом 0x50. однако, как указано в документации microblaze, ветвь (вектор) к обработчику прерывания должна располагаться по адресу 0x10.

'mb-ld --verbose' намекнул на эту проблему

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

'mb-objdump -d исполняемый файл.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 — очень полезный инструмент! (это было ново для меня)

person sema    schedule 04.09.2011
comment
Рад, что вы поняли это :) Синтаксис и использование GNU binutils могут быть довольно загадочными ( например, синтаксис objdump -D -b binary -m <arch> для дизассемблирования двоичных файлов), но они чрезвычайно полезны, и их изучение приносит дивиденды. - person user786653; 04.09.2011