diff --git a/Labs/10. Interrupt subsystem/README.md b/Labs/10. Interrupt subsystem/README.md index cd1f2e4..d234d89 100644 --- a/Labs/10. Interrupt subsystem/README.md +++ b/Labs/10. Interrupt subsystem/README.md @@ -246,90 +246,95 @@ _Рисунок 4. Структурная схема контроллера пр ```asm _start: # Инициализируем начальные значения регистров -li sp, 0x00003FFC # устанавливаем указатель на верхушку стека +00: li sp, 0x00003FFC # устанавливаем указатель на верхушку стека +04: # данная псевдоинструкция будет разбита на две + # инструкции: lui и addi + +08: li gp, 0x00000000 # устанавливаем указатель на глобальные данные + +0C: li t0, 0x00000001 # подготавливаем маску прерывания единственного + # (нулевого) входа +10: csrw mie, t0 # загружаем маску в регистр маски + +14: la t0, interrupt # псевдоинструкция la аналогично li загружает число, +18: # только в случае la — это число является адресом + # указанного места (адреса обработчика перехвата) # данная псевдоинструкция будет разбита на две # инструкции: lui и addi -li gp, 0x00000000 # устанавливаем указатель на глобальные данные +1С: csrw mtvec, t0 # устанавливаем вектор прерывания -li t0, 0x00000001 # подготавливаем маску прерывания единственного - # (нулевого) входа -csrw mie, t0 # загружаем маску в регистр маски +20: li t0, 0x00001FFC # готовим адрес верхушки стека прерывания +24: # данная псевдоинструкция будет разбита на две + # инструкции: lui и addi -la t0, interrupt # псевдоинструкция la аналогично li загружает число, - # только в случае la — это число является адресом - # указанного места (адреса обработчика перехвата) +28: csrw mscratch, t0 # загружаем в указатель на верхушку стека прерывания -csrw mtvec, t0 # устанавливаем вектор прерывания +2С: li t0, 1 # начальное значение глобальной переменной +30: sw t0, 0(gp) # загружаем переменную в память -li t0, 0x00001FFC # готовим адрес верхушки стека прерывания -csrw mscratch, t0 # загружаем в указатель на верхушку стека прерывания +34: li t1, 0 # начальное значение, чтобы в симуляции не было xxx +38: li t2, 0 # начальное значение, чтобы в симуляции не было xxx -li t0, 1 # начальное значение глобальной переменной -sw t0, 0(gp) # загружаем переменную в память +# Вызов ecall исключительно из хулиганских соображений, поскольку в данной +# микроархитектурной реализации это приведет к появлению illegal_instr и +# последующей обработке исключения +3С: ecall -li t1, 0 # начальное значение, чтобы в симуляции не было xxx -li t2, 0 # начальное значение, чтобы в симуляции не было xxx - -# Вызов ecall исключительно из хулиганских соображений, -# поскольку в данной микроархитектурной реализации это -# приведет к появлению illegal_instr и последующей обработке -# исключения -ecall # Вызов функции main main: - beq x0, x0, main # бесконечный цикл, аналогичный while (1); +40: beq x0, x0, main # бесконечный цикл, аналогичный while (1); # ОБРАБОТЧИК ПРЕРЫВАНИЯ -# Без стороннего вмешательства процессор никогда не перейдет -# к инструкциям ниже, однако в случае прерывания, -# в программный счетчик будет загружен адрес первой +# Без стороннего вмешательства процессор никогда не перейдет к инструкциям ниже, +# однако в случае прерывания в программный счетчик будет загружен адрес первой # нижележащей инструкции. # Сохраняем используемые регистры на стек interrupt: - csrrw t0, mscratch, t0 # меняем местами mscratch и t0 - sw t1, 0(t0) # сохраняем t1 на стек mscratch - sw t2, 4(t0) # сохраняем t2 на стек mscratch +44: csrrw t0, mscratch, t0 # меняем местами mscratch и t0 +48: sw t1, 0(t0) # сохраняем t1 на стек mscratch +4С: sw t2, 4(t0) # сохраняем t2 на стек mscratch - # Проверяем произошло ли прерывание - csrr t1, mcause # t1 = mcause - li t2, 0x10000010 # загружаем в t2 код того, что произошло прерывание - bne t1, t2, exc_handler # если коды не совпадают, переходим к проверке +# Проверяем произошло ли прерывание +50: csrr t1, mcause # t1 = mcause +54: li t2, 0x10000010 # загружаем в t2 код того, что произошло прерывание +58: # данная псевдоинструкция будет разбита на две + # инструкции: lui и addi +5C: bne t1, t2, exc_handler # если коды не совпадают, переходим к проверке # на исключение - # Обработчик прерывания - lw t2, 0(gp) # загружаем переменную из памяти - addi t2, t2, 3 # прибавляем к значению 3 - sw t2, 0(gp) # возвращаем переменную в память - j done # идем возвращать регистры и на выход +# Обработчик прерывания +60: lw t2, 0(gp) # загружаем переменную из памяти +64: addi t2, t2, 3 # прибавляем к значению 3 +68: sw t2, 0(gp) # возвращаем переменную в память +6C: j done # идем возвращать регистры и на выход exc_handler: # Проверяем произошло ли исключение - li t2, 0x0000002 # загружаем в t2 код того, что произошло исключение - bne t1, t2, done # если это не оно, то выходим +70: li t2, 0x0000002 # загружаем в t2 код того, что произошло исключение +74: bne t1, t2, done # если это не оно, то выходим - # Обработчик исключения - csrr t1, mepc # Узнаем значение PC (адреса инструкции, +# Обработчик исключения +78: csrr t1, mepc # Узнаем значение PC (адреса инструкции, # вызвавшей исключение) - lw t2, 0x0(t1) # Загружаем эту инструкцию в регистр t2 +7C: lw t2, 0x0(t1) # Загружаем эту инструкцию в регистр t2 # Теоретически мы могли бы после этого # сделать что-то, в зависимости от этой инструкции. # Например если это операция умножения — вызвать # подпрограмму умножения. - addi t1, t1, 4 # Увеличиваем значение PC на 4, чтобы после +80: addi t1, t1, 4 # Увеличиваем значение PC на 4, чтобы после # возврата не попасть на инструкцию, вызвавшую # исключение. - csrw mepc, t1 # Записываем обновленное значение PC в регистр mepc - j done # идем восстанавливать регистры со стека и на выход +84: csrw mepc, t1 # Записываем обновленное значение PC в регистр mepc +88: j done # идем восстанавливать регистры со стека и на выход # Возвращаем регистры на места и выходим done: - lw t1, 0(t0) # возвращаем t1 со стека - lw t2, 4(t0) # возвращаем t2 со стека - csrrw t0, mscratch, t0 # меняем обратно местами t0 и mscratch - mret # возвращаем управление программе (pc = mepc) +8C: lw t1, 0(t0) # возвращаем t1 со стека +90: lw t2, 4(t0) # возвращаем t2 со стека +94: csrrw t0, mscratch, t0 # меняем обратно местами t0 и mscratch +98: mret # возвращаем управление программе (pc = mepc) # что означает возврат в бесконечный цикл - ``` ## Задание