10.1 Conspect (ru)
Прерывания в отличие от исключений имеют внешний источник. Происходят потому что-то произошло снаружи. Нужно чтобы не заниматься ”тупым” поллингом. Прерывания асинхронны. Обрабатываются тем же обработчиком что и исключения.
Архитектура вашей машины должна быть так устроена чтобы в какой бы момент не произошло прерывание, переделывать инструкцию которая только что выполнялась было безопасно.
Первая проблема – понять что прерывание произошло.
Вторая проблема - поскольку прерывания могут произойти одновременно, нужно иметь возможность обработать 2,3 и тд. прерываний.
За обработку прерываний отвечает регистр с0 .
Когда происходят прерывания, прерывание имеет номер 0.
Все регистры должны быть сохранены (включая $at), кроме $k0 и $k1.
Прерывания должны быть отключены как можно скорее (для предотвращения параллельной обработки). Не полагайтесь на $sp (он может быть поврежден). Обычно предоставляется отдельный стек ядра. Исключения различны для обработки. При обработке прерывания «код исключения» поле регистра Cause C0 равен 0.
Прерывание должно быть обработано как можно быстрее, чем меньше поток выполнения остается в пространстве ядра, тем лучше.
Чтобы другие устройства работали нормально перед выходом сделать: Чистое поле Cause, Восстановить все регистры, Включить прерывания.
Для этого рассмотрим код:
.data
msg:    .asciiz "Tick\n"
.text
        mfc0    $a0 $12                 # read from the status register
        ori     $a0 0xff11              # enable all interrupts
        mtc0    $a0 $12                 # write back to the status register
        
        # Byte value at address 0xFFFF0012 : command row number of hexadecimal keyboard (bit 0 to 3) and enable keyboard interrupt (bit 7) 
        li      $t0 0x80
        sb      $t0 0xffff0012
        
loop:   li      $v0 4
        la      $a0 msg
        syscall
        li      $v0 32
        li      $a0 1000
        syscall
        j       loopВ марсе нельзя генерировать прерывания по таймеру, но можно генерировать прерывание каждую 30 инструкцию. Код:
.macro  push    %reg
        addiu   $sp $sp -4
        sw      %reg ($sp)
.end_macro
.macro  pop     %reg
        lw      %reg ($sp)
        addiu   $sp $sp 4
.end_macro
.data
msg:    .asciiz " tick\n"
.text
        mfc0    $a0 $12                 # read from the status register
        ori     $a0 0xff11              # enable all interrupts
        mtc0    $a0 $12                 # write back to the status register
        
        # Byte value at address 0xFFFF0012 : command row number of hexadecimal keyboard (bit 0 to 3) and enable keyboard interrupt (bit 7) 
        li      $t0 1
        sb      $t0 0xffff0013
        
        li      $t0 0
loop:   li      $v0 1
        move    $a0 $t0
        syscall
        li      $v0 4
        la      $a0 msg
        syscall
        li      $v0 32
        li      $a0 1000
        syscall
        addiu   $t0 $t0 1
        j       loop
.macro  keep    %reg %addr
        move    $k0 %reg
        sw      $k0 %addr
.end_macro
.macro  undo    %reg %addr
        lw      $k0 %addr
        move    %reg $k0
.end_macro
.kdata
_at:    .word   0       # keep $at
_sp:    .word   0       # keep $sp
imsg:   .asciiz "-!-"
.ktext  0x80000180
        mfc0    $k0 $12         # !! disable interrupts
        andi    $k0 $k0 0xfffe  # !!
        mtc0    $k0 $12         # !!
        
        keep    $at _at         # why not use "sw $at _at" ? :)
        keep    $sp _sp         # user stack
        li      $sp 0x90100000  # MARS restriction; we can use stack from now
        push    $a0
        push    $v0
        mfc0    $k0 $13         # Cause register
        srl     $a0 $k0 2       # Extract ExcCode Field
        andi    $a0 $a0 0x1f
        bne     $a0 $zero kexc  # Exception Code is 0 for interrupts
kint:   # Just mark the interrupt
        li      $v0 4
        la      $a0 imsg
        syscall
        b       intret
        
kexc:   # No exceptions in the program, but just in case of one
        b       exret
exret:  mfc0    $v0 $14
        addi    $v0 $v0 4       # Return to next instruction
        mtc0    $v0 $14
intret:
        pop     $v0
        pop     $a0
        undo    $sp _sp
        undo    $at _at
        mfc0    $k0 $12         # Set Status register
        ori     $k0 0x01        # Interrupts enabled
        mtc0    $k0 $12         # write back to status  
        mtc0    $zero $13       # clean Cause
        eretЕсли засовывать какую-либо логику в ядро, Вы навсегда застрянете в этом ядре.
Keyboard and Display MMIO Simulator:
Консоль-это устройство, которое может вводить байты с клавиатуры и выводить байты на текстовый экран:
 
 
Когда устройство готово к trausmit / receive, соответствующий бит ready устанавливается как 1.
Когда RcC ready равен 0, клавиша не была нажата или нажатие клавиши еще не обработано консолью. Когда TxC ready равен 0, консоль не может выполнить вывод . Например, занята передачей предыдущего байта.
Устройство является (намеренно) медленным, поэтому часто неготовым.
Пример консольного пуллинга:
loop:   lb      $t0 0xffff0000          # check input ready
        andi    $t0 $t0 1               # is it?
        beqz    $t0 loop                # to check again
        lb      $a0 0xffff0004          # read character
        li      $v0 11                  # print it
        syscall
        b       loopТакже рассмотрим сonsole interrupts.
      li      $a0 2                   
        sw      $a0 0xffff0000     # enable keyboard interrupt
        li      $a0 0
loop:   beqz    $a0 loop           # infinite loop
        beq     $a0 0x1b done      # finish when pressing ESC
        li      $v0 11             # print character stored by handler
        syscall
        li      $a0 0              # make $a0 zer0 again
        j       loop
done:   li      $v0 10
        syscall
.ktext  0x80000180                 # THIS IS DIRTY!
        lw      $a0 0xffff0004     # store input to $a0Также рассмотрим более чистую реализацию: более или менее справедливый обработчик, программа большую часть времени делает бессмысленные вещи, но периодически проверяет, не было ли чего-то нажато на клавиатуре.
.text
        .globl main
main:
        mfc0    $a0 $12                 # read from the status register
        ori     $a0 0xff11              # enable all interrupts
        mtc0    $a0 $12                 # write back to the status register
        li      $a0 2                   # enable keyboard interrupt
        sw      $a0 0xffff0000
here:
        jal     sleep
        lw      $a0 ($gp)               # print key stored in ($gp)
        beqz  $a0 here    # no keypress
        beq     $a0 0x1b done           # ESC terminates
        li      $v0 1
        syscall
        sw  $zero ($gp)
        j       here
done:   li      $v0 10
        syscall
.eqv    ZZZ     100000
sleep:  li      $t0 ZZZ                 # Do nothing
tormo0: subi    $t0 $t0 1
        blez    $t0 tormo1
        j       tormo0
tormo1: jr      $ra
.ktext  0x80000180                      # kernel code starts here
        mfc0    $k0 $12                 # !! disable interrupts
        andi    $k0 $k0 0xfffe          # !!
        mtc0    $k0 $12                 # !!
        move    $k1 $at                 # save $at. User programs are not supposed to touch $k0 and $k1
        sw      $v0 s1                  # We need to use these registers
        sw      $a0 s2                  # not using the stack
        mfc0    $k0 $13                 # Cause register
        srl     $a0 $k0 2               # Extract ExcCode Field
        andi    $a0 $a0 0x1f
        bne     $a0 $zero kexc          # Exception Code 0 is I/O. Only processing I/O here
        lw      $a0 0xffff0004          # get the input key
        sw      $a0 ($gp)               # store key
        li      $a0 '.'                 # Show that we handled the interrupt
        li      $v0 11
        syscall
        j       kdone
kexc:   mfc0    $v0 $14                 # No exceptions in the program, but just in case of one
        addi    $v0 $v0 4               # Return to next instruction
        mtc0    $v0 $14
kdone:
        lw      $v0 s1                  # Restore other registers
        lw      $a0 s2
        move    $at $k1                 # Restore $at
        mtc0    $zero $13
        mfc0    $k0 $12                 # Set Status register
        ori     $k0 0x01                # Interrupts enabled
        mtc0    $k0 $12                 # write back to status
        eret
.kdata
s1:     .word 10
s2:     .word 11Device control:
Некоторые устройства, например принтеры, консоли, модемы и т. д. не могут полностью контролироваться специальными регистрами MMIO. Вместо этого они интерпретируют полученные данные. Эти данные называются» управляющими символами устройства " (или управляющей последовательностью).
Клавиатура и дисплей - симулятор:
байт выхода №12 - отсутствие контрольных данных - чистый экран
выходной байт 7-позиционирование курсора, управляющие данные: столбец (биты 31-20), строка (биты 19-8).
Показать “@” на экране:
.macro  text    %reg
wait:   lb      $a0 0xffff0008  # wait until output is ready
        andi    $a0 $a0 1
        beqz    $a0 wait        # if not, wait again
        move    $a0 %reg
        sw      $a0 0xffff000c
.end_macro
        
.macro  pos     %x %y %c
        li      $a0 %x
        sll     $a0 $a0 20      # X-coordinate
        li      $a1 %y
        sll     $a1 $a1 8       # Y-coordinate
        or      $a0 $a0 $a1
        ori     $a1 $a0 7
        text    $a1             # cursor poitioning
        li      $a1 %c
        text    $a1             # character output
.end_macro
.text
        li      $s1 12
        text    $s1
        pos     1 1 '@'
        pos     6 2 '@'
        pos     12 4 '@'
        pos     15 6 '@'
        nop
        nop
        nop
        nop
        nop
![[ПРИКРЕПЛЁННЫЙ ФАЙЛ] [ПРИКРЕПЛЁННЫЙ ФАЙЛ]](/moin_static197/modernized/img/attach.png)