Add full compiler toolchain, libc, examples and reference docs
First substantive commit: the entire Sprinter C compiler tree on top of
the bare README+gitignore initial commit.
What's in here:
bin/sprinter-cc — driver script invoking SDCC + linker + mkexe
libc/ — Sprinter-specific libc layer over ESTEX/BIOS
(conio, gfx, io, mem, stdio + headers)
runtime/ — crt0 variants (default/small/banked/minimal)
+ heap + bank trampolines
toolchain/ — mkexe (SprintEXE packer, C + tests)
examples/ — 30 demo programs (gfx, file I/O, env, time, …)
lib/Makefile — builds the libc archive (sprinter.lib)
docs/ — converted Sprinter manuals + asm reference samples
third_party/ — solid-c reference compiler dump + sdcc setup script
release_docs/ — packaging / release notes
gitignore overhaul:
• Drop dangerous blanket patterns: *.asm (would hide docs/samples/*.asm)
and *.exe (case-insensitive match was hiding third_party/solid-c/*.EXE
on macOS APFS). Replaced with examples/*/*.{asm,exe,…} and lib/*.lib.
• Restore tracking of toolchain/mkexe/tests/{one,big}.bin — those are
INPUT fixtures, not build outputs.
• Collapse the duplicated SDCC/C/Sdcc sections into one section per
concern (build outputs / vendored / OS-junk).
• Add .sprinter-cc-*/, build/ (catches lib/build/ too), .claude/.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Vendored
+228
@@ -0,0 +1,228 @@
|
||||
СОЗДАНИЕ БИБЛИОТЕК
|
||||
|
||||
|
||||
Известны два способа создания библиотеки. Оба они будут описаны в следующих
|
||||
параграфах. Первый из них, метод "а" - быстрый и легкий по исполнению, однако
|
||||
к собираемым пользовательским программам прилинковываются в том числе и такие
|
||||
функции, которые не обязательно будут использоваться.
|
||||
В отличие от первого, способ "b" реализуется сложнее и требует большего вре-
|
||||
мени, но получаемые в соответствии с ним пользовательские программы будут со-
|
||||
держать в себе только те функции, которые заведомо применяются в программе.
|
||||
Стандартная библиотека компилятора "clib.irl" создается именно по способу "b".
|
||||
|
||||
|
||||
1. Простой способ создания библиотеки
|
||||
|
||||
Рассмотрим пример двух функций "power" и "log2":
|
||||
|
||||
int power(x,e)
|
||||
int x,e;
|
||||
{
|
||||
int y;
|
||||
for(y=1; e>0; e--)
|
||||
y *= x;
|
||||
return(y);
|
||||
}
|
||||
|
||||
int log2(x)
|
||||
int x;
|
||||
{
|
||||
int y;
|
||||
for(y=0; x>1; x>>=1)
|
||||
y++;
|
||||
return(y);
|
||||
}
|
||||
|
||||
Если эти функции помещаются в файл с именем XLIB.C, последовательность
|
||||
создания библиотеки выглядит следующим образом:
|
||||
|
||||
cc1 xlib
|
||||
cc2 xlib
|
||||
as xlib
|
||||
|
||||
При выполнении этой последовательности будет создана библиотека с именем
|
||||
XLIB.REL. Ниже приведена команда сборки программы, которая вызывает функции
|
||||
из этой библиотеки:
|
||||
|
||||
ld prog,xlib,clib/l/gXMAIN
|
||||
|
||||
В этом случае нет необходимости писать ключ /l после имени библиотеки XLIB,
|
||||
т.к. даже если его написать, тем не менее все функции, входящие в библиотеку
|
||||
XLIB, будут скомпонованы с программой "prog".
|
||||
|
||||
Здесь будет описан способ включения в библиотеку программ, написанных на
|
||||
Ассемблере. В качестве примеров взяты функции hex, ror и rol, помещенные в
|
||||
файл ALIB.ASM:
|
||||
|
||||
public hex_, ror_, rol_
|
||||
cseg
|
||||
hex_: ; convert 0..F -> '0'..'F'
|
||||
and 0Fh
|
||||
add a,90h
|
||||
daa
|
||||
adc a,40h
|
||||
daa
|
||||
ret
|
||||
|
||||
ror_: ; ror(c,n) n bit rotate right char
|
||||
inc e
|
||||
rorl: dec e
|
||||
ret z
|
||||
rrca
|
||||
jp rorl
|
||||
|
||||
rol_: ; rol(c,n) n bit rotate left char
|
||||
inc e
|
||||
roll: dec e
|
||||
ret z
|
||||
rlca
|
||||
jp roll
|
||||
|
||||
Включение этих функций в библиотеку производится путем выполнения следующей
|
||||
команды:
|
||||
|
||||
as alib.asm
|
||||
|
||||
Следующая команда вызывает линковку программы, как и в случае Си-программы:
|
||||
|
||||
ld prog,alib,clib/l/gXMAIN
|
||||
|
||||
Как видно из приведенных выше примеров, самый простой способ формирования
|
||||
библиотеки - включение в нее тех программ, из которых компонуется программа.
|
||||
Однако этот способ не совершенен, так как вызывает подключение всей библиотеки.
|
||||
В следующем параграфе будет описан способ создания библиотеки, при котором
|
||||
программа компонуется только из тех функций, к которым предполагаются обраще-
|
||||
ния.
|
||||
|
||||
|
||||
2. Создание полной библиотеки
|
||||
|
||||
2.1. Включение Си-программ в библиотеку
|
||||
|
||||
Здесь будет приведен тот же пример, что и выше - включение файла XLIB.C,
|
||||
содержащего тексты функций POWER и LOG2 в библиотеку.
|
||||
Вначале нужно "разделить" файл XLIB.C на составляющие его функции, записав
|
||||
их в отдельные файлы POWER.C и LOG2.C. Далее необходимо выполнить следующие
|
||||
команды:
|
||||
|
||||
cc1 power
|
||||
cc1 log2
|
||||
cc2 power
|
||||
cc2 log2
|
||||
as power
|
||||
as log2
|
||||
ol a xlib.irl power log2
|
||||
|
||||
При выполнении этой последовательности команд, происходит следующее:
|
||||
|
||||
1. Си-тексты функций транслируются в ассемблерные листинги.
|
||||
2. В результате ассемблирования получаем модули с расширением ".rel".
|
||||
3. С помощью библиотекаря OL из двух модулей с расширением ".rel"
|
||||
создается библиотека XLIB.IRL.
|
||||
|
||||
После создания библиотеки XLIB.IRL, файлы POWER.REL и LOG2.REL уже не нужны
|
||||
и их можно удалить.
|
||||
Применение библиотеки XLIB.IRL определяется следующей командой:
|
||||
|
||||
ld prog,xlib/l,clib/l/gXMAIN
|
||||
|
||||
После имени библиотеки XLIB нужен ключ /l как указание линкеру подключить
|
||||
к программе только необходимые ей функции.
|
||||
|
||||
При сборке программ, состоящих из большого числа файлов (функций), имеет
|
||||
значение порядок расположения функций. Ниже приведены два примера: один из
|
||||
них правильный, а другой неправильный.
|
||||
|
||||
Правильный пример:
|
||||
|
||||
char islower(c)
|
||||
char c;
|
||||
{
|
||||
return('a'<=c && c<='z');
|
||||
}
|
||||
|
||||
char toupper(c)
|
||||
char c;
|
||||
{
|
||||
return(islower(c) ? c-'a'-'A' : c);
|
||||
}
|
||||
|
||||
В данном примере в библиотеку включается файл X.C, состоящий из двух
|
||||
функций. В этом случае функция "islower" расположена в файле X.REL перед
|
||||
функцией "toupper". Поэтому при редактировании связей по ключу /l линкер
|
||||
не выдаст диагностику об ошибке типа отсутствия определения.
|
||||
|
||||
Но если написать вначале текст функции "toupper", возникает следующий
|
||||
неправильный пример:
|
||||
|
||||
char toupper(c)
|
||||
char c;
|
||||
{
|
||||
char islower();
|
||||
return(islower(c) ? c-'a'-'A' : c);
|
||||
}
|
||||
|
||||
char islower(c)
|
||||
char c;
|
||||
{
|
||||
return('a'<=c && c<='z');
|
||||
}
|
||||
|
||||
В результате расположение модулей в библиотечном файле будет неправильным.
|
||||
Подводя итоги сказанному, можно резюмировать, что для правильного порядка
|
||||
расположения модулей в библиотеке нужно в исходной программе вначале писать
|
||||
вызываемую функцию, а после нее - вызывающую.
|
||||
|
||||
|
||||
2.2. Создание библиотеки модулей на Ассемблере
|
||||
|
||||
По сравнению с описанием включения в библиотеку, которое было дано в п.1,
|
||||
здесь, файл ALIB.ASM следует предварительно разделить на следующие три файла
|
||||
"hex.asm", "ror.asm" и "rol.asm":
|
||||
|
||||
HEX.ASM:
|
||||
cseg
|
||||
|
||||
hex_:: and 0Fh
|
||||
add a,90h
|
||||
daa
|
||||
adc a,40h
|
||||
daa
|
||||
ret
|
||||
|
||||
|
||||
ROR.ASM:
|
||||
cseg
|
||||
|
||||
ror_:: inc e
|
||||
rorl: dec e
|
||||
ret z
|
||||
rrca
|
||||
jp rorl
|
||||
|
||||
|
||||
ROL.ASM:
|
||||
cseg
|
||||
|
||||
rol_:: inc e
|
||||
roll: dec e
|
||||
ret z
|
||||
rlca
|
||||
jp roll
|
||||
|
||||
После того, как каждый из них будет ассемблирован и получен файл с расши-
|
||||
рением ".rel", вызывается библиотекарь OL для создания библиотеки:
|
||||
|
||||
as hex
|
||||
as ror
|
||||
as rol
|
||||
ol a alib.irl hex ror rol
|
||||
|
||||
Применение библиотеки ALIB.IRL определяется следующей командой:
|
||||
|
||||
ld prog,alib/l,clib/l/gXMAIN
|
||||
|
||||
При сборке программы, точно таким же образом, как и для сборки Си-программы
|
||||
из модулей, должна соблюдаться последовательность записи исходного текста, а
|
||||
именно: вызываемая функция должна быть записана прежде, а вызывающая ее, вслед
|
||||
за ней.
|
||||
Reference in New Issue
Block a user