|
2 | 2 |
|
3 | 3 | 
|
4 | 4 |
|
5 |
| -**13.05.2025**: Исправлен рисунок II.8-3 — исправлена опечатка в названии нижнего сигнала (`mem_wd_i` → `mem_wd_o`). |
| 5 | +**13.05.2025**: Исправлен _листинг II.14-2_ — теперь при обработке перехвата сохраняются все регистры регистрового файла, а не только оберегаемые. |
| 6 | + |
| 7 | +В опубликованном издании при реализации обработчика намеренно не было реализовано сохранение необерегаемых регистров. Так было сделано в виду неправильной интерпретации [EABI](https://github.com/riscvarchive/riscv-eabi-spec/blob/master/EABI.adoc#eabi-interrupt-handler-context-save). |
| 8 | + |
| 9 | +На самом деле, при входе в низкоуровневый обработчик необходимо сохранять весь регистровый файл. |
| 10 | + |
| 11 | +<details> |
| 12 | +<summary> Обновлённый листинг </summary> |
| 13 | + |
| 14 | +```asm |
| 15 | + .section .boot |
| 16 | +
|
| 17 | + .global _start |
| 18 | +_start: |
| 19 | + la gp, _gbl_ptr # Инициализация глобального указателя |
| 20 | + la sp, _stack_ptr # Инициализация указателя на стек |
| 21 | +
|
| 22 | +# Инициализация (зануление) сегмента bss |
| 23 | + la t0, _bss_start |
| 24 | + la t1, _bss_end |
| 25 | +_bss_init_loop: |
| 26 | + blt t1, t0, _irq_config |
| 27 | + sw zero, 0(t0) |
| 28 | + addi t0, t0, 4 |
| 29 | + j _bss_init_loop |
| 30 | +
|
| 31 | +# Настройка вектора (mtvec) и маски (mie) прерываний, а также указателя на стек |
| 32 | +# прерываний (mscratch). |
| 33 | +_irq_config: |
| 34 | + la t0, _int_handler |
| 35 | + li t1, -1 # -1 (все биты равны 1) означает, что разрешены все прерывания |
| 36 | + la t2, _trap_stack_ptr |
| 37 | + csrw mtvec, t0 |
| 38 | + csrw mscratch, t2 |
| 39 | + csrw mie, t1 |
| 40 | +
|
| 41 | +# Вызов функции main |
| 42 | +_main_call: |
| 43 | + li a0, 0 # Передача аргументов argc и argv в main. Формально, argc должен |
| 44 | + li a1, 0 # быть больше нуля, а argv должен указывать на массив строк, |
| 45 | + # нулевой элемент которого является именем исполняемого файла, |
| 46 | + # Но для простоты реализации оба аргумента всего лишь обнулены. |
| 47 | + # Это сделано для детерминированного поведения программы в случае, |
| 48 | + # если программист будет пытаться использовать эти аргументы. |
| 49 | +
|
| 50 | + # Вызов main. |
| 51 | + # Для того чтобы программа скомпоновалась, где-то должна быть описана |
| 52 | + # функция именно с таким именем. |
| 53 | + call main |
| 54 | +# Зацикливание после выхода из функции main |
| 55 | +_endless_loop: |
| 56 | + j _endless_loop |
| 57 | +
|
| 58 | +# Низкоуровневый обработчик прерывания отвечает за: |
| 59 | +# * Сохранение и восстановление контекста; |
| 60 | +# * Вызов высокоуровневого обработчика с передачей id источника прерывания в |
| 61 | +# качестве аргумента. |
| 62 | +# В основе кода лежит обработчик из репозитория urv-core: |
| 63 | +# https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S |
| 64 | +# Из реализации убраны сохранения нереализованных CS-регистров. |
| 65 | +_int_handler: |
| 66 | + # Данная операция меняет местами регистры sp и mscratch. |
| 67 | + # В итоге указатель на стек прерываний оказывается в регистре sp, а вершина |
| 68 | + # программного стека оказывается в регистре mscratch. |
| 69 | + csrrw sp, mscratch, sp |
| 70 | +
|
| 71 | + # Далее мы поднимаемся по стеку прерываний и сохраняем все регистры. |
| 72 | + addi sp, sp, -144 # Указатель на стек должен быть выровнен до 16 байт, поэтому |
| 73 | + # поднимаемся вверх не на 136, а на 144. |
| 74 | + sw ra, 4(sp) |
| 75 | + # Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на |
| 76 | + # программный стек, поэтому записываем в освободившийся регистр низ |
| 77 | + # программного стека, и проверяем что приподнятый указатель на верхушку |
| 78 | + # стека прерываний не залез в программный стек. |
| 79 | + # В случае, если это произошло (произошло переполнение стека прерываний), |
| 80 | + # мы хотим остановить работу процессора, чтобы не потерять данные, которые |
| 81 | + # могут помочь нам в отладке этой ситуации. |
| 82 | + la ra, _stack_ptr |
| 83 | + blt sp, ra, _endless_loop |
| 84 | +
|
| 85 | + sw gp,12(sp) # Мы перепрыгнули через смещение 8, поскольку там должен |
| 86 | + # лежать регистр sp, который ранее сохранили в mscratch. |
| 87 | + # Мы запишем его на стек чуть позже. |
| 88 | + sw tp,16(sp) |
| 89 | + sw t0,20(sp) |
| 90 | + sw t1,24(sp) |
| 91 | + sw t2,28(sp) |
| 92 | + sw s0,32(sp) |
| 93 | + sw s1,36(sp) |
| 94 | + sw a0,40(sp) |
| 95 | + sw a1,44(sp) |
| 96 | + sw a2,48(sp) |
| 97 | + sw a3,52(sp) |
| 98 | + sw a4,56(sp) |
| 99 | + sw a5,60(sp) |
| 100 | + sw a6,64(sp) |
| 101 | + sw a7,68(sp) |
| 102 | + sw s2,72(sp) |
| 103 | + sw s3,76(sp) |
| 104 | + sw s4,80(sp) |
| 105 | + sw s5,84(sp) |
| 106 | + sw s6,88(sp) |
| 107 | + sw s7,92(sp) |
| 108 | + sw s8,96(sp) |
| 109 | + sw s9,100(sp) |
| 110 | + sw s10,104(sp) |
| 111 | + sw s11,108(sp) |
| 112 | + sw t3,112(sp) |
| 113 | + sw t4,116(sp) |
| 114 | + sw t5,120(sp) |
| 115 | + sw t6,124(sp) |
| 116 | +
|
| 117 | + # Кроме того, мы сохраняем состояние регистров прерываний на случай, если |
| 118 | + # произойдет ещё одно прерывание. |
| 119 | + csrr t0,mscratch |
| 120 | + csrr t1,mepc |
| 121 | + csrr a0,mcause |
| 122 | + sw t0,8(sp) |
| 123 | + sw t1,128(sp) |
| 124 | + sw a0,132(sp) |
| 125 | +
|
| 126 | + # Вызов высокоуровневого обработчика прерываний. |
| 127 | + # Для того чтобы программа скомпоновалась, где-то должна быть описана |
| 128 | + # функция именно с таким именем. |
| 129 | + call int_handler |
| 130 | +
|
| 131 | + # Восстановление контекста. В первую очередь мы хотим восстановить CS-регистры, |
| 132 | + # на случай, если происходило вложенное прерывание. Для этого, мы должны |
| 133 | + # вернуть исходное значение указателя стека прерываний. Однако его нынешнее |
| 134 | + # значение нам ещё необходимо для восстановления контекста, поэтому мы |
| 135 | + # сохраним его в регистр a0, и будем восстанавливаться из него. |
| 136 | + mv a0,sp |
| 137 | +
|
| 138 | + lw t1,128(a0) |
| 139 | + addi sp,sp,144 |
| 140 | + csrw mscratch,sp |
| 141 | + csrw mepc,t1 |
| 142 | + lw ra,4(a0) |
| 143 | + lw sp,8(a0) |
| 144 | + lw gp,12(a0) |
| 145 | + lw tp,16(a0) |
| 146 | + lw t0,20(a0) |
| 147 | + lw t1,24(a0) |
| 148 | + lw t2,28(a0) |
| 149 | + lw s0,32(a0) |
| 150 | + lw s1,36(a0) |
| 151 | + lw a1,44(a0) # Мы пропустили a0, потому что сейчас он используется в |
| 152 | + # качестве указателя на верхушку стека и не может быть |
| 153 | + # восстановлен. |
| 154 | + lw a2,48(a0) |
| 155 | + lw a3,52(a0) |
| 156 | + lw a4,56(a0) |
| 157 | + lw a5,60(a0) |
| 158 | + lw a6,64(a0) |
| 159 | + lw a7,68(a0) |
| 160 | + lw s2,72(a0) |
| 161 | + lw s3,76(a0) |
| 162 | + lw s4,80(a0) |
| 163 | + lw s5,84(a0) |
| 164 | + lw s6,88(a0) |
| 165 | + lw s7,92(a0) |
| 166 | + lw s8,96(a0) |
| 167 | + lw s9,100(a0) |
| 168 | + lw s10,104(a0) |
| 169 | + lw s11,108(a0) |
| 170 | + lw t3,112(a0) |
| 171 | + lw t4,116(a0) |
| 172 | + lw t5,120(a0) |
| 173 | + lw t6,124(a0) |
| 174 | + lw a0,40(a0) |
| 175 | +
|
| 176 | + # Выход из обработчика прерывания |
| 177 | + mret |
| 178 | +
|
| 179 | +``` |
| 180 | + |
| 181 | +_Листинг 2. Пример содержимого файла первичных команд с поясняющими комментариями._ |
| 182 | + |
| 183 | +</details> |
| 184 | + |
| 185 | +--- |
| 186 | + |
| 187 | +**13.05.2025**: _Исправлен рисунок II.8-3_ — опечатка в названии нижнего сигнала (`mem_wd_i` → `mem_wd_o`). |
6 | 188 |
|
7 | 189 | <details>
|
8 | 190 | <summary> Обновлённый рисунок </summary>
|
9 | 191 |
|
10 | 192 | 
|
11 | 193 |
|
12 |
| -Рисунок II.8-3. Временна́я диаграмма запросов на запись со стороны ядра и сигнала mem_wd_o. |
| 194 | +_Рисунок II.8-3. Временна́я диаграмма запросов на запись со стороны ядра и сигнала mem_wd_o._ |
13 | 195 |
|
14 | 196 | </details>
|
15 | 197 |
|
16 | 198 | ---
|
17 | 199 |
|
18 |
| -**29.03.2025**: Исправлен рисунок II.4-4 — убрана логика безусловного перехода, т.к. она должна была появиться только в следующем параграфе. |
| 200 | +**29.03.2025**: _Исправлен рисунок II.4-4_ — убрана логика безусловного перехода, т.к. она должна была появиться только в следующем параграфе. |
19 | 201 |
|
20 | 202 | <details>
|
21 | 203 | <summary> Обновлённый рисунок </summary>
|
22 | 204 |
|
23 | 205 | 
|
24 | 206 |
|
25 |
| -Рисунок II.4-4. Реализация условного перехода. |
| 207 | +_Рисунок II.4-4. Реализация условного перехода._ |
26 | 208 |
|
27 | 209 | </details>
|
0 commit comments