Опубликован: 04.08.2025 | Доступ: свободный | Студентов: 7 / 0 | Длительность: 02:58:00
Лекция 5:

Разработка цифровых ИС на примере микроконтроллерного ядра SCR1 - прgграммное обеспечение

Из секции .data:

 .align 4; message: .string "Core is ready for work!\n"

Побайтовый вывод отладочного сообщения осуществляется следующим образом:

  • Устанавливается счётчик выведенных байт и их общее количество
  • Проверяется статус очереди TX. Если очередь занята, остаётся в цикле проверки. Если очередь свободна, то считывается заданный символ строки и загружается в TX
  • Инкрементируется счётчик байт (a0) и указателя на строку (a6).

После вывода сообщения ядро входит в бесконечный цикл (j .) в ожидании прерывания.

     /* Byte count */
     li a0,
     0 li s10, 24
1:
      li t0, SC1F_UART_ST_TRDY
      lw t1, SC1F_UART_STATUS(s0)
      and t1, t1, t0
      beqz t1, 1b

      lbu t0, 0(a6)
      sb t0, SC1F_UART_TXD(s0)

     addi a6, a6, 1
     addi a0, a0, 1
     bne a0, s10, 1b 

Программный код загрузчика: Обработчик прерываний

.align 4
trap_vector:

              li t5, 0x10000
              bne a7, t5, 1f

              csrr s0, mcause
              li t0, 0xfff
             and s0, s0, t0

             li t6, CAUSE_MACHINE_ECALL
             beq s0, t6, transmit_exit_code
1:
             j mtvec_handler

Договоримся, что в рамках наших тестов прерывание от инструкции ecall и значение регистра a7, равное 0x10000 означает, что требуется перейти к выводу сообщения об успешности выполнения нашего кода.

В случае, если эти условия не выполняются, совершается переход на mtvec_handler, в котором будут обрабатываться остальные прерывания.

.align 4
mtvec_handler:

           csrr s1, mcause
           /* Mask the mcause */
           li t0, (1 << (__riscv_xlen - 1)) | 0xFFF
           and s1, s1, t0

            /* Compare cause with external interrupt */
            li t0, (1 << (__riscv_xlen - 1)) | IRQ_M_EXT
            beq s1, t0, uart_handler

Причина возникновения прерывания или исключения содержится в регистре mcause. Значение mcause маскируется (нужны только младшие 12 бит и старший (XLEN-1), сигнализирующий о прерывании.

Здесь сравнивается значение mcause и интересующий нас код внешнего прерывания. Если они совпадают, совершается переход по адресу uart_handler.

Далее представлены обработчики для других значений mcause. В случае их обнаружения прерываний или исключений, отличных от внешних, будет выведено сообщение об ошибке.

При желании можно прописать поведение ядра в случае возникновения этих прерываний/исключений. Пример для исключения misaligned fetch:

     li t0, (1 << (__riscv_xlen - 1)) | CAUSE_MISALIGNED_FETCH
     beq s1, t0, misaligned_fetch
…
misaligned_fetch:
     li gp, 0x1 j
     1f 
…
1:
    j fail

Программный код загрузчика Обработчик прерываний UART

Проверка наличия прерывания, ожидающего обработки:

uart_handler:
         li gp, 0x8

         # Check interrupt pending bit of IPIC ICSR
         csrr s0, IPIC_ICSR
         li t0, (1 << 1) | (1 << 0)
         and s0, s0, t0
         bne s0, t0, fail

Далее - в прилагаемом архиве. Рассмотренные примеры помогут разобраться в остальном исходном коде.

Тестовая программа

~/scr1-sdk-new/sw/uart_test/test.S

     mv t0,     zero

     addi   t0, t0, 1
     addi   t1, t0, 2
     addi   t2, t1, 3
     addi   t3, t2, 4
     addi   t4, t3, 5
     addi   t5, t4, 6
     addi   t6, t5, 7
     addi   s0, t6, 8
     addi   s1, s0, 9
     addi   s2, s1, 10

     csrr    s6,    time

     csrr    s7,    mstatus

     jr        s10

Тестовая программа выполняет ряд простых операций (сложение чисел и считывание ряда CSR регистров). В конце производится безусловный переход по адресу в регистре s10, который должен быть записан в процессе обработки прерывания UART.

Для корректной обработки прерывания требуется сформировать пакет UART. В этом нам поможет скрипт, который будет представлен на следующем слайде.

Двоичный код данной программы будет загружен в память микроконтроллера по UART.

Формирование пакета UART

Первые 32 бита бинарного файла содержат размер последующих инструкций.

~/scr1-sdk-new/sw/uart_test/size_of.sh

#!/bin/bash
make clean
make
size=$(wc -c < <build_dir>/test.bin)
while [ $((size % 4)) -ne 0 ]; do
           ((size++))
Done
size_hex=$(printf "%08x\n" $size)
echo $size_hex > <build_dir</size.txt
xxd -r -p <build_dir>/size.txt > < build_dir > /size.bin
cat < build_dir >/size.bin < build_dir> /test.bin > < build_dir >/test_2.bin
mv < build_dir >/test_2.bin < build_dir >/test.bin
xxd -p < build_dir >/test.bin > < build_dir >/test_hex

Сформированный пакет UART

После исполнения скрипта мы получим файл следующей структуры:


Первые 4 байта содержат размер последующих данных

Вспомогательные скрипты: TTY

Для отправки данных устройству потребуется определить TTY, к которому подключена отладочная плата. Для этого можно воспользоваться следующим скриптом:

~/scripts/know_tty

#!/bin/bash

for sysdevpath in $(find /sys/bus/usb/devices/usb*/ -name dev); do
       (
                syspath="${sysdevpath%/dev}"
                devname="$(udevadm info -q name -p $syspath)"
                [[ "$devname" == "bus/"* ]] && exit
                eval "$(udevadm info -q property --export -p $syspath)"
                [[ -z "$ID_SERIAL" ]] && exit
                echo "/dev/$devname - $ID_SERIAL"
         )
Done

Вывод данного скрипта выглядит следующим образом:


Для приёма и отправки данных ядру SCR1 используется ttyUSB1.

! У вас номер TTY может отличаться. Учтите это в последующих скриптах: send_uart, setup_screen.sh.

Вспомогательные скрипты: Подключение OpenOCD

Для загрузки конфигурационного файла для ПЛИС используется скрипт, вызывающий утилиту openFPGAloader.

~/scripts/connect_ocd.sh - прошивка конфигурации и подключение OpenOCD.

#!/bin/bash

if [ "$1" = "reboot" ]
then
sudo openFPGALoader -b arty_a7_35t /arty_scr1_new.bit
fi

sudo /sc-dt/tools/bin/openocd -s /sc-dt/tools/share/openocd/scripts \
-f /sc-dt/tools/share/openocd/scripts/interface/ftdi/olimex-arm-usb-tiny-h.cfg \
-f /sc-dt/tools/share/openocd/scripts/target/syntacore_riscv.cfg

Опция reboot позволит загрузить битовый поток в ПЛИС из указанной директории. Эта команда может быть использована отдельно.