Обработка прерываний в MIPS-процессорах

 

Теперь - про "устранение причины". Звучит не очень внятно. Поясню, опять же, на примере. Все тот же мультикор, все тот же таймер.

Таймер установлен с некоторыми настройками. Когда он досчитывает до конца - он в своем регистре статуса/управления сбрасывает бит ENABLE и выставляет бит INT. Бит INT транслируется в соответствующий бит регистра QSTR. А единица в регистре QSTR (при единице в соответствующем разряде MASKR) - это исключение прерывания. То есть, если мы по прерыванию таймера выполним свою обработку и сразу сделаем ERET - то единица в QSTR у нас останется, и мы сразу попадем обратно в исключение. И так - до бесконечности. Поэтому в обработчике мы записываем в бит INT ноль, а в бит ENABLE - единицу (конечно, если нам надо перезапустить таймер). Аналогичная картина - со всеми остальными прерываниями. Для внутреннего устройства необходимо сбросить бит в регистре статуса, для программного прерывания - записать ноль, для аппаратного... С аппаратным сложнее. Оно либо в виде короткого импульса (нажатие кнопки) - тогда, конечно, этот абзац можно пропустить. Либо же "источник" внешнего прерывания как-то связан с процессором помимо этой линии - тогда надо как-то сообщить "источнику"о том, что прерывание обрабатывается и можно его "сбросить".

То есть, в общем виде обработчик прерывания будет выглядеть так:

void int_handler() {
unsigned int reg_Cause, reg_Status;
unsigned int ExcCode;
unsigned int IP;
unsigned int IM; // маска прерываний (в регистре Status CP0)
unsigned int ActiveIRQ;
unsigned int ActiveQST;
asm("la $3,reg_Cause"); // адрес переменной reg_Cause
asm("mfc0 $4,$13"); // копируем в $4 содержимое регистра Cause (13й регистр CP0).
asm("sw $4,0($3)"); // сохраняем это значение в переменную
asm("la $3, reg_Status"); // адрес переменной reg_Status
asm("mfc0 $4,$12"); // копируем в $4 содержимое регистра Status
asm("sw $4,0($3)"); // сохраняем в переменную
ExcCode = (reg_Cause >> 2) & 0x1F; // выделяем для удобства поле ExcCode в отдельную переменную
IP = (reg_Cause >> 8) & 0xFF; // аналогично - с полем IP
IM = (reg_Status >> 8) &0xFF; // и с полем IM поступаем также безжалостно
ActiveIRQ = IP & IM;
if ( ExcCode == 0 ) { //  исключение прерывания
................
   if (ActiveIRQ & (1<<4) ) { // внешнее прерывание nIRQ[2]
     // TO DO
   }
   if (ActiveIRQ & (1<<5) ) { // внешнее прерывание nIRQ[3]
     // TO DO
   }
................
   if ( ActiveIRQ & (1<<7) ) { // прерывание от внутреннего устройства
      ActiveQST = MASKR & QSTR;
................
      if ( ActiveQST & (1<<29) ) { // прерывание от таймера
         // TO DO
         ITCSR = 1; // ENABLE = 1, INT = 0 - то есть, сбрасываем прерывание и стартуем таймер заново
      }
................
   }
}

На месте многоточий может быть проверка на остальные прерывания. А может и ничего не быть. Это уже зависит от конкретных условий.

Размещение обработчика

Собственно, размещение - вещь несложная. Секцию .text обработчика надо просто разместить по нужному адресу. Как это сделать - разумеется, зависит от инструментов и IDE. Важный нюанс - на обработчики отводится не так уж много места в данной архитектуре. Например, обработчик исключения TLB Refill находится по адресу 0x8000_0000, а вектор исключения прерывания - по адресу 0x8000_0180. То есть, вроде бы на обработку TLB Refill у нас аж 0x180 байт. Это не мало, но не так уж и много. Иногда может быть необходимо и больше места. Да и отслеживать это бывает сложно. Поэтому проще по вектору обработчика разместить только некий минимальный обработчик, который будет выполнять только сохранение контекста и переход на основную функцию, которая располагается в далеких от вектора областях и поэтому может раскинуться хоть на мегабайт. Разумеется, решать каждому персонально, какой подход избрать. Но так как в компиляторе для мультикоров не предусмотрены ключевые слова, чтобы объявить функцию обработчиком - приходится на векторе располагать такой код, делающий jmp на сишную функцию-обработчик.

Почему нельзя объявить обычную функцию обработчиком? В других компиляторах - можно. Но не в данном конкретном случае. Функция на C в ассемблере будет состоять из сохранения используемых регистров, собственно рабочей части (то, что пишет программист), восстановления использованных регистров и возврата управления. Казалось бы, те же части, из которых состоит обработчик прерываний. За одним маленьким исключением. Обработчик должен заканчиваться инструкцией ERET. А обычная функция заканчивается инструкцией JR $31. В регистре $31 по MIPS-овому соглашению содержится адрес возврата из процедуры. Можно вставить ERET в тело функции. Но тогда она будет выполняться ДО восстановления регистров, что приведет вообще к непредсказуемым последствиям. Поэтому наилучшим пока считаю данный вариант. Разумеется, с использованием других компиляторов ситуация может меняться.

Разрешение прерываний

Казалось бы, мелочь. Однако, стоит ее упомянуть. Сколько каждый эмбеддер в своей жизни потратил времени на "отладку", когда вот не входит в прерывание, и все, хоть ты тресни! А потом оказывалось, что они тупо запрещены. Не стану говорить за всех. Но за себя скажу однозначно и честно - таких моментов было очень много.

Сначала надо разрешить прерывания вообще. За это отвечает бит IE регистра Status сопроцессора CP0 (Status[0]). Далее, необходимо разрешить программные, внешние и внутренние прерывания (разумеется, не все, а те, которые нужны. За это, как мы уже говорили, отвечает поле IM[7:0] регистра Status сопроцессора CP0 (Status[15:8]). Но бит IM[7] отвечает за все прерывания от внутренних устройств разом. Поэтому, чтобы разрешить прерывания от конкретных устройств, необходимо внести соответствующее значение в регистр MASKR. И вот лишь после этого прерывания будут доступны.

Ну, пожалуй, на сегодня и все. Посмотрим, что скажут благодарные читатели... Отзывы важны, жду с нетерпением...

Комментарии

Настройки просмотра комментариев

Выберите нужный метод показа комментариев и нажмите "Сохранить установки".

Ich bin gegen covid 19. Was ist deine Meinung?

Ich bin gegen covid 19. Was ist deine Meinung? mituns

Thank you very much for the invitation

thx much for the invitation :). I am expert of pandemic, and i can help you. PS: How are you? I am from France :) very good forum :) mixx

Ich bin gegen covid 19. Was ist deine Meinung?

Ich bin gegen covid 19. Was ist deine Meinung? mituns

Ich bin gegen covid 19. Was ist deine Meinung?

Ich bin gegen covid 19. Was ist deine Meinung? mituns

I want to explain you about pandemiuc

hi, i am woo from Sweden and i want to explain any thing about "pandemic". Please ask me :)

I want to explain you about pandemiuc

hi, i am woo from Sweden and i want to explain any thing about "pandemic". Please ask me :)

Отправить комментарий

Содержание этого поля является приватным и не предназначено к показу.
  • Syntax highlight code surrounded by the {syntaxhighlighter SPEC}...{/syntaxhighlighter} tags, where SPEC is a Syntaxhighlighter options string or "class="OPTIONS" title="the title".
  • Адреса страниц и электронной почты автоматически преобразуются в ссылки.
  • Доступны HTML теги: <a> <p> <span> <s> <strike> <div> <h1> <h2> <h3> <h4> <h5> <h6> <img> <map> <area> <hr> <br> <br /> <ul> <ol> <li> <dl> <dt> <dd> <table> <caption> <tbody> <tr> <td> <em> <b> <u> <i> <strong> <del> <ins> <sub> <sup> <quote> <blockquote> <pre> <address> <code> <cite> <embed> <object> <param> <strike>
  • Использовать как разделитель страниц.

Подробнее о форматировании