diff --git a/Labs/14. Programming/README.md b/Labs/14. Programming/README.md index 831713b..83f8100 100644 --- a/Labs/14. Programming/README.md +++ b/Labs/14. Programming/README.md @@ -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. Пример содержимого файла первичных команд с поясняющими комментариями._ diff --git a/Labs/14. Programming/startup.S b/Labs/14. Programming/startup.S index 6d54e7d..e920617 100644 --- a/Labs/14. Programming/startup.S +++ b/Labs/14. Programming/startup.S @@ -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) diff --git a/Labs/16. Coremark/startup.S b/Labs/16. Coremark/startup.S index bf2a015..e920617 100644 --- a/Labs/16. Coremark/startup.S +++ b/Labs/16. Coremark/startup.S @@ -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