ЛР14,16. Дополнение startup-файла

- добавлен код восстановления CS-регистра mcause
- в более явном виде описано почему в низкоуровневом обработчике
на стек сохраняется не весь регистровый файл.
This commit is contained in:
Andrei Solodovnikov
2025-05-13 17:11:06 +03:00
parent 6f74ab5c21
commit eca95fe11f
3 changed files with 131 additions and 124 deletions

View File

@@ -361,12 +361,10 @@ _endless_loop:
# В основе кода лежит обработчик из репозитория urv-core:
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
# сохранение контекста, что и при программном вызове (EABI подразумевает ещё
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
# файл.
# Документ:
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
# в реализации сохраняются только необерегаемые регистры регистрового файла.
# Это сделано по причине того, что при вызове высокоуровневого обработчика
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
# с соглашением о вызовах.
_int_handler:
# Данная операция меняет местами регистры sp и mscratch.
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
@@ -427,9 +425,11 @@ _int_handler:
mv a0,sp
lw t1, 72(a0)
lw t2, 76(a0)
addi sp, sp, 80
csrw mscratch, sp
csrw mepc, t1
csrw mcause, t2
lw ra, 4(a0)
lw sp, 8(a0)
lw t0, 12(a0)
@@ -453,6 +453,7 @@ _int_handler:
# Выход из обработчика прерывания
mret
```
_Листинг 2. Пример содержимого файла первичных команд с поясняющими комментариями._

View File

@@ -58,12 +58,10 @@ _endless_loop:
# В основе кода лежит обработчик из репозитория urv-core:
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
# сохранение контекста, что и при программном вызове (EABI подразумевает еще
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
# файл.
# Документ:
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
# в реализации сохраняются только необерегаемые регистры регистрового файла.
# Это сделано по причине того, что при вызове высокоуровневого обработчика
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
# с соглашением о вызовах.
_int_handler:
# Данная операция меняет местами регистры sp и mscratch.
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
@@ -103,7 +101,7 @@ _int_handler:
sw t6, 68(sp)
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
# произойдет еще одно прерывание.
# произойдет ещё одно прерывание.
csrr t0, mscratch
csrr t1, mepc
csrr a0, mcause
@@ -119,14 +117,16 @@ _int_handler:
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
# на случай, если происходило вложенное прерывание. Для этого, мы должны
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
# значение нам еще необходимо для восстановления контекста, поэтому мы
# значение нам ещё необходимо для восстановления контекста, поэтому мы
# сохраним его в регистр a0, и будем восстанавливаться из него.
mv a0,sp
lw t1, 72(a0)
lw t2, 76(a0)
addi sp, sp, 80
csrw mscratch, sp
csrw mepc, t1
csrw mcause, t2
lw ra, 4(a0)
lw sp, 8(a0)
lw t0, 12(a0)

View File

@@ -41,7 +41,11 @@ _main_call:
# нулевой элемент которого является именем исполняемого файла,
# Но для простоты реализации оба аргумента всего лишь обнулены.
# Это сделано для детерминированного поведения программы в случае,
# если будет пытаться использовать эти аргументы.
# если программист будет пытаться использовать эти аргументы.
# Вызов main.
# Для того чтобы программа скомпоновалась, где-то должна быть описана
# функция именно с таким именем.
call main
# Зацикливание после выхода из функции main
_endless_loop:
@@ -54,12 +58,10 @@ _endless_loop:
# В основе кода лежит обработчик из репозитория urv-core:
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
# сохранение контекста, что и при программном вызове (EABI подразумевает еще
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
# файл.
# Документ:
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
# в реализации сохраняются только необерегаемые регистры регистрового файла.
# Это сделано по причине того, что при вызове высокоуровневого обработчика
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
# с соглашением о вызовах.
_int_handler:
# Данная операция меняет местами регистры sp и mscratch.
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
@@ -99,7 +101,7 @@ _int_handler:
sw t6, 68(sp)
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
# произойдет еще одно прерывание.
# произойдет ещё одно прерывание.
csrr t0, mscratch
csrr t1, mepc
csrr a0, mcause
@@ -107,20 +109,24 @@ _int_handler:
sw t1, 72(sp)
sw a0, 76(sp)
# Вызов высокоуровневого обработчика прерываний
# call int_handler
# Вызов высокоуровневого обработчика прерываний.
# Для того чтобы программа скомпоновалась, где-то должна быть описана
# функция именно с таким именем.
call int_handler
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
# на случай, если происходило вложенное прерывание. Для этого, мы должны
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
# значение нам еще необходимо для восстановления контекста, поэтому мы
# значение нам ещё необходимо для восстановления контекста, поэтому мы
# сохраним его в регистр a0, и будем восстанавливаться из него.
mv a0,sp
lw t1, 72(a0)
lw t2, 76(a0)
addi sp, sp, 80
csrw mscratch, sp
csrw mepc, t1
csrw mcause, t2
lw ra, 4(a0)
lw sp, 8(a0)
lw t0, 12(a0)