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:

Консоль-это устройство, которое может вводить байты с клавиатуры и выводить байты на текстовый экран:

5.png

Когда устройство готово к 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 11

Device 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

[ATTACH]

HSE/ArchitectureASM/10_Interrupts/Conspect (last edited 2020-06-24 17:30:32 by FrBrGeorge)