Использование прерываний в программе на языке ассемблер
Пример программы на ассемблере для процессорной системы «DE2-70 Media Computer», в котором используются прерывания, показан в листинге 7. Эта программа отображает циклически сдвигаемый набор на 7-сегментных индикаторах. Набор сдвигается вправо, если нажата кнопка KEY1, и влево, если нажата KEY2. Нажатие KEY3 приводит к тому, что набор переустанавливается с использованием величины, заданной на переключателях. Два типа прерываний используется в этом примере. Отображение шестнадцатеричных чисел на 7-сегментных индикаторах выполняется программой обслуживания прерываний от интервального таймера и другая программа обработки прерываний, вызывается нажатием кнопок. Скорость, с которой шестнадцатеричные наборы отображаются в режиме бегущей строки на 7-сегментных индикаторах, устанавливается в основной программе посредством использования интервального таймера, который формирует прерывания каждые 33 мс.
Листинг 7. Пример программы на ассемблере, в которой используются прерывания
.equ KEY1, 0
.equ KEY2, 1
/*******************************************************************************
* Эта программа демонстрирует использование прерываний на стенде
* DE2-70 Media Computer. Вначале запускается таймер, который генерирует
* прерывания каждые 33 мс. Затем разрешаются прерывания от таймера и кнопок.
* Процедура обработки прерывания таймера отображает текст на 7-сегментных
* индикаторах и сдвигает его влево или вправо. Направление сдвига определяется
* кнопками. При нажатии кнопки key1 текст сдвигается вправо, при нажатии
* key2 – влево, при нажатии key3 изменяется текст, используя данные с переключателей.
********************************************************************************/
.text
.global _start
_start:
movia sp, 0x03FFFFFC /* Определяем адрес вершины стека */
movia r16, 0x10002000
/* Определяем период срабатывания интервального таймера */
movia r12, 0x190000 /* 1/(50 MHz) x (0x190000) = 33 msec */
sthio r12, 8(r16) /*определяем младшее полуслово как стартовое значение*/
srli r12, r12, 16
sthio r12, 0xC(r16) /* старшее полуслово как стартовое значение */
/* Запускаем таймер и разрешаем прерывания от него */
movi r15, 0b0111 /* START = 1, CONT = 1, ITO = 1 */
sthio r15, 4(r16)
/* Разрешаем прерывания PIO, к которому подсоединены кнопки */
movia r15, 0x10000050 /* Адрес регистра кнопок */
movi r7, 0b01110
stwio r7, 8(r15) /* Устанавливаем 3 бита регистра маски прерывания*/
/* Разрешаем прерывания NIOS 2 процессора */
movi r7, 0b011
wrctl ienable, r7 /*Разрешаем прерывания от кнопок*/
movi r7, 1
wrctl status, r7 /* Разрешаем процессору обрабатывать прерывания */
IDLE:
br IDLE /* Бесконечный цикл */
.data
.global PATTERN
PATTERN:
.word 0x0000000F
.global KEY_PRESSED
KEY_PRESSED:
.word KEY2
.end
Обработчики сброса и исключений процессора для представленной выше программы приведены в листинге 8. Обработчик сброса процессора просто выполняет переход на метку _start в основной программе. Обработчик исключений вначале проверяет, является ли исключение внешним прерыванием, или внутренним. В случае внутреннего прерывания, такого как обнаружение некорректного кода операции или команды ловушки (trap) обработчик просто выполняет возврат из прерывания. То есть, он не обрабатывает эти случаи. Для внешних прерываний он вызывает либо программу обслуживания интервального таймера для прерывания уровня 0, либо программу обслуживания прерываний от кнопок для прерывания уровня 1. Эти программы показаны в листингах 9 и 10, соответственно.
Листинг 8. Обработчики сброса и исключений
/*****************************************************************************
* ОБРАБОТЧИК СБРОСА
* "ax" требуется для того, чтобы определить секцию как исполняемую.
* AMP автоматически размещает секцию сброса по адресу, определяемому в настройках
* процессора в SOPC Builder.
*****************************************************************************/
.section .reset, "ax"
movia r2, _start
jmp r2 /* Переходим в основную программу */
/*****************************************************************************
* ОБРАБОТЧИК ИСКЛЮЧЕНИЙ
* "ax" требуется для того, чтобы определить секцию как исполняемую.
* AMP автоматически размещает секцию сброса по адресу, определяемому в настройках
* процессора в SOPC Builder.
*****************************************************************************/
.section .exceptions, "ax"
.global EXCEPTION_HANDLER /*Определяем процедуру как глобальную*/
EXCEPTION_HANDLER: /*Процедура обработки прерываний*/
subi sp, sp, 16 /* Изменяем адрес указателя стека */
stw et, 0(sp) /*Сохраняем содержимое регистра et в стеке*/
rdctl et, ctl4
beq et, r0, SKIP_EA_DEC /* Если прерывание не внешнее, то переходим на SKIP_EA_DEC */
subi ea, ea, 4 /* декрементируем регистр ea на 1 команду */
SKIP_EA_DEC:
stw ea, 4(sp) /* Сохраняем регистры в стеке */
stw ra, 8(sp)
stw r22, 12(sp)
rdctl et, ctl4
bne et, r0, CHECK_LEVEL_0 /* Если прерывание внешнее, то переходим на CHECK_LEVEL_0*/
NOT_EI: /* Прерывание произошло в случае встречи невыполнимой команды или команды TRAP */
br END_ISR /* Выходим из обработчика прерываний */
CHECK_LEVEL_0: /* Проверка, является ли прерывание прерыванием от таймера IRQ0 */
andi r22, et, 0b1
beq r22, r0, CHECK_LEVEL_1 /*Если бит 0b1 регистра et не равен 1, то переходим к проверке, является ли прерывание прерыванием от кнопок*/
call INTERVAL_TIMER_ISR /*Вызываем процедуру обработки прерывания от таймера*/
br END_ISR /*Выходим из обработчика прерываний*/
CHECK_LEVEL_1: /*Проверка, является ли прерывание прерыванием от кнопок IRQ1*/
andi r22, et, 0b10
beq r22, r0, END_ISR /* Если бит 0b10 регистра et не равен 10, то выходим из обработчика прерываний*/
call PUSHBUTTON_ISR /*Вызываем процедуру обработки прерываний от кнопок*/
END_ISR:
/*Восстанавливаем из стека все используемые регистры*/
ldw et, 0(sp)
ldw ea, 4(sp)
ldw ra, 8(sp)
ldw r22, 12(sp)
addi sp, sp, 16
eret /*Выходим из процедуры обработки прерывания*/
.end
T +vZmenoEkXBKf2X40Wd1KNlpH0ayUTgN8xUXGa+XIDjOVgsG+18gy0L+9y+/AQAA//8DAFBLAQIt ABQABgAIAAAAIQC2gziS/gAAAOEBAAATAAAAAAAAAAAAAAAAAAAAAABbQ29udGVudF9UeXBlc10u eG1sUEsBAi0AFAAGAAgAAAAhADj9If/WAAAAlAEAAAsAAAAAAAAAAAAAAAAALwEAAF9yZWxzLy5y ZWxzUEsBAi0AFAAGAAgAAAAhAPlmgqkqAgAAIAQAAA4AAAAAAAAAAAAAAAAALgIAAGRycy9lMm9E b2MueG1sUEsBAi0AFAAGAAgAAAAhANfjQI7bAAAABwEAAA8AAAAAAAAAAAAAAAAAhAQAAGRycy9k b3ducmV2LnhtbFBLBQYAAAAABAAEAPMAAACMBQAAAAA= " strokecolor="red" strokeweight="2pt">
Листинг 9. Программа обработки прерываний от интервального таймера
.include "key_codes.s"
.extern PATTERN
.extern KEY_PRESSED
/*****************************************************************************
* Процедура обработки прерываний от таймера
******************************************************************************/
.global INTERVAL_TIMER_ISR
INTERVAL_TIMER_ISR:
subi sp, sp, 40 /* Сохраняем регистры в стеке */
stw ra, 0(sp)
stw r4, 4(sp)
stw r5, 8(sp)
stw r6, 12(sp)
stw r8, 16(sp)
stw r10, 20(sp)
stw r20, 24(sp)
stw r21, 28(sp)
stw r22, 32(sp)
stw r23, 36(sp)
movia r10, 0x10002000
sthio r0, 0(r10)
movia r20, 0x10000020 /*адрес регистра HEX3_HEX0 */
movia r21, 0x10000030 /*адрес регистра HEX7_HEX4*/
addi r5, r0, 1
movia r22, PATTERN
movia r23, KEY_PRESSED
ldw r6, 0(r22) /* загружаем текст для вывода на 7-сегментные индикаторы */
stwio r6, 0(r20) /* выводим на HEX3 ... HEX0 */
stwio r6, 0(r21) /* выводим на HEX7 ... HEX4 */
ldw r4, 0(r23) /* Проверяем, какая кнопка была нажата */
movi r8, KEY1
beq r4, r8, LEFT /* Если была нажата key1, то сдвигаем текст вправо */
rol r6, r6, r5 /* иначе, сдвигаем влево */
br END_INTERVAL_TIMER_ISR
LEFT:
ror r6, r6, r5 /* сдвигаем текст вправо*/
END_INTERVAL_TIMER_ISR:
stw r6, 0(r22) /* выводим текст на 7-сегментные индикаторы */
ldw ra, 0(sp) /* Восстанавливаем регистры из стека */
ldw r4, 4(sp)
ldw r5, 8(sp)
ldw r6, 12(sp)
ldw r8, 16(sp)
ldw r10, 20(sp)
ldw r20, 24(sp)
ldw r21, 28(sp)
ldw r22, 32(sp)
ldw r23, 36(sp)
addi sp, sp, 40
ret
.end
Дата добавления: 2015-05-30; просмотров: 1466;