mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
ЛР14,16. Дополнение startup-файла
- добавлен код восстановления CS-регистра mcause - в более явном виде описано почему в низкоуровневом обработчике на стек сохраняется не весь регистровый файл.
This commit is contained in:
@@ -361,21 +361,19 @@ _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, а вершина
|
||||
# программного стека оказывается в регистре mscratch.
|
||||
csrrw sp, mscratch, sp
|
||||
csrrw sp, mscratch,sp
|
||||
|
||||
# Далее мы поднимаемся по стеку прерываний и сохраняем все регистры.
|
||||
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
|
||||
# поднимаемся вверх не на 76, а на 80.
|
||||
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
|
||||
# поднимаемся вверх не на 76, а на 80.
|
||||
sw ra, 4(sp)
|
||||
# Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на
|
||||
# программный стек, поэтому записываем в освободившийся регистр низ
|
||||
@@ -387,32 +385,32 @@ _int_handler:
|
||||
la ra, _stack_ptr
|
||||
blt sp, ra, _endless_loop
|
||||
|
||||
sw t0,12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
|
||||
# лежать регистр sp, который ранее сохранили в mscratch.
|
||||
# Мы запишем его на стек чуть позже.
|
||||
sw t1,16(sp)
|
||||
sw t2,20(sp)
|
||||
sw a0,24(sp)
|
||||
sw a1,28(sp)
|
||||
sw a2,32(sp)
|
||||
sw a3,36(sp)
|
||||
sw a4,40(sp)
|
||||
sw a5,44(sp)
|
||||
sw a6,48(sp)
|
||||
sw a7,52(sp)
|
||||
sw t3,56(sp)
|
||||
sw t4,60(sp)
|
||||
sw t5,64(sp)
|
||||
sw t6,68(sp)
|
||||
sw t0, 12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
|
||||
# лежать регистр sp, который ранее сохранили в mscratch.
|
||||
# Мы запишем его на стек чуть позже.
|
||||
sw t1, 16(sp)
|
||||
sw t2, 20(sp)
|
||||
sw a0, 24(sp)
|
||||
sw a1, 28(sp)
|
||||
sw a2, 32(sp)
|
||||
sw a3, 36(sp)
|
||||
sw a4, 40(sp)
|
||||
sw a5, 44(sp)
|
||||
sw a6, 48(sp)
|
||||
sw a7, 52(sp)
|
||||
sw t3, 56(sp)
|
||||
sw t4, 60(sp)
|
||||
sw t5, 64(sp)
|
||||
sw t6, 68(sp)
|
||||
|
||||
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
|
||||
# произойдет ещё одно прерывание.
|
||||
csrr t0,mscratch
|
||||
csrr t1,mepc
|
||||
csrr a0,mcause
|
||||
sw t0,8(sp)
|
||||
sw t1,72(sp)
|
||||
sw a0,76(sp)
|
||||
csrr t0, mscratch
|
||||
csrr t1, mepc
|
||||
csrr a0, mcause
|
||||
sw t0, 8(sp)
|
||||
sw t1, 72(sp)
|
||||
sw a0, 76(sp)
|
||||
|
||||
# Вызов высокоуровневого обработчика прерываний.
|
||||
# Для того чтобы программа скомпоновалась, где-то должна быть описана
|
||||
@@ -426,33 +424,36 @@ _int_handler:
|
||||
# сохраним его в регистр a0, и будем восстанавливаться из него.
|
||||
mv a0,sp
|
||||
|
||||
lw t1,72(a0)
|
||||
addi sp,sp,80
|
||||
csrw mscratch,sp
|
||||
csrw mepc,t1
|
||||
lw ra,4(a0)
|
||||
lw sp,8(a0)
|
||||
lw t0,12(a0)
|
||||
lw t1,16(a0)
|
||||
lw t2,20(a0)
|
||||
lw a1,28(a0) # Мы пропустили a0, потому что сейчас он используется в
|
||||
# качестве указателя на верхушку стека и не может быть
|
||||
# восстановлен.
|
||||
lw a2,32(a0)
|
||||
lw a3,36(a0)
|
||||
lw a4,40(a0)
|
||||
lw a5,44(a0)
|
||||
lw a6,48(a0)
|
||||
lw a7,52(a0)
|
||||
lw t3,56(a0)
|
||||
lw t4,60(a0)
|
||||
lw t5,64(a0)
|
||||
lw t6,68(a0)
|
||||
lw a0,40(a0)
|
||||
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)
|
||||
lw t1, 16(a0)
|
||||
lw t2, 20(a0)
|
||||
lw a1, 28(a0) # Мы пропустили a0, потому что сейчас он используется в
|
||||
# качестве указателя на верхушку стека и не может быть
|
||||
# восстановлен.
|
||||
lw a2, 32(a0)
|
||||
lw a3, 36(a0)
|
||||
lw a4, 40(a0)
|
||||
lw a5, 44(a0)
|
||||
lw a6, 48(a0)
|
||||
lw a7, 52(a0)
|
||||
lw t3, 56(a0)
|
||||
lw t4, 60(a0)
|
||||
lw t5, 64(a0)
|
||||
lw t6, 68(a0)
|
||||
lw a0, 40(a0)
|
||||
|
||||
# Выход из обработчика прерывания
|
||||
mret
|
||||
|
||||
|
||||
```
|
||||
|
||||
_Листинг 2. Пример содержимого файла первичных команд с поясняющими комментариями._
|
||||
|
@@ -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)
|
||||
|
@@ -41,7 +41,11 @@ _main_call:
|
||||
# нулевой элемент которого является именем исполняемого файла,
|
||||
# Но для простоты реализации оба аргумента всего лишь обнулены.
|
||||
# Это сделано для детерминированного поведения программы в случае,
|
||||
# если будет пытаться использовать эти аргументы.
|
||||
# если программист будет пытаться использовать эти аргументы.
|
||||
|
||||
# Вызов main.
|
||||
# Для того чтобы программа скомпоновалась, где-то должна быть описана
|
||||
# функция именно с таким именем.
|
||||
call main
|
||||
# Зацикливание после выхода из функции main
|
||||
_endless_loop:
|
||||
@@ -54,22 +58,20 @@ _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, а вершина
|
||||
# программного стека оказывается в регистре mscratch.
|
||||
csrrw sp,mscratch,sp
|
||||
csrrw sp, mscratch,sp
|
||||
|
||||
# Далее мы поднимаемся по стеку прерываний и сохраняем все регистры.
|
||||
addi sp,sp,-80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
|
||||
# поднимаемся вверх не на 76, а на 80.
|
||||
sw ra,4(sp)
|
||||
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
|
||||
# поднимаемся вверх не на 76, а на 80.
|
||||
sw ra, 4(sp)
|
||||
# Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на
|
||||
# программный стек, поэтому записываем в освободившийся регистр низ
|
||||
# программного стека, и проверяем что приподнятый указатель на верхушку
|
||||
@@ -80,66 +82,70 @@ _int_handler:
|
||||
la ra, _stack_ptr
|
||||
blt sp, ra, _endless_loop
|
||||
|
||||
sw t0,12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
|
||||
# лежать регистр sp, который ранее сохранили в mscratch.
|
||||
# Мы запишем его на стек чуть позже.
|
||||
sw t1,16(sp)
|
||||
sw t2,20(sp)
|
||||
sw a0,24(sp)
|
||||
sw a1,28(sp)
|
||||
sw a2,32(sp)
|
||||
sw a3,36(sp)
|
||||
sw a4,40(sp)
|
||||
sw a5,44(sp)
|
||||
sw a6,48(sp)
|
||||
sw a7,52(sp)
|
||||
sw t3,56(sp)
|
||||
sw t4,60(sp)
|
||||
sw t5,64(sp)
|
||||
sw t6,68(sp)
|
||||
sw t0, 12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
|
||||
# лежать регистр sp, который ранее сохранили в mscratch.
|
||||
# Мы запишем его на стек чуть позже.
|
||||
sw t1, 16(sp)
|
||||
sw t2, 20(sp)
|
||||
sw a0, 24(sp)
|
||||
sw a1, 28(sp)
|
||||
sw a2, 32(sp)
|
||||
sw a3, 36(sp)
|
||||
sw a4, 40(sp)
|
||||
sw a5, 44(sp)
|
||||
sw a6, 48(sp)
|
||||
sw a7, 52(sp)
|
||||
sw t3, 56(sp)
|
||||
sw t4, 60(sp)
|
||||
sw t5, 64(sp)
|
||||
sw t6, 68(sp)
|
||||
|
||||
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
|
||||
# произойдет еще одно прерывание.
|
||||
csrr t0,mscratch
|
||||
csrr t1,mepc
|
||||
csrr a0,mcause
|
||||
sw t0,8(sp)
|
||||
sw t1,72(sp)
|
||||
sw a0,76(sp)
|
||||
# произойдет ещё одно прерывание.
|
||||
csrr t0, mscratch
|
||||
csrr t1, mepc
|
||||
csrr a0, mcause
|
||||
sw t0, 8(sp)
|
||||
sw t1, 72(sp)
|
||||
sw a0, 76(sp)
|
||||
|
||||
# Вызов высокоуровневого обработчика прерываний
|
||||
# call int_handler
|
||||
# Вызов высокоуровневого обработчика прерываний.
|
||||
# Для того чтобы программа скомпоновалась, где-то должна быть описана
|
||||
# функция именно с таким именем.
|
||||
call int_handler
|
||||
|
||||
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
|
||||
# на случай, если происходило вложенное прерывание. Для этого, мы должны
|
||||
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
|
||||
# значение нам еще необходимо для восстановления контекста, поэтому мы
|
||||
# значение нам ещё необходимо для восстановления контекста, поэтому мы
|
||||
# сохраним его в регистр a0, и будем восстанавливаться из него.
|
||||
mv a0,sp
|
||||
|
||||
lw t1,72(a0)
|
||||
addi sp,sp,80
|
||||
csrw mscratch,sp
|
||||
csrw mepc,t1
|
||||
lw ra,4(a0)
|
||||
lw sp,8(a0)
|
||||
lw t0,12(a0)
|
||||
lw t1,16(a0)
|
||||
lw t2,20(a0)
|
||||
lw a1,28(a0) # Мы пропустили a0, потому что сейчас он используется в
|
||||
# качестве указателя на верхушку стека и не может быть
|
||||
# восстановлен.
|
||||
lw a2,32(a0)
|
||||
lw a3,36(a0)
|
||||
lw a4,40(a0)
|
||||
lw a5,44(a0)
|
||||
lw a6,48(a0)
|
||||
lw a7,52(a0)
|
||||
lw t3,56(a0)
|
||||
lw t4,60(a0)
|
||||
lw t5,64(a0)
|
||||
lw t6,68(a0)
|
||||
lw a0,40(a0)
|
||||
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)
|
||||
lw t1, 16(a0)
|
||||
lw t2, 20(a0)
|
||||
lw a1, 28(a0) # Мы пропустили a0, потому что сейчас он используется в
|
||||
# качестве указателя на верхушку стека и не может быть
|
||||
# восстановлен.
|
||||
lw a2, 32(a0)
|
||||
lw a3, 36(a0)
|
||||
lw a4, 40(a0)
|
||||
lw a5, 44(a0)
|
||||
lw a6, 48(a0)
|
||||
lw a7, 52(a0)
|
||||
lw t3, 56(a0)
|
||||
lw t4, 60(a0)
|
||||
lw t5, 64(a0)
|
||||
lw t6, 68(a0)
|
||||
lw a0, 40(a0)
|
||||
|
||||
# Выход из обработчика прерывания
|
||||
mret
|
||||
|
Reference in New Issue
Block a user