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

View File

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

View File

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