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