- •Однокристальная микроЭвм мс68нс705с8.
- •2. Специальные режимы работы.
- •2.1 Reset
- •2.2 Режимы с пониженным энергопотреблением.
- •1. Внешнее аппаратное прерывание irq.
- •2. Программное прерывание swi.
- •3. Аппаратное прерывание reset.
- •4. Режимы малого потребления stop и wait.
- •Контрольные вопросы.
- •Задания.
2. Программное прерывание swi.
Как было отмечено выше, SWI является программным прерыванием и инициируется программистом, в отличие от других прерываний, генерируемых аппаратурой микроконтроллера. SWI является немаскируемым, то есть его нельзя программно запретить.
Для генерации этого прерывания используется команда ассемблера SWI, при выполнении которой происходит следующее:
1. инкрементируется счетчик команд PC, в стеке сохраняется сначала младший, затем старший байты PC;
2. в стеке последовательно сохраняются регистры X, A, C;
3. в счетчик команд заносятся два байта, хранящихся по адресам $1FFC, $1FFD;
Таким образом, после выполнения команды SWI указатель стека смещается на пять байт в сторону младших адресов, и управление передается по вектору, записанному в ячейках $1FFC, $1FFD.
В качестве примера использования команды SWI рассмотрим программу вычисления факториала.
Программу организуем следующим образом:
· с адреса $200 запишем блок начальной инициализации ячеек памяти и вызова подпрограммы обработки прерывания;
· с адреса $300 будет находиться собственно подпрограмма обработки прерывания, вычисляющая факториал;
· по адресу $400 поместим вспомогательную подпрограмму умножения двух чисел.
В ячейке $50 разместим аргумент, а в ячейку $51 будем записывать результат (то есть факториал от содержимого ячейки $50).
Рассмотрим программу вычисления 4!
Основной блок :
200 LDA #$4 Записываем аргумент
202 STA $50 в ячейку $50.
204 LDA #$1 Записываем 1
206 STA $51 в ячейку $51.
208 RSP Устанавливаем указатель стека в $FF.
209 SWI Генерируем вызов подпрограммы обработки прерывания.
20А LDA $51 Записываем результат вычислений в регистр А.
20С BRA 20С Организуем бесконечный цикл.
Подпрограмма обработки прерывания :
300 LDA $50 Сравниваем аргумент
302 CMP #$1 с единицей.
304 BEQ $30С Если аргумент равен единице, то переходим на $30С (вычисления окончены),
306 JSR $400 иначе вызываем подпрограмму умножения чисел.
309 DEC $50 Уменьшаем аргумент на единицу.
30В SWI Вызываем подпрограмму вычисления факториала.
30С RTI Возврат из подпрограммы.
Подпрограмма умножения двух чисел :
400 LDA $50 Перемножаем два числа,
402 LDX $51 находящихся в ячейках
404 MUL $50 и $51.
405 STA $51 Запоминаем результат.
407 RTS Возврат из подпрограммы.
Следующие несколько замечаний поясняют работу программы:
· при выполнении команды SWI, расположенной по адресу $209, в стеке сохраняются значения регистров PC, X, A, C, указатель стека SP смещается на 5 байт вниз, то есть в сторону младших адресов, и управление передается по адресу, записанному в ячейках $1FFC (старший байт) и $1FFD (младший байт), где находится вектор программного прерывания (в нашем случае - $300);
· поскольку мы вычисляем факториал, используя рекурсию, то подпрограмма обработки прерывания будет иметь следующую структуру:
1. проверка условия завершения вычислений, возврат из подпрограммы в случае его истинности;
2. уменьшение аргумента на единицу и вложенный вызов этой же подпрограммы;
· при выполнении команды SWI, расположенной по адресу $30В, происходит вызов подпрограммы вычисления факториала от числа, на единицу меньшего, чем то, что хранится в ячейке $50; при этом регистры опять сохраняются в стеке, указатель стека смещается на 5 байт в сторону младших адресов, и управление передается по адресу, хранящемуся в ячейках $1FFC, $1FFD;
· задача вспомогательной подпрограммы умножения чисел - перемножить два числа, хранящихся в ячейках $50, $51 и поместить младший байт результата в ячейку $51;
Для правильной работы программы необходимо занести адрес подпрограммы обработки прерывания в ячейки $1FFC, $1FFD ($03 в $1FFC и $00 в $1FFD) и поставить точку останова по адресу $20C.
Запустите программу с адреса $200. На экране появится содержимое регистров микроконтроллера, причем регистр A будет содержать результат работы нашей программы: число $18 (в десятичной системе счисления оно равно 24). Можно убедиться, что в ячейке $51 находится то же самое.
Выведите на экран дамп памяти с $C0 по $FF ячейки. Эту область занимает стек. Напомним, что стек начинается с ячейки $FF и по мере заполнения растет вниз - в сторону младших адресов. Начиная с адреса $FF и ниже расположены 30 байт, которые использовала наша программа в процессе работы. Каждый раз при выполнении команды SWI занимаются очередные свободные пять ячеек памяти в стеке, а при выполнении команды RTI из последних пяти использованных ячеек считываются значения регистров, и указатель стека увеличивется на 5 байт, то есть занятая часть стека становится короче. После завершения работы программы стек полностью освобождается, указатель стека принимает то значение, которое он имел до запуска программы, но вся информация, сохраненная в свое время в стеке, остается. Убедитесь в этом.
Тем не менее, при написании и отладке программ следует иметь ввиду, что стек может занимать максимум 64 байта (адреса $C0...$FF). Если происходит переполнение, то указатель стека циклически смещается на начало , что приводит к потере данных. Из вышесказанного следует, что для нашего примера максимальное значение аргумента равно 10, в этом случае стек заполнится целиком. Однако, поскольку мы отвели под результат лишь один байт, то программа перестанет правильно работать уже при значении аргумента, равном 6. Избежать этого можно, предусмотрев в подпрограмме умножения чисел сохранение двухбайтного результата.