@@ -41,7 +41,11 @@ _main_call:
41
41
# нулевой элемент которого является именем исполняемого файла,
42
42
# Но для простоты реализации оба аргумента всего лишь обнулены.
43
43
# Это сделано для детерминированного поведения программы в случае,
44
- # если будет пытаться использовать эти аргументы.
44
+ # если программист будет пытаться использовать эти аргументы.
45
+
46
+ # Вызов main.
47
+ # Для того чтобы программа скомпоновалась, где-то должна быть описана
48
+ # функция именно с таким именем.
45
49
call main
46
50
# Зацикливание после выхода из функции main
47
51
_endless_loop:
@@ -54,22 +58,20 @@ _endless_loop:
54
58
# В основе кода лежит обработчик из репозитория urv-core:
55
59
# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S
56
60
# Из реализации убраны сохранения нереализованных 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
+ # с соглашением о вызовах.
63
65
_int_handler:
64
66
# Данная операция меняет местами регистры sp и mscratch.
65
67
# В итоге указатель на стек прерываний оказывается в регистре sp , а вершина
66
68
# программного стека оказывается в регистре mscratch.
67
- csrrw sp ,mscratch,sp
69
+ csrrw sp , mscratch,sp
68
70
69
71
# Далее мы поднимаемся по стеку прерываний и сохраняем все регистры.
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 )
73
75
# Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на
74
76
# программный стек, поэтому записываем в освободившийся регистр низ
75
77
# программного стека, и проверяем что приподнятый указатель на верхушку
@@ -80,66 +82,70 @@ _int_handler:
80
82
la ra, _stack_ptr
81
83
blt sp , ra, _endless_loop
82
84
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 )
100
102
101
103
# Кроме того, мы сохраняем состояние регистров прерываний на случай, если
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 )
109
111
110
- # Вызов высокоуровневого обработчика прерываний
111
- # call int_handler
112
+ # Вызов высокоуровневого обработчика прерываний.
113
+ # Для того чтобы программа скомпоновалась, где-то должна быть описана
114
+ # функция именно с таким именем.
115
+ call int_handler
112
116
113
117
# Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры,
114
118
# на случай, если происходило вложенное прерывание. Для этого, мы должны
115
119
# вернуть исходное значение указателя стека прерываний. Однако его нынешнее
116
- # значение нам еще необходимо для восстановления контекста, поэтому мы
120
+ # значение нам ещё необходимо для восстановления контекста, поэтому мы
117
121
# сохраним его в регистр a0 , и будем восстанавливаться из него.
118
122
mv a0 ,sp
119
123
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 )
143
149
144
150
# Выход из обработчика прерывания
145
151
mret
0 commit comments