/* ----------------------------------------------------------------------------- * Project Name : Architectures of Processor Systems (APS) lab work * Organization : National Research University of Electronic Technology (MIET) * Department : Institute of Microdevices and Control Systems * Author(s) : Andrei Solodovnikov * Email(s) : hepoh@org.miet.ru See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details. * ------------------------------------------------------------------------------ */ .section .boot .global _start _start: la gp, _gbl_ptr # Инициализация глобального указателя la sp, _stack_ptr # Инициализация указателя на стек # Инициализация (зануление) сегмента bss la t0, _bss_start la t1, _bss_end _bss_init_loop: blt t1, t0, _irq_config sw zero, 0(t0) addi t0, t0, 4 j _bss_init_loop # Настройка вектора (mtvec) и маски (mie) прерываний, а также указателя на стек # прерываний (mscratch). _irq_config: la t0, _int_handler li t1, -1 # -1 (все биты равны 1) означает, что разрешены все прерывания la t2, _trap_stack_ptr csrw mtvec, t0 csrw mscratch, t2 csrw mie, t1 # Вызов функции main _main_call: li a0, 0 # Передача аргументов argc и argv в main. Формально, argc должен li a1, 0 # быть больше нуля, а argv должен указывать на массив строк, # нулевой элемент которого является именем исполняемого файла, # Но для простоты реализации оба аргумента всего лишь обнулены. # Это сделано для детерминированного поведения программы в случае, # если программист будет пытаться использовать эти аргументы. # Вызов main. # Для того чтобы программа скомпоновалась, где-то должна быть описана # функция именно с таким именем. call main # Зацикливание после выхода из функции main _endless_loop: j _endless_loop # Низкоуровневый обработчик прерывания отвечает за: # * Сохранение и восстановление контекста; # * Вызов высокоуровневого обработчика с передачей id источника прерывания в # качестве аргумента. # В основе кода лежит обработчик из репозитория urv-core: # https://github.com/twlostow/urv-core/blob/master/sw/common/irq.S # Из реализации убраны сохранения нереализованных CS-регистров. Кроме того, # в реализации сохраняются только необерегаемые регистры регистрового файла. # Это сделано по причине того, что при вызове высокоуровневого обработчика # прерываний, тот будет обязан сохранить оберегаемые регистры в соответствии # с соглашением о вызовах. _int_handler: # Данная операция меняет местами регистры sp и mscratch. # В итоге указатель на стек прерываний оказывается в регистре sp, а вершина # программного стека оказывается в регистре mscratch. csrrw sp, mscratch,sp # Далее мы поднимаемся по стеку прерываний и сохраняем все регистры. addi sp, sp, -80 # Указатель на стек должен быть выровнен до 16 байт, поэтому # поднимаемся вверх не на 76, а на 80. sw ra, 4(sp) # Мы хотим убедиться, что очередное прерывание не наложит стек прерываний на # программный стек, поэтому записываем в освободившийся регистр низ # программного стека, и проверяем что приподнятый указатель на верхушку # стека прерываний не залез в программный стек. # В случае, если это произошло (произошло переполнение стека прерываний), # мы хотим остановить работу процессора, чтобы не потерять данные, которые # могут помочь нам в отладке этой ситуации. 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) # Кроме того, мы сохраняем состояние регистров прерываний на случай, если # произойдет ещё одно прерывание. csrr t0, mscratch csrr t1, mepc csrr a0, mcause sw t0, 8(sp) sw t1, 72(sp) sw a0, 76(sp) # Вызов высокоуровневого обработчика прерываний. # Для того чтобы программа скомпоновалась, где-то должна быть описана # функция именно с таким именем. call 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) 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, 24(a0) # Выход из обработчика прерывания mret