Как работает программирование на C без заголовков?

Я знаком с языком программирования C и сборкой z80, и я сделал простой компьютер z80 только с процессором с 32 КБ оперативной памяти, 32 КБ ПЗУ и 8255 pia для управления вводом-выводом. Я заставил 8255 подключить светодиод к моей системе с помощью подпрограммы на языке ассемблера.

Итак, вопрос: если есть SDCC (компилятор C для малых устройств), который может скомпилировать программу C в сборку для различных небольших процессоров, включая z80, как создать программу C, если нет библиотек stdio или каких-либо библиотек? вид из-за того, насколько индивидуальна эта система. Должен ли я сначала использовать сборку, а затем создавать и вызывать функцию как процедуру ASM? Я неправильно понимаю какую-то ключевую идею? Я совсем запутался в том, как это работает. Я не могу просто printf() в системе без вывода. Не говоря уже о том, что printf() предполагает, что терминал каким-то образом подключен.


person Marlon Barbee    schedule 24.11.2020    source источник
comment
Любая строка кода, о которой вы беспокоитесь? В общем, язык C не требует никаких заголовков   -  person Yaroslav Stetsyk    schedule 24.11.2020
comment
Если у вас нет стандартной библиотеки, но вы хотите использовать какие-либо функции, которые она обычно предоставляет, вам придется написать эти функции самостоятельно — либо на C, либо на ассемблере, по вашему выбору.   -  person Nate Eldredge    schedule 24.11.2020
comment
Согласно пункту 4 C11 автономная реализация ограничен заголовками <float.h>, <iso646.h>, <limits.h>, <stdalign.h>, <stdarg.h>, <stdbool.h>, <stddef.h>, <stdint.h> и <stdnoreturn.h>.   -  person pmg    schedule 24.11.2020
comment
Должен ли я сначала использовать ассемблер, а затем создавать и вызывать функцию как подпрограмму ASM? Да. Учитывая, что у вас мигает светодиод, вы почти все сделали. Чтобы запустить код C, вам нужно указать указатель стека на старший адрес блока ОЗУ (2 КБ, вероятно, является хорошим размером). Затем вам нужно позвонить main. В сборке наверное _main. Ваш код C не должен возвращаться из main или вызывать exit. И затем, возможно, есть еще 200 вещей, которые вам нужно сделать правильно, прежде чем это заработает. Например, очистка BSS и копирование инициализированных ДАННЫХ из ПЗУ в ОЗУ.   -  person user3386109    schedule 24.11.2020
comment
Зачем вам вызывать printf, если нет экрана для печати?   -  person TonyK    schedule 25.11.2020
comment
Заголовки не являются библиотеками.   -  person Clifford    schedule 25.11.2020
comment
@TonyK printf выводит в поток stdout - это не обязательно должен быть экран. Чаще всего в небольших встроенных системах он реализован на UART, поэтому дисплеем является терминал или, что более вероятно, эмулятор терминала, работающий на ПК.   -  person Clifford    schedule 25.11.2020


Ответы (2)


Вы должны написать библиотеку ввода-вывода для конкретной платформы, которая использует любые возможности ввода-вывода, доступные на вашей платформе. Во многих встроенных системах минимальный стандартный ввод-вывод реализуется через последовательный порт UART, поэтому ваша консоль может быть эмулятором терминала на главном ПК.

Ваш API ввода-вывода не обязательно должен быть таким же сложным, как stdio стандартной библиотеки. Его также не нужно писать на ассемблере, доступ на уровне регистров к отображаемым в памяти периферийным устройствам возможен (фактически нормальный) в C - в конце концов, это язык системного уровня.

Тем не менее, SDCC уже включает подмножество стандартной библиотеки, которое включает в себя подмножество stdio. Поэтому непонятно, почему вы думаете, что вам не хватает этой поддержки. Вы должны обеспечить низкоуровневую поддержку конкретной платформы, но для поддержки printf вам нужно только реализовать putchar() для создания символа на выбранном вами устройстве stdout. Для небуферизованного последовательного вывода это довольно тривиально. Более сложная реализация может использовать управляемый прерываниями буферизованный последовательный вывод. Портирование библиотеки описано в руководстве SDCC.

person Clifford    schedule 24.11.2020

Ты прав. Процедура ассемблера содержит фактическую точку входа, где выполняется инициализация памяти, и затем эта процедура вызывает main().

sdcc/device/lib/z80/crt0.s содержит код запуска по умолчанию, предоставленный SDCC.

Если вашей системе нужно сделать больше, чем она позволяет, обратитесь к разделу 3.12.3 руководства SDCC о том, как предоставить свои собственные.

Что касается printf(), вам просто нужно как-то поставить putchar(). Если это просто инструкция out для какого-то устройства, вы можете просто закинуть ее и в crt0.s, например так:

    .area   _CODE
init:
    call    0x01B0 ; ROM_CLEAR_SCREEN    
    ;; Initialise global variables
    call    gsinit
    call    _main
_exit:
    call    0x0200 ; ROM_GET_KEY
    jr      z, _exit
    call    0x01B0 ; ROM_CLEAR_SCREEN
    ret
_putchar:
    ld      hl, #2
    add     hl, sp
    ld      a, (hl)
    out     (0xBC), a
    ld      hl, #0
    ret
person Stefan Paul Noack    schedule 11.02.2021