mik32_picolibc
Зачем?
Собственно для использования Picolibc в проектах для MIK32 “Амур”
Сборка
Понадобится установленная сборочная система meson
Понадобится установленный инструментарий riscv64-unknown-elf (например, установить пакет gcc-riscv64-unknown-elf)
Подготовка к сборке
- создать временный директорий, например mkdir -p ${HOME}/temp
- перейти в созданный директорий, например cd ${HOME}/temp
- склонировать проект, например git clone https://gitflic.ru/project/rabidrabbit/mik32_picolibc.git
- создать директорий для сборки build-picolibc, например mkdir -p ${HOME}/temp/build-picolibc
- перейти в созданный директорий, например cd ${HOME}/temp/build-picolibc
- создать директорий для установки, например mkdir -p ${HOME}/tools/picolibc-mik32
- запустить сборочную систему, например meson setup --cross-file ${HOME}/temp/mik32_picolibc/picolibc-mik32/scripts/cross-mik32-amur.txt -Dtests=false -Dmultilib=false -Dsemihost=false -Dnewlib-multithread=false -Dnewlib-retargetable-locking=false -Dprefix=${HOME}/tools/picolibc-mik32 -Dbuildtype=debugoptimized ${HOME}/temp/mik32_picolibc/picolibc-mik32
- при отсутствии ошибок запустить сборку, команда ninja
- при отсутствии ошибок запустить установку, команда ninja install (может потребовать ввод пароля для получения доступа к директорию инструментария riscv64-unknown-elf, т.к. устанавливается файл спецификации и скрипты линкера)
- если установилось, то директорий с проектом ${HOME}/temp/mik32_picolibc и директорий для сборки ${HOME}/temp/build-picolibc можно удалить
Применение
Есть готовый пример
А так, “для общего применения”, в файл с функцией main()
нужно добавить следующее (можно в другой, но не забыть):
#include <mik32_memory_map.h> // это заголовок с описанием оборудования Mik32
#include <uart.h> // это заголовок с описанием блока UART
#include <stdio.h>
#include <string.h>
__attribute__((used)) FILE __sf[2];
__attribute__((used)) FILE * const stdin = &__sf[0];
__attribute__((used)) FILE * const stdout = &__sf[1];
__attribute__((used)) FILE * const stderr = &__sf[1];
int mik32_putchar( char a_char, struct __file * ) {
while ( 0 == (UART_0->FLAGS & UART_FLAGS_TXE_M) ) {}
UART_0->TXDATA = a_char;
return a_char;
}
int mik32_getchar( struct __file * ) {
while ( 0 == (UART_0->FLAGS & UART_FLAGS_RXNE_M) ) {}
return UART_0->RXDATA;
}
void local_init() {
bzero( __sf, sizeof(__sf) );
fdev_setup_stream( stdin, NULL, mik32_getchar, NULL, __SRD );
fdev_setup_stream( stdout, mik32_putchar, NULL, NULL, __SWR );
}
И в самое начало функции main()
добавить вызов функции local_init()
Кроме этого, конечно, должна быть проведена инициализация UART_0, и это нужно сделать до первого использования функций из stdio.h
Для сборки проектов под Mik32 с picolibc можно использовать такие параметры: riscv64-unknown-elf-gcc –specs=picolibc.specs -crt0=minimal -march=rv32imc_zicsr -mabi=ilp32 -L/usr/lib/gcc/riscv64-unknown-elf/12.2.0/rv32im/ilp32/
Путь к библиотеке -L/usr/lib/gcc/riscv64-unknown-elf/12.2.0/rv32im/ilp32/ указывается для того, чтобы линкер нашёл libgcc.a (вроде необходимое оттуда перенесено в picolibc). Этот путь не потребуется, если для riscv64-unknown-elf есть цель сборки rv32imc. В другой версии gcc путь может отличаться.
Полезные ссылки
Описание
Picolibc для Mik32 "Амур", совсем чуть-чуть подпилено для совместимости с Mik32.