Skip to content

Commit eca95fe

Browse files
committed
ЛР14,16. Дополнение startup-файла
- добавлен код восстановления CS-регистра mcause - в более явном виде описано почему в низкоуровневом обработчике на стек сохраняется не весь регистровый файл.
1 parent 6f74ab5 commit eca95fe

File tree

3 files changed

+131
-124
lines changed

3 files changed

+131
-124
lines changed

Labs/14. Programming/README.md

Lines changed: 56 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -361,21 +361,19 @@ _endless_loop:
361361
# В основе кода лежит обработчик из репозитория urv-core:
362362
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
363363
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
364-
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
365-
# сохранение контекста, что и при программном вызове (EABI подразумевает ещё
366-
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
367-
# файл.
368-
# Документ:
369-
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
364+
# в реализации сохраняются только необерегаемые регистры регистрового файла.
365+
# Это сделано по причине того, что при вызове высокоуровневого обработчика
366+
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
367+
# с соглашением о вызовах.
370368
_int_handler:
371369
# Данная операция меняет местами регистры sp и mscratch.
372370
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
373371
# программного стека оказывается в регистре mscratch.
374-
csrrw sp, mscratch, sp
372+
csrrw sp, mscratch,sp
375373
376374
# Далее мы поднимаемся по стеку прерываний и сохраняем все регистры.
377-
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
378-
# поднимаемся вверх не на 76, а на 80.
375+
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
376+
# поднимаемся вверх не на 76, а на 80.
379377
sw ra, 4(sp)
380378
# Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на
381379
# программный стек, поэтому записываем в освободившийся регистр низ
@@ -387,32 +385,32 @@ _int_handler:
387385
la ra, _stack_ptr
388386
blt sp, ra, _endless_loop
389387
390-
sw t0,12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
391-
# лежать регистр sp, который ранее сохранили в mscratch.
392-
# Мы запишем его на стек чуть позже.
393-
sw t1,16(sp)
394-
sw t2,20(sp)
395-
sw a0,24(sp)
396-
sw a1,28(sp)
397-
sw a2,32(sp)
398-
sw a3,36(sp)
399-
sw a4,40(sp)
400-
sw a5,44(sp)
401-
sw a6,48(sp)
402-
sw a7,52(sp)
403-
sw t3,56(sp)
404-
sw t4,60(sp)
405-
sw t5,64(sp)
406-
sw t6,68(sp)
388+
sw t0, 12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
389+
# лежать регистр sp, который ранее сохранили в mscratch.
390+
# Мы запишем его на стек чуть позже.
391+
sw t1, 16(sp)
392+
sw t2, 20(sp)
393+
sw a0, 24(sp)
394+
sw a1, 28(sp)
395+
sw a2, 32(sp)
396+
sw a3, 36(sp)
397+
sw a4, 40(sp)
398+
sw a5, 44(sp)
399+
sw a6, 48(sp)
400+
sw a7, 52(sp)
401+
sw t3, 56(sp)
402+
sw t4, 60(sp)
403+
sw t5, 64(sp)
404+
sw t6, 68(sp)
407405
408406
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
409407
# произойдет ещё одно прерывание.
410-
csrr t0,mscratch
411-
csrr t1,mepc
412-
csrr a0,mcause
413-
sw t0,8(sp)
414-
sw t1,72(sp)
415-
sw a0,76(sp)
408+
csrr t0, mscratch
409+
csrr t1, mepc
410+
csrr a0, mcause
411+
sw t0, 8(sp)
412+
sw t1, 72(sp)
413+
sw a0, 76(sp)
416414
417415
# Вызов высокоуровневого обработчика прерываний.
418416
# Для того чтобы программа скомпоновалась, где-то должна быть описана
@@ -426,33 +424,36 @@ _int_handler:
426424
# сохраним его в регистр a0, и будем восстанавливаться из него.
427425
mv a0,sp
428426
429-
lw t1,72(a0)
430-
addi sp,sp,80
431-
csrw mscratch,sp
432-
csrw mepc,t1
433-
lw ra,4(a0)
434-
lw sp,8(a0)
435-
lw t0,12(a0)
436-
lw t1,16(a0)
437-
lw t2,20(a0)
438-
lw a1,28(a0) # Мы пропустили a0, потому что сейчас он используется в
439-
# качестве указателя на верхушку стека и не может быть
440-
# восстановлен.
441-
lw a2,32(a0)
442-
lw a3,36(a0)
443-
lw a4,40(a0)
444-
lw a5,44(a0)
445-
lw a6,48(a0)
446-
lw a7,52(a0)
447-
lw t3,56(a0)
448-
lw t4,60(a0)
449-
lw t5,64(a0)
450-
lw t6,68(a0)
451-
lw a0,40(a0)
427+
lw t1, 72(a0)
428+
lw t2, 76(a0)
429+
addi sp, sp, 80
430+
csrw mscratch, sp
431+
csrw mepc, t1
432+
csrw mcause, t2
433+
lw ra, 4(a0)
434+
lw sp, 8(a0)
435+
lw t0, 12(a0)
436+
lw t1, 16(a0)
437+
lw t2, 20(a0)
438+
lw a1, 28(a0) # Мы пропустили a0, потому что сейчас он используется в
439+
# качестве указателя на верхушку стека и не может быть
440+
# восстановлен.
441+
lw a2, 32(a0)
442+
lw a3, 36(a0)
443+
lw a4, 40(a0)
444+
lw a5, 44(a0)
445+
lw a6, 48(a0)
446+
lw a7, 52(a0)
447+
lw t3, 56(a0)
448+
lw t4, 60(a0)
449+
lw t5, 64(a0)
450+
lw t6, 68(a0)
451+
lw a0, 40(a0)
452452
453453
# Выход из обработчика прерывания
454454
mret
455455
456+
456457
```
457458

458459
_Листинг 2. Пример содержимого файла первичных команд с поясняющими комментариями._

Labs/14. Programming/startup.S

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,10 @@ _endless_loop:
5858
# В основе кода лежит обработчик из репозитория urv-core:
5959
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
6060
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
61-
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
62-
# сохранение контекста, что и при программном вызове (EABI подразумевает еще
63-
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
64-
# файл.
65-
# Документ:
66-
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
61+
# в реализации сохраняются только необерегаемые регистры регистрового файла.
62+
# Это сделано по причине того, что при вызове высокоуровневого обработчика
63+
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
64+
# с соглашением о вызовах.
6765
_int_handler:
6866
# Данная операция меняет местами регистры sp и mscratch.
6967
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
@@ -103,7 +101,7 @@ _int_handler:
103101
sw t6, 68(sp)
104102

105103
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
106-
# произойдет еще одно прерывание.
104+
# произойдет ещё одно прерывание.
107105
csrr t0, mscratch
108106
csrr t1, mepc
109107
csrr a0, mcause
@@ -119,14 +117,16 @@ _int_handler:
119117
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
120118
# на случай, если происходило вложенное прерывание. Для этого, мы должны
121119
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
122-
# значение нам еще необходимо для восстановления контекста, поэтому мы
120+
# значение нам ещё необходимо для восстановления контекста, поэтому мы
123121
# сохраним его в регистр a0, и будем восстанавливаться из него.
124122
mv a0,sp
125123

126124
lw t1, 72(a0)
125+
lw t2, 76(a0)
127126
addi sp, sp, 80
128127
csrw mscratch, sp
129128
csrw mepc, t1
129+
csrw mcause, t2
130130
lw ra, 4(a0)
131131
lw sp, 8(a0)
132132
lw t0, 12(a0)

Labs/16. Coremark/startup.S

Lines changed: 67 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,11 @@ _main_call:
4141
# нулевой элемент которого является именем исполняемого файла,
4242
# Но для простоты реализации оба аргумента всего лишь обнулены.
4343
# Это сделано для детерминированного поведения программы в случае,
44-
# если будет пытаться использовать эти аргументы.
44+
# если программист будет пытаться использовать эти аргументы.
45+
46+
# Вызов main.
47+
# Для того чтобы программа скомпоновалась, где-то должна быть описана
48+
# функция именно с таким именем.
4549
call main
4650
# Зацикливание после выхода из функции main
4751
_endless_loop:
@@ -54,22 +58,20 @@ _endless_loop:
5458
# В основе кода лежит обработчик из репозитория urv-core:
5559
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
5660
# Из реализации убраны сохранения нереализованных CS-регистров. Кроме того,
57-
# судя по документу приведенному ниже, обычное ABI подразумевает такое же
58-
# сохранение контекста, что и при программном вызове (EABI подразумевает еще
59-
# меньшее сохранение контекста), поэтому нет нужды сохранять весь регистровый
60-
# файл.
61-
# Документ:
62-
# https://github.com/riscv-non-isa/riscv-eabi-spec/blob/master/EABI.adoc
61+
# в реализации сохраняются только необерегаемые регистры регистрового файла.
62+
# Это сделано по причине того, что при вызове высокоуровневого обработчика
63+
# прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии
64+
# с соглашением о вызовах.
6365
_int_handler:
6466
# Данная операция меняет местами регистры sp и mscratch.
6567
# В итоге указатель на стек прерываний оказывается в регистре sp, а вершина
6668
# программного стека оказывается в регистре mscratch.
67-
csrrw sp,mscratch,sp
69+
csrrw sp, mscratch,sp
6870

6971
# Далее мы поднимаемся по стеку прерываний и сохраняем все регистры.
70-
addi sp,sp,-80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
71-
# поднимаемся вверх не на 76, а на 80.
72-
sw ra,4(sp)
72+
addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому
73+
# поднимаемся вверх не на 76, а на 80.
74+
sw ra, 4(sp)
7375
# Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на
7476
# программный стек, поэтому записываем в освободившийся регистр низ
7577
# программного стека, и проверяем что приподнятый указатель на верхушку
@@ -80,66 +82,70 @@ _int_handler:
8082
la ra, _stack_ptr
8183
blt sp, ra, _endless_loop
8284

83-
sw t0,12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
84-
# лежать регистр sp, который ранее сохранили в mscratch.
85-
# Мы запишем его на стек чуть позже.
86-
sw t1,16(sp)
87-
sw t2,20(sp)
88-
sw a0,24(sp)
89-
sw a1,28(sp)
90-
sw a2,32(sp)
91-
sw a3,36(sp)
92-
sw a4,40(sp)
93-
sw a5,44(sp)
94-
sw a6,48(sp)
95-
sw a7,52(sp)
96-
sw t3,56(sp)
97-
sw t4,60(sp)
98-
sw t5,64(sp)
99-
sw t6,68(sp)
85+
sw t0, 12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен
86+
# лежать регистр sp, который ранее сохранили в mscratch.
87+
# Мы запишем его на стек чуть позже.
88+
sw t1, 16(sp)
89+
sw t2, 20(sp)
90+
sw a0, 24(sp)
91+
sw a1, 28(sp)
92+
sw a2, 32(sp)
93+
sw a3, 36(sp)
94+
sw a4, 40(sp)
95+
sw a5, 44(sp)
96+
sw a6, 48(sp)
97+
sw a7, 52(sp)
98+
sw t3, 56(sp)
99+
sw t4, 60(sp)
100+
sw t5, 64(sp)
101+
sw t6, 68(sp)
100102

101103
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
102-
# произойдет еще одно прерывание.
103-
csrr t0,mscratch
104-
csrr t1,mepc
105-
csrr a0,mcause
106-
sw t0,8(sp)
107-
sw t1,72(sp)
108-
sw a0,76(sp)
104+
# произойдет ещё одно прерывание.
105+
csrr t0, mscratch
106+
csrr t1, mepc
107+
csrr a0, mcause
108+
sw t0, 8(sp)
109+
sw t1, 72(sp)
110+
sw a0, 76(sp)
109111

110-
# Вызов высокоуровневого обработчика прерываний
111-
# call int_handler
112+
# Вызов высокоуровневого обработчика прерываний.
113+
# Для того чтобы программа скомпоновалась, где-то должна быть описана
114+
# функция именно с таким именем.
115+
call int_handler
112116

113117
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
114118
# на случай, если происходило вложенное прерывание. Для этого, мы должны
115119
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
116-
# значение нам еще необходимо для восстановления контекста, поэтому мы
120+
# значение нам ещё необходимо для восстановления контекста, поэтому мы
117121
# сохраним его в регистр a0, и будем восстанавливаться из него.
118122
mv a0,sp
119123

120-
lw t1,72(a0)
121-
addi sp,sp,80
122-
csrw mscratch,sp
123-
csrw mepc,t1
124-
lw ra,4(a0)
125-
lw sp,8(a0)
126-
lw t0,12(a0)
127-
lw t1,16(a0)
128-
lw t2,20(a0)
129-
lw a1,28(a0) # Мы пропустили a0, потому что сейчас он используется в
130-
# качестве указателя на верхушку стека и не может быть
131-
# восстановлен.
132-
lw a2,32(a0)
133-
lw a3,36(a0)
134-
lw a4,40(a0)
135-
lw a5,44(a0)
136-
lw a6,48(a0)
137-
lw a7,52(a0)
138-
lw t3,56(a0)
139-
lw t4,60(a0)
140-
lw t5,64(a0)
141-
lw t6,68(a0)
142-
lw a0,40(a0)
124+
lw t1, 72(a0)
125+
lw t2, 76(a0)
126+
addi sp, sp, 80
127+
csrw mscratch, sp
128+
csrw mepc, t1
129+
csrw mcause, t2
130+
lw ra, 4(a0)
131+
lw sp, 8(a0)
132+
lw t0, 12(a0)
133+
lw t1, 16(a0)
134+
lw t2, 20(a0)
135+
lw a1, 28(a0) # Мы пропустили a0, потому что сейчас он используется в
136+
# качестве указателя на верхушку стека и не может быть
137+
# восстановлен.
138+
lw a2, 32(a0)
139+
lw a3, 36(a0)
140+
lw a4, 40(a0)
141+
lw a5, 44(a0)
142+
lw a6, 48(a0)
143+
lw a7, 52(a0)
144+
lw t3, 56(a0)
145+
lw t4, 60(a0)
146+
lw t5, 64(a0)
147+
lw t6, 68(a0)
148+
lw a0, 40(a0)
143149

144150
# Выход из обработчика прерывания
145151
mret

0 commit comments

Comments
 (0)