diff options
| author | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
|---|---|---|
| committer | kx <kx@radix-linux.su> | 2026-10-09 18:00:15 +0300 |
| commit | 065da3509019b15dd0e678072e6be629e5330bef (patch) | |
| tree | 69c934c9e786ac048b4fbe8f4c4c5571661521f4 /doc | |
| parent | d130fe27fa753be02ed76fd9b277aa3c3d928eb9 (diff) | |
| download | libmcpu-0.4.0.tar.xz | |
Version 0.4.00.4.0
Diffstat (limited to 'doc')
| -rw-r--r-- | doc/libmcpu-bytecode-architecture-ru.pdf | bin | 0 -> 343966 bytes | |||
| -rw-r--r-- | doc/libmcpu-melf-abi-ru.pdf | bin | 0 -> 106016 bytes | |||
| -rw-r--r-- | doc/src/README | 28 | ||||
| -rwxr-xr-x | doc/src/build-docs.sh | 26 | ||||
| -rw-r--r-- | doc/src/libmcpu-architecture-core-ru.tex | 1644 | ||||
| -rw-r--r-- | doc/src/libmcpu-architecture-runtime-ru.tex | 349 | ||||
| -rw-r--r-- | doc/src/libmcpu-assembler-details-ru.tex | 233 | ||||
| -rw-r--r-- | doc/src/libmcpu-assembler-directives-table.tex | 37 | ||||
| -rw-r--r-- | doc/src/libmcpu-bytecode-architecture-ru.tex | 230 | ||||
| -rw-r--r-- | doc/src/libmcpu-doc-common.tex | 169 | ||||
| -rw-r--r-- | doc/src/libmcpu-hll-crt-contract-ru.tex | 181 | ||||
| -rw-r--r-- | doc/src/libmcpu-isa-coverage-ru.tex | 66 | ||||
| -rw-r--r-- | doc/src/libmcpu-melf-abi-ru.tex | 661 | ||||
| -rw-r--r-- | doc/src/libmcpu-opcode-table.tex | 174 | ||||
| -rw-r--r-- | doc/src/libmcpu-psw-table.tex | 31 | ||||
| -rw-r--r-- | doc/src/libmcpu-rconst-table.tex | 72 |
16 files changed, 3901 insertions, 0 deletions
diff --git a/doc/libmcpu-bytecode-architecture-ru.pdf b/doc/libmcpu-bytecode-architecture-ru.pdf Binary files differnew file mode 100644 index 0000000..25a5425 --- /dev/null +++ b/doc/libmcpu-bytecode-architecture-ru.pdf diff --git a/doc/libmcpu-melf-abi-ru.pdf b/doc/libmcpu-melf-abi-ru.pdf Binary files differnew file mode 100644 index 0000000..334916c --- /dev/null +++ b/doc/libmcpu-melf-abi-ru.pdf diff --git a/doc/src/README b/doc/src/README new file mode 100644 index 0000000..cd2f22b --- /dev/null +++ b/doc/src/README @@ -0,0 +1,28 @@ +LibMCPU documentation sources +============================= + +These are the editable XeLaTeX sources for: + + libmcpu-bytecode-architecture-ru.pdf + libmcpu-melf-abi-ru.pdf + +Build both manuals with: + + ./build-docs.sh + +The manuals intentionally do not embed the LibMCPU package release number. +They document the current architectural contracts; package release history +belongs to NEWS.md and ChangeLog, while installed utilities report the actual +package version through --version / --dump-version. + +The manuals use the memoir-based LibMCPU book style with Roboto body text, +vector TikZ diagrams, booktabs/tabularx tables and breakable command/code +blocks. The build script performs three XeLaTeX passes for each document and +writes both PDFs to doc/. + +The bytecode manual contains the signed HLL Runtime ABI contract joining +mcpu-ld, CRT and MCPU Libc, together with reference appendices for assembler +directives, all architectural opcodes, PSW branch selectors and RCONST +selectors. The MELF manual documents static ABI v1, historical ABI v2 and +the frozen normal dynamic ABI v3, including HLL CRT integration layered above +the MELF container contract. diff --git a/doc/src/build-docs.sh b/doc/src/build-docs.sh new file mode 100755 index 0000000..5078ac3 --- /dev/null +++ b/doc/src/build-docs.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +DIR=$(cd -- "$(dirname -- "$0")" && pwd) +DOC=$(cd -- "$DIR/.." && pwd) +BUILD="$DIR/.build" + +rm -rf "$BUILD" +mkdir -p "$BUILD" +cd "$DIR" + +build_one() +{ + local base="$1" + local pass + for pass in 1 2 3; do + xelatex -interaction=nonstopmode -halt-on-error \ + -output-directory="$BUILD" "$base.tex" >"$BUILD/$base.pass$pass.log" + done + cp -f "$BUILD/$base.pdf" "$DOC/$base.pdf" +} + +build_one libmcpu-bytecode-architecture-ru +build_one libmcpu-melf-abi-ru + +rm -rf "$BUILD" diff --git a/doc/src/libmcpu-architecture-core-ru.tex b/doc/src/libmcpu-architecture-core-ru.tex new file mode 100644 index 0000000..16c6a0f --- /dev/null +++ b/doc/src/libmcpu-architecture-core-ru.tex @@ -0,0 +1,1644 @@ +\section{Адресные пространства} +LibMCPU имеет независимые архитектурные адресные пространства (address spaces). Register file остаётся TLS-состоянием CPU; PROGRAM содержит исполняемый код; остальные сегменты являются пространствами объектов данных (data-object spaces) и используют целевое представление объектов LibMPU. + +\begin{center} +\begin{tabularx}{0.99\textwidth}{@{}L{21mm}L{15mm}L{81mm}Y@{}} +\toprule +\textbf{Пространство} & \textbf{SEG} & \textbf{Назначение} & \textbf{Доступ guest}\\ +\midrule +DATA & 0x0 & Глобальные/статические объекты и полноразмерные константы & R/W\\ +STACK & 0x1 & Вызовы, аргументы, automatic objects, spills & R/W\\ +PROGRAM & 0x2 & Машинный код; секции \code{.init/.text/.fini} & R + execute; запись запрещена\\ +CONTROL & 0x3 & Параметры управления запуском и модельным временем & R; runtime может изменять\\ +INPUT & 0x4 & Внешние возмущающие воздействия & R; runtime задаёт значения\\ +OUTPUT & 0x5 & Воздействие модели на среду / текущий выходной вектор & R/W\\ +TRACE & 0x6 & Текущий telemetry frame модели & R/W\\ +HEAP & 0x7 & Обнулённая runtime-область динамической памяти & R/W\\ +reserved & 0x8..0xF & Будущие адресные пространства & dereference fault\\ +Register file & -- & 512 KiB TLS; перекрывающиеся представления регистров & REG24\\ +\bottomrule +\end{tabularx} +\end{center} + +PROGRAM, DATA, STACK, CONTROL, INPUT, OUTPUT, TRACE и HEAP логически независимы и байтово адресуемы. Host backing каждого активного адресного пространства создаётся отдельным anonymous \code{mmap()}; файлы executable/image никогда не являются file-backed memory виртуального CPU. + +DATA и HEAP разделены. DATA является статическим пространством данных, формируемым образом executable (image-backed data space). HEAP является отдельным runtime-пространством с SEG=0x7, не имеет assembler payload и не расширяет DATA. Будущие malloc/free/realloc/calloc будут library-level ABI поверх HEAP, а не ISA instructions. + +Структуры CONTROL/INPUT/OUTPUT/TRACE не задаются CPU. ISA видит только bytes и права доступа. Форматы записей модели (model records), имена полей, типы и семантику модельного времени определит будущий C-подобный язык моделирования и runtime metadata. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,node distance=7mm and 8mm] + \node[draw=McpuBlue,fill=McpuGrayBg,minimum width=31mm,minimum height=12mm,align=center] (d) {DATA 0x0\\{\scriptsize R/W}}; + \node[draw=McpuBlue,fill=McpuGrayBg,right=of d,minimum width=31mm,minimum height=12mm,align=center] (s) {STACK 0x1\\{\scriptsize R/W}}; + \node[draw=McpuBlue,fill=McpuGreenBg,right=of s,minimum width=31mm,minimum height=12mm,align=center] (p) {PROGRAM 0x2\\{\scriptsize R + execute}}; + \node[draw=McpuBlue,fill=McpuGrayBg,right=of p,minimum width=31mm,minimum height=12mm,align=center] (c) {CONTROL 0x3\\{\scriptsize read-only}}; + \node[draw=McpuBlue,fill=McpuGrayBg,below=of d,minimum width=31mm,minimum height=12mm,align=center] (i) {INPUT 0x4\\{\scriptsize read-only}}; + \node[draw=McpuBlue,fill=McpuGrayBg,right=of i,minimum width=31mm,minimum height=12mm,align=center] (o) {OUTPUT 0x5\\{\scriptsize R/W}}; + \node[draw=McpuBlue,fill=McpuGrayBg,right=of o,minimum width=31mm,minimum height=12mm,align=center] (t) {TRACE 0x6\\{\scriptsize R/W}}; + \node[draw=McpuBlue,fill=McpuGrayBg,right=of t,minimum width=31mm,minimum height=12mm,align=center] (h) {HEAP 0x7\\{\scriptsize R/W}}; + \node[draw=McpuBlue2,dashed,fill=white,below=9mm of $(o)!0.5!(t)$,minimum width=70mm,minimum height=9mm] {0x8..0xF зарезервированы; разыменование запрещено}; +\end{tikzpicture} +\caption{Активная карта сегментов PTR64 и права доступа guest-программы.} +\end{figure} + +\section{Физическая адресация регистра: REG24} +Машинный операнд физического регистра имеет ровно 24 бита. Четыре старших бита кодируют физическую ширину представления регистра, оставшиеся двадцать --- байтовый адрес начала представления внутри единого регистрового файла. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,x=0.31cm,y=0.78cm] + \draw[fill=McpuGreenBg] (0,0) rectangle (4,1); + \draw[fill=McpuBlueBg] (4,0) rectangle (24,1); + \node at (2,0.5) {WIDTH}; + \node at (14,0.5) {BYTE ADDRESS}; + \node[above] at (2,1) {bits 23..20}; + \node[above] at (14,1) {bits 19..0}; + \draw[decorate,decoration={brace,mirror,amplitude=4pt}] (0,-0.18) -- (24,-0.18); + \node[below=6pt] at (12,-0.18) {REG24 = 3 bytes в PROGRAM}; +\end{tikzpicture} +\caption{Логическое устройство REG24.} +\end{figure} + +Три байта PROGRAM формируются следующим образом: первый байт содержит \code{WIDTH[3:0]} и \code{ADDRESS[19:16]}, второй --- \code{ADDRESS[15:8]}, третий --- \code{ADDRESS[7:0]}. Это машинное поле имеет канонический порядок байтов PROGRAM и не является host C bit-field. + +\begin{center} +\begin{tabularx}{0.78\textwidth}{@{}L{22mm}L{38mm}Y@{}} +\toprule +\textbf{WIDTH} & \textbf{Физическая ширина} & \textbf{Размер}\\ +\midrule +0x0 & 8 bit & 1 byte\\ +0x1 & 16 bit & 2 bytes\\ +0x2 & 32 bit & 4 bytes\\ +0x3 & 64 bit & 8 bytes\\ +0x4 & 128 bit & 16 bytes\\ +0x5 & 256 bit & 32 bytes\\ +0x6 & 512 bit & 64 bytes\\ +0x7 & 1024 bit & 128 bytes\\ +0x8 & 2048 bit & 256 bytes\\ +0x9 & 4096 bit & 512 bytes\\ +0xA & 8192 bit & 1024 bytes\\ +0xB & 16384 bit & 2048 bytes\\ +0xC & 32768 bit & 4096 bytes\\ +0xD & 65536 bit & 8192 bytes\\ +\bottomrule +\end{tabularx} +\end{center} + +Register file имеет 512 KiB, поэтому ADDRESS[19] обязан быть нулём. Views имеют natural alignment. Формула архитектуры остаётся REGISTER = WIDTH + BYTE ADDRESS. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + r8@0x00000 -> 00 00 00 + r16@0x00000 -> 10 00 00 + r4096@0x02000 -> 90 20 00 + r65536@0x7e000 -> D7 E0 00 +\end{lstlisting} + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Latex,x=0.92cm,y=0.85cm] + \foreach \x in {0,...,7} { + \draw (\x,0) rectangle ++(1,0.75); + \node[font=\ttfamily\scriptsize] at (\x+0.5,0.375) {+\x}; + } + \draw[very thick,color=McpuBlue] (0,-0.18) rectangle (8,0.93); + \node[anchor=east,color=McpuBlue] at (-0.15,0.38) {\texttt{r64@0x100}}; + \draw[very thick,color=McpuGreen] (4,-0.35) rectangle (8,1.10); + \node[anchor=west,color=McpuGreen] at (8.15,0.38) {\texttt{r32@0x104}}; + \node[below=5mm] at (4,0) {одни и те же физические байты register file}; +\end{tikzpicture} +\caption{Представления (views) разной ширины могут перекрываться.} +\end{figure} + +\section{r и c: разные смыслы одного REG24} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + r64@0x02000 ; 64 физических бита, integer/real смысл задаёт opcode + c64@0x02000 ; те же 64 физических бита, complex semantic view +\end{lstlisting} + +Обе записи имеют одинаковый REG24. Для c<bits> число bits означает полную физическую ширину; каждая real-компонента имеет половинную ширину. + +\begin{center} +\begin{tabularx}{0.78\textwidth}{@{}L{34mm}L{38mm}Y@{}} +\toprule +\textbf{Complex view} & \textbf{Физический размер} & \textbf{Компоненты}\\ +\midrule +\code{c64} & 64 bit & 2 x real32\\ +\code{c128} & 128 bit & 2 x real64\\ +\code{c4096} & 4096 bit & 2 x real2048\\ +\code{c32768} & 32768 bit & 2 x real16384\\ +\code{c65536} & 65536 bit & 2 x real32768\\ +\bottomrule +\end{tabularx} +\end{center} + +\section{Канонический порядок байтов PROGRAM} +OPCODE16, REG24, IMM64, ADDR64, CODE64 и OFF64 кодируются в PROGRAM MSB-first, независимо от host endian и target data profile. Архитектурные data objects (register file, DATA, STACK и остальные data spaces) образуют отдельный byte-order domain и используют representation, совместимое с настроенной LibMPU. Полная нормативная модель приведена в разделе 31. + +PROGRAM serialization и architectural data-object representation - разные уровни. Decoder собирает многобайтовые поля явно как MSB-first; произвольный host-cast packed C-структурой не является частью формата. + +\section{Непосредственные числовые константы} +Inline numeric payload всегда равен 64 битам; opcode задаёт интерпретацию. Непосредственная форма предназначена только для значений, которые точно представимы в машинном immediate-формате соответствующей инструкции. Ассемблер не имеет права молча терять значащие биты/цифры при преобразовании textual literal в immediate. + +Exact-immediate rule. Если textual literal не представим точно в immediate source format, + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mcpu-as завершает сборку с ошибкой и рекомендует создать полноразмерный объект +\end{lstlisting} + +через .integer/.real/.complex в DATA и загрузить его инструкцией LOAD. + +\subsection{LDI - Integer} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LDI r<bits>@addr, integer +\end{lstlisting} + +OPCODE16 + REG24 + IMM64 = 13 bytes + +IMM64 - signed 64-bit two's-complement integer. Для destination шириной 64 бит и более literal обязан точно помещаться в signed integer64. Для destination уже 64 бит literal дополнительно обязан помещаться в signed диапазон именно этой ширины: assembler не генерирует заведомо теряющее значение icvt(). + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; корректно + LDI r8@0x00000, -1 + LDI r32@0x00010, 1000000 + LDI r4096@0x00100, 9223372036854775807 + + ; ошибка: +255 не является signed integer8 value + LDI r8@0x00000, 255 + + ; ошибка: literal шире signed integer64 source format + LDI r128@0x00100, 9223372036854775808 +\end{lstlisting} + +Для большого целого используется DATA: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 16 +\end{lstlisting} + +wide\_integer: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 128, 9223372036854775808 + .text + LOAD r128@0x00100, wide_integer +\end{lstlisting} + +Типичная диагностика: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mcpu-as: error: + line N: LDI immediate is not exactly representable as integer64; +\end{lstlisting} + +use .integer <bits>, value in DATA and LOAD + +\subsection{LDR - Real} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LDR r32@0x02000, -17.0 + LDR r4096@0x04000, 2.0 +\end{lstlisting} + +OPCODE16 + REG24 + REAL64 = 13 bytes + +Machine payload LDR всегда binary64. Но assembler применяет более строгую проверку в зависимости от destination: для r32 textual literal обязан быть точно представим как real32; для r64 и всех более широких Real-register views - точно представим как real64. После этой проверки runtime по-прежнему выполняет r\_cvt() из embedded real64 к физической ширине destination. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; корректно: значения точно представимы + LDR r32@0x02000, -17.0 + LDR r4096@0x04000, 2.0 + + ; ошибка: 0.1 не имеет точного binary32 representation + LDR r32@0x02000, 0.1 + + ; ошибка: high-precision decimal сначала потерял бы точность в binary64 + LDR r4096@0x04000, 3.14243987129849274029174912694696912849214e-286 +\end{lstlisting} + +Диагностика для r32: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mcpu-as: error: + line N: LDR immediate is not exactly representable as real32; +\end{lstlisting} + +use .real <bits>, value in DATA and LOAD + +Диагностика для r64 и шире: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mcpu-as: error: + line N: LDR immediate is not exactly representable as real64; +\end{lstlisting} + +use .real <bits>, value in DATA and LOAD + +Правильная форма для произвольной высокоточной константы: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 16 +\end{lstlisting} + +pi\_like: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .real 4096, 3.14243987129849274029174912694696912849214e-286 + .text + LOAD r4096@0x04000, pi_like +\end{lstlisting} + +.real передаёт textual literal непосредственно ascii\_to\_real() LibMPU с precision конечного DATA-object; промежуточного binary64 здесь нет. + +\subsection{LDC - Complex} +В машинном коде inline-комплекс состоит из двух компонент binary32: +\begin{center} +\begin{tabularx}{0.72\textwidth}{@{}Y Y@{}} +\toprule +\textbf{REAL} & \textbf{IMAG}\\ +\midrule +float32, 32 bits & float32, 32 bits\\ +\bottomrule +\end{tabularx} +\end{center} + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LDC c64@0x02000, -17.0r0+32.0j0 + LDC c4096@0x04000, 2.0r0-0.5j0 +\end{lstlisting} + +Формат инструкции: OPCODE16 + REG24 + COMPLEX64 = 13 bytes. + +Минимальный complex destination - c64, то есть две real32 components. Inline LDC всегда содержит 2 x binary32, поэтому каждая textual component обязана быть точно представима как real32 независимо от ширины destination. После декодирования CPU расширяет обе real32 components через LibMPU к половине физической ширины c-view и вызывает c\_gen\_complex(). + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; корректно + LDC c64@0x02000, -17.0r0+32.0j0 + LDC c4096@0x04000, 2.0r0-0.5j0 + + ; ошибка: real component 0.1 не представима точно как real32 + LDC c128@0x02000, 0.1r0+32.0j0 + + ; ошибка ещё на разборе регистра: c32 запрещён + LDC c32@0x02000, 1.0r0+2.0j0 +\end{lstlisting} + +Диагностика потери точности: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mcpu-as: error: + line N: LDC immediate component is not exactly representable as real32; +\end{lstlisting} + +use .complex <bits>, real, imag in DATA and LOAD + +Для широкого complex object: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 16 +\end{lstlisting} + +wide\_z: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .complex 4096, 3.14243987129849274029174912694696912849214e-286, -0.125 + .text + LOAD c4096@0x04000, wide_z +\end{lstlisting} + +.complex формирует components непосредственно в требуемой LibMPU precision; LDC для таких значений использовать нельзя. + +\subsection{Почему это assembler error, а не runtime rounding} +Immediate является частью PROGRAM image и уже после сборки не содержит исходный текст literal. Если assembler сначала округлит длинную десятичную запись до binary64/binary32, executor уже не способен узнать, что информация была потеряна. Поэтому exactness проверяется до emission bytecode: textual literal разбирается LibMPU с высокой precision, конвертируется в immediate precision и обратно, после чего значения сравниваются. Только exact round-trip допускается к emission. + +Это правило относится к immediate-формам LDI/LDR/LDC. Полноразмерные DATA directives намеренно выполняют conversion непосредственно к объявленной ширине объекта; обычное математическое округление decimal->binary в этой целевой precision является частью создания самого объекта. + +\subsection{Conversion-class instructions сохраняют PSW} +Некоторые LibMPU conversion helpers изменяют внутренние arithmetic/status flags как побочный эффект своей реализации. Например, icvt() влияет на часть integer flags. Для LibMCPU это нежелательно: преобразование значения не должно неожиданно уничтожать condition state, вычисленное предыдущей инструкцией. + +Нормативное правило. Инструкции LDI, LDR, LDC, ICVT, RCVT, ITOR, UITOR, RTOI, RTOUI, CCVT и CRTOC являются PSW-neutral. Перед вызовом LibMPU conversion routine executor сохраняет PSW[15:0], после завершения conversion восстанавливает прежнее значение. HF/TF/IF/MODE при этом вообще не изменяются. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + saved = PSW[15:0] + icvt(...) ; или r_cvt(), c_cvt(), ltor(), ... +\end{lstlisting} + +PSW[15:0] = saved + +Внутренняя реализация LibMCPU намеренно не включает private header LibMPU и не зависит от private macro \_\_MPU\_FLAGS. Сохранение/восстановление делается через уже существующий public PSW facade LibMCPU, который собирает и восстанавливает LibMPU flags через публичные accessor functions. Архитектурно результат эквивалентен сохранению \_\_MPU\_FLAGS вокруг conversion. + +Это правило относится только к операциям, смысл которых - загрузить или преобразовать значение. Обычные arithmetic instructions продолжают публиковать нормальные LibMPU flag effects и поэтому не выполняют такого save/restore. + +\section{DATA, ADDR64 и NULL guard} +ADDR64 остаётся 64-битным byte offset внутри DATA для прямых инструкций LOAD/STORE. Это не PTR64. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LOAD REG24, ADDR64 ; DATA -> register file + STORE ADDR64, REG24 ; register file -> DATA +\end{lstlisting} + +Обе формы занимают 13 байт. Размер копии задаётся физической шириной REG24. + +\subsection{Нулевой PTR64 и первые 16 байт DATA} +ABI определяет нулевой указатель как ровно 0x0000000000000000. Битово это совпадает с комбинацией SEG=DATA, OFFSET=0. Поэтому executor отдельно распознаёт all-zero PTR64; при попытке разыменования LOADP, STOREP, BMOV и BMOVI возвращают CPU\_EXEC\_POINTER\_FAULT. + +PTR64 NULL = 0x0000000000000000 + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + DATA 0x0000 .. 0x000f reserved NULL guard + DATA 0x0010 .. ordinary assembler objects +\end{lstlisting} + +Assembler всегда начинает DATA image с 16 нулевых guard bytes. Поэтому обычная DATA label не может иметь PTR64 value zero и первый допустимый object offset сразу кратен 16. + +Прямой ADDR64 и NULL. NULL относится к PTR64. Низкоуровневые прямые LOAD/STORE технически адресуют DATA по raw ADDR64, но ABI считает DATA[0..15] зарезервированной областью и conforming assembler/program не размещает там объекты. + +\subsection{.align выравнивает guest offset} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 16 +\end{lstlisting} + +x: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .real 4096, 0.0 +\end{lstlisting} + +.align N двигает только текущий guest DATA offset до следующего кратного N значения. Директивы .integer/.real/.complex сами по себе не вставляют никакого padding и пишут + +объект точно с текущего offset. Это принципиально: assembler способен описывать как обычные ABI-layouts, так и packed binary layouts. + +\subsection{Code pointers in DATA} +DATA может содержать PROGRAM pointers для indirect control flow. Директива .cptr label занимает 8 байт, резервирует PTR64 object и после полной сборки .text разрешает CODE label в PROGRAM byte offset. Она не добавляет implicit alignment. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 8 +\end{lstlisting} + +handlers: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .cptr handler0 + .cptr handler1 +\end{lstlisting} + +Получившийся object можно загрузить обычным LOADP r64,... и передать в JMPP/CALLP. Forward CODE labels поддерживаются assembler fixup mechanism. + +\section{Полноразмерные константы} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 16 +\end{lstlisting} + +huge\_integer: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 65536, 12345678901234567890... +\end{lstlisting} + +high\_precision\_real: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .real 16384, 1.234567890123456789... +\end{lstlisting} + +high\_precision\_complex: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .complex 32768, 1.234567890123456789..., -2.5 + + .text + LOAD r65536@0x00000, huge_integer + LOAD r16384@0x02000, high_precision_real + LOAD c32768@0x08000, high_precision_complex +\end{lstlisting} + +Тип, размер, internal padding/alignment C-like объектов известны assembler/compiler. CPU копирует байты и не хранит runtime type tag. + +\section{Предопределённые математические константы} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + RCONST r4096@0x02000, PI + RCONST r16384@0x04000, E + RCONST r128@0x08000, SQRT2 +\end{lstlisting} + +OPCODE16 + REG24 + CONST8 = 6 bytes + +LibMPU строит значение непосредственно с требуемой точностью. Основные группы констант перечислены в приложении: ZERO/HALF/ONE/TWO/TEN, PI/E/LN2/LN10, кратные PI, SQRT2/SQRT3/SQRTPI, GOLDENRATIO, EULERGAMMA и CATALAN. + +\section{OPCODE16 и сигнатуры} +OPCODE16 полностью определяет количество и тип следующих операндов. Отдельного format-byte нет. + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{22mm}L{52mm}Y@{}} +\toprule +\textbf{Диапазон} & \textbf{Назначение} & \textbf{Примеры}\\ +\midrule +0x00xx & CPU/system и PSW status & NOP, HALT, SETF/CLRF, CLRCPUF/CLRMPUF\\ +0x01xx & data movement / построение адресов & MOV, LDI, LDR, LDC, LOAD, STORE, LEA, LEASP, LOADP, STOREP\\ +0x10xx & integer & IADD, ISUB, ICMP, ...\\ +0x20xx & real & RADD, RSIN, RLOG, ...\\ +0x30xx & complex & CADD, CEXP, CPOW, ...\\ +0x40xx & control flow & JMP/JMPP, JSET/JCLR, CALL/CALLP, RET\\ +0x50xx & stack/frame & PUSH, POP, LDSP, STSP, ADJSP, PUSHFP, SETFP, ...\\ +\bottomrule +\end{tabularx} +\end{center} + +\begin{longtable}{@{}L{23mm}L{30mm}L{105mm}@{}} +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Формат операндов}\\ +\midrule +\endfirsthead +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Формат операндов}\\ +\midrule +\endhead +0x0010 & SETF & PSWBIT8 (AF..INXF)\\ +0x0011 & CLRF & PSWBIT8 (AF..INXF)\\ +0x0012 & CLRCPUF & ---\\ +0x0013 & CLRMPUF & ---\\ +0x0120 & LOAD & R/C, ADDR64\\ +0x0121 & STORE & ADDR64, R/C\\ +0x0130 & LEA & r64, ADDR64\\ +0x0131 & LEASP & r64, OFF64\\ +0x0132 & LOADP & R/C, r64(PTR64)\\ +0x0133 & STOREP & r64(PTR64), R/C\\ +0x0140 & PADD & r64(dst), r64(ptr), r64(delta)\\ +0x0141 & PADDI & r64(dst), r64(ptr), OFF64\\ +0x0142 & PSUB & r64(dst), r64(ptr), r64(delta)\\ +0x0143 & PSUBI & r64(dst), r64(ptr), OFF64\\ +0x0144 & PDIFF & r64(dst), r64(ptr1), r64(ptr2)\\ +0x0150 & BMOV & r64(dst PTR64), r64(src PTR64), r64(byte_count)\\ +0x0151 & BMOVI & r64(dst PTR64), r64(src PTR64), IMM64 byte_count\\ +0x4000 & JMP & CODE64\\ +0x4001/02 & JSET/JCLR & PSWBIT8, CODE64\\ +0x4003 & JMPP & r64(PROGRAM PTR64)\\ +0x4010 & CALL & CODE64\\ +0x4011 & RET & ---\\ +0x4012 & CALLP & r64(PROGRAM PTR64)\\ +0x5000/01 & PUSH/POP & R/C\\ +0x5010/11 & LDSP/STSP & R/C,OFF64 / OFF64,R/C\\ +0x5020 & ADJSP & OFF64\\ +\bottomrule +\end{longtable} + +\section{Явное управление флагами PSW} +Arithmetic/status domain PSW намеренно разделён на два byte-range. \code{PSW[7:0]} --- CPU flags, \code{PSW[15:8]} --- MPU mathematical flags. Execution/control state начинается выше этого диапазона и не является writable через обычные flag instructions. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + SETF CF ; PSW[CF] = 1 + CLRF AF ; PSW[AF] = 0 + CLRCPUF ; PSW[7:0] = 0 + CLRMPUF ; PSW[15:8] = 0 +\end{lstlisting} + +\code{SETF} и \code{CLRF} принимают те же symbolic flag names AF, CF, OF, SF, PF, ZF, RF, VF, DOMF, SNGF, OVFF, UDFF, TLSF, PLSF, INDF, INXF, которые используются branch selector namespace, но write contract намеренно заканчивается на bit 15. Попытка \code{SETF HF}, \code{CLRF TF} или \code{SETF IF} является assembler error; decoder/executor независимо отвергает такой bytecode как invalid operand. MODE многобитовое поле и отдельного selector не имеет. + +Каждая single-flag instruction изменяет ровно выбранный bit и сохраняет остальные биты PSW. \code{CLRCPUF} использует маску \code{0x000000ff}, \code{CLRMPUF} --- \code{0x0000ff00}; обе операции сохраняют HF/TF/IF/MODE и reserved bits. + +Практически это устраняет необходимость искусственно выполнять арифметическую операцию только ради получения заданного initial carry: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + CLRF CF + IADC r64@0x00000, r64@0x00010, r64@0x00018 + IADC r64@0x00008, r64@0x00020, r64@0x00028 + + SETF CF + ISBB r64@0x00030, r64@0x00040, r64@0x00048 +\end{lstlisting} + +\code{IADC}, \code{ISBB} и rotate-through-carry instructions продолжают использовать установленную LibMPU flag semantics; \code{SETF/CLRF} не переопределяют их арифметику, а только задают входное flag state. + +\section{Ограничения разрядности} + +\begin{center} +\begin{tabularx}{0.84\textwidth}{@{}L{30mm}L{62mm}Y@{}} +\toprule +\textbf{Класс} & \textbf{Простые операции} & \textbf{Трансцендентные}\\ +\midrule +Integer & до 65536 bit & ---\\ +Real & до 65536 bit & до 16384 bit\\ +Complex & до c65536 = 2 x real32768 & до c32768 = 2 x real16384\\ +\bottomrule +\end{tabularx} +\end{center} + +\section{PC, CODE64 и direct/indirect control flow} +PC - 64-битный byte offset в PROGRAM. CODE64 - такой же raw PROGRAM offset внутри machine code, encoded canonical MSB-first. Прямые переходы получают target из bytecode, а indirect forms получают target через обычный 64-bit register, содержащий PROGRAM PTR64. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + обычная инструкция: PC = old_PC + instruction_length + JMP CODE64: PC = target + JSET/JCLR taken: PC = target + JSET/JCLR not taken: PC = next_pc + JMPP r64(PTR64): PC = OFFSET(ptr), если SEG=PROGRAM + CALL CODE64: push next_pc; PC = target + CALLP r64(PTR64): push next_pc; PC = OFFSET(ptr), если SEG=PROGRAM +\end{lstlisting} + +JZ/JNZ/JC/JNC/JO/JNO/JS/JNS являются assembler aliases для JSET/JCLR над конкретными PSW bit. + +\subsection{Зачем нужны JMPP и CALLP} +JMP и CALL кодируют конкретный CODE64 target прямо внутри инструкции. Это удобно для statically known labels. JMPP и CALLP нужны тогда, когда target выбирается во время исполнения: function pointer, callback, таблица обработчиков, virtual dispatch, jump table или runtime-selected routine. + +Code/function pointer ABI. Указатель на executable code является обычным PTR64 с SEG = PROGRAM (0x2). Offset - byte address внутри текущего PROGRAM. Отдельного архитектурного типа function-pointer не существует: это 64-битное значение в обычном r64. + +\subsection{JMPP - indirect jump} +\begin{center} +\begin{tabularx}{0.86\textwidth}{@{}L{24mm}L{45mm}Y@{}} +\toprule +\textbf{Код операции} & \textbf{Source syntax} & \textbf{Машинный формат / длина}\\ +\midrule +0x4003 & \code{JMPP r64@addr} & OPCODE16 + REG24 = 5 bytes\\ +\bottomrule +\end{tabularx} +\end{center} + +Source register содержит полный PTR64. Executor сначала читает 8 байт register view и проверяет: + +ptr != NULL SEG(ptr) == PROGRAM OFFSET(ptr) < program.size + +При успехе выполняется только: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + PC = OFFSET(ptr) +\end{lstlisting} + +SP, FP, STACK, PSW и сам source register не изменяются. Ошибка segment selector, NULL или offset за пределами текущего PROGRAM даёт CPU\_EXEC\_POINTER\_FAULT, причём PC остаётся прежним. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; r64@0x00100 = PTR64(PROGRAM, target_offset) + JMPP r64@0x00100 +\end{lstlisting} + +Для r64@0x00100 REG24 равен 30 01 00, поэтому machine bytes инструкции: + +40 03 30 01 00 + +Instruction boundary metadata нет. CPU проверяет только PROGRAM segment и byte range. Если runtime-created pointer указывает в середину другой инструкции, PTR64 может быть range-valid; следующая decode operation определит, образует ли последовательность bytes допустимую инструкцию. Assembler-generated code labels и + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .cptr label естественно указывают на начало помеченной assembler instruction. +\end{lstlisting} + +\subsection{CALLP - indirect call} +\begin{center} +\begin{tabularx}{0.86\textwidth}{@{}L{24mm}L{45mm}Y@{}} +\toprule +\textbf{Код операции} & \textbf{Source syntax} & \textbf{Машинный формат / длина}\\ +\midrule +0x4012 & \code{CALLP r64@addr} & OPCODE16 + REG24 = 5 bytes\\ +\bottomrule +\end{tabularx} +\end{center} + +CALLP использует тот же CALL ABI, что и direct CALL CODE64. Различается только источник target. После проверки PROGRAM PTR64 и наличия места в STACK вычисляется: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + next_pc = old_PC + 5 + new_sp = old_SP - 8 +\end{lstlisting} + +и только после всех проверок происходит архитектурное изменение: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + STACK[new_sp .. new_sp+7] = next_pc ; raw 64-bit CODE64 offset + SP = new_sp + PC = OFFSET(ptr) +\end{lstlisting} + +Возвратный адрес не является PTR64. CALLP, как и CALL, помещает в STACK raw 64-bit PROGRAM byte offset. Поэтому существующий RET не различает direct и indirect call: он снимает тот же CODE64 и устанавливает PC. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; r64@0x00100 = PTR64(PROGRAM, function_offset) + CALLP r64@0x00100 + ; execution resumes here after RET +\end{lstlisting} + +Для того же r64@0x00100 machine bytes: + +40 12 30 01 00 + +CALLP не меняет PSW и FP. Register file считается volatile across CALL по уже принятому ABI; это соглашение caller/callee, а не side effect самой инструкции. + +\subsection{Atomic fault semantics CALLP} +CALLP сначала проверяет pointer, текущий PROGRAM range и возможность разместить 8-byte адрес возврата (return PC) в STACK. До успешного завершения всех проверок не изменяются PC, SP и STACK. Поэтому не существует состояния "return address уже записан, но переход не произошёл". + +\begin{center} +\begin{tabularx}{0.97\textwidth}{@{}L{58mm}L{38mm}Y@{}} +\toprule +\textbf{Условие} & \textbf{Результат} & \textbf{Архитектурное состояние}\\ +\midrule +Operand не является физическим 64-bit register & WIDTH/operand fault & без изменений\\ +NULL или любой non-PROGRAM PTR64 & POINTER\_FAULT & без изменений\\ +PROGRAM offset $\ge$ \code{program.size} & POINTER\_FAULT & без изменений\\ +Недостаточно STACK для адрес возврата (return PC) & STACK\_FAULT & без изменений\\ +Успех & CPU\_EXEC\_BRANCH & адрес возврата (return PC) помещён в STACK; SP/PC изменены\\ +\bottomrule +\end{tabularx} +\end{center} + +\subsection{Assembler directive .cptr} +Чтобы таблицы function/code pointers можно было собирать непосредственно в DATA, assembler поддерживает: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .cptr CODE_LABEL +\end{lstlisting} + +Директива занимает ровно 8 байт и после разрешения label создаёт: + +PTR64(SEG=PROGRAM, OFFSET=byte\_address\_of(CODE\_LABEL)) + +Forward references разрешены. .cptr не вставляет automatic alignment; при необходимости таблица явно начинается с .align 8 или более сильного alignment. + +Каноническое spelling - .cptr. Историческое .codeptr assembler продолжает принимать как compatibility alias, но новые исходники должны использовать .cptr. Имя .label намеренно не используется: label определяется синтаксисом name:, а эта directive создаёт 8-byte code-pointer object. + +Не путать с bytecode field encoding. OPCODE16/CODE64/IMM64 внутри PROGRAM имеют canonical MSB-first encoding. .cptr находится в DATA и записывает architectural object representation PTR64, то есть те же 8 байт, которые затем LOADP r64,... помещает в 64-bit register view. + +\subsection{Полный пример: indirect call + indirect jump} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 8 +\end{lstlisting} + +dispatch: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .cptr indirect_function + .cptr done + + .text + LEA r64@0x00000, dispatch + LOADP r64@0x00008, r64@0x00000 + CALLP r64@0x00008 + + PADDI r64@0x00000, r64@0x00000, 8 + LOADP r64@0x00010, r64@0x00000 + JMPP r64@0x00010 + + ; unreachable if JMPP works + LDI r64@0x00020, 99 + HALT +\end{lstlisting} + +indirect\_function: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LDI r64@0x00020, 42 + RET +\end{lstlisting} + +done: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + HALT +\end{lstlisting} + +Первый table element вызывает функцию через CALLP. RET возвращает на инструкцию после 5-byte CALLP. Затем pointer arithmetic выбирает второй element, LOADP загружает следующий PROGRAM PTR64, а JMPP переносит PC к done. Никакой специальной SWITCH/JUMP-TABLE инструкции не требуется. + +\subsection{Jump-table pattern} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; index/range validation and index*8 scaling are done by surrounding code + ; r64@byte_off already contains the byte offset of the selected 8-byte entry + LEA r64@table_ptr, table + PADD r64@entry_ptr, r64@table_ptr, r64@byte_off + LOADP r64@target, r64@entry_ptr + JMPP r64@target +\end{lstlisting} + +Это normative low-level pattern для будущего assembler/compiler. Проверка index range и перевод element index в byte offset выполняются до вычисления/использования table entry. CPU остаётся независимым от high-level конструкции switch. + +\section{STACK и SP} + +\term{STACK}{стек} --- отдельное архитектурное адресное пространство MCPU. Оно растёт \textbf{к меньшим адресам}: при выделении памяти значение SP уменьшается, при освобождении --- увеличивается. После создания пустого стека + +\begin{center} +\code{SP = FP = stack_size}. +\end{center} + +SP хранит не PTR64, а обычный 64-битный \textbf{byte offset внутри STACK}. Поэтому указатель на объект стека получается явно через \code{LEASP}/\code{LEAFP}; сам SP не содержит selector сегмента. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,x=1cm,y=1cm] + \draw[McpuBlue,thick] (2.0,0.3) rectangle (8.3,5.7); + \fill[McpuGrayBg] (2.02,0.32) rectangle (8.28,2.25); + \fill[McpuGreenBg] (2.02,2.25) rectangle (8.28,5.68); + \draw[McpuBlue,very thick] (1.65,2.25) -- (8.85,2.25); + \node[anchor=west,color=McpuBlue] at (8.95,2.25) {SP}; + \node[color=McpuBlue] at (5.15,4.05) {свободная область STACK}; + \node[color=McpuBlue2] at (5.15,1.25) {занятые данные}; + \node[anchor=west,color=McpuBlue2] at (0.0,5.65) {малые адреса}; + \node[anchor=west,color=McpuBlue2] at (0.0,-0.12) {большие адреса; конец STACK = \code{stack_size}}; + \draw[->,McpuGreen,very thick] (9.8,3.95) -- (9.8,2.55); + \node[anchor=west,color=McpuGreen] at (10.0,3.25) {PUSH}; + \draw[->,McpuBlue,very thick] (10.9,1.0) -- (10.9,2.0); + \node[anchor=west,color=McpuBlue] at (11.1,1.45) {POP}; +\end{tikzpicture} +\caption{Стек растёт к меньшим адресам. PUSH уменьшает SP, POP увеличивает SP.} +\end{figure} + +Такое направление роста удобно для ABI вызовов: caller формирует блок аргументов (argument block), затем CALL кладёт адрес возврата (return PC) непосредственно \textbf{перед} ним, а callee может обращаться к аргументам по положительным смещениям от входного SP или от стабильного FP. + +\subsection{Низкоуровневые операции STACK} + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{24mm}L{56mm}Y@{}} +\toprule +\textbf{Инструкция} & \textbf{Изменение SP} & \textbf{Смысл}\\ +\midrule +\code{PUSH R} & \code{SP -= sizeof(R)} & Записать представление регистра в \code{STACK[SP]}.\\ +\code{POP R} & \code{SP += sizeof(R)} после чтения & Прочитать значение из текущей вершины стека.\\ +\code{LDSP R,off} & не изменяется & Прочитать объект по адресу \code{SP + off}.\\ +\code{STSP off,R} & не изменяется & Записать объект по адресу \code{SP + off}.\\ +\code{ADJSP off} & \code{SP += signed(off)} & Явно зарезервировать или освободить область стека.\\ +\bottomrule +\end{tabularx} +\end{center} + +CPU не добавляет скрытого padding или alignment. ABI требует 16-byte alignment перед ABI-conforming CALL, но конкретные \code{ADJSP}, padding slots и offsets формирует assembler/compiler. Низкоуровневые операции остаются byte-addressable и допускают unaligned addresses, если конкретное ABI-правило не требует большего выравнивания. + +\begin{principle} +SP --- не обычная переменная. Каждое изменение SP меняет границу живой stack storage. Выделение и освобождение памяти должны быть симметричны, а любой PTR64 на освобождённую stack-область становится семантически недействительным. +\end{principle} + +\section{CALL/RET, блок аргументов (argument block) и PSW calling convention} + +Нормативный ABI отделяет \textbf{блок аргументов (argument block)}, принадлежащий caller-у, от 8-байтового адрес возврата (return PC), который автоматически добавляет CALL. Непосредственно перед ABI-conforming CALL значение SP кратно 16. Caller заранее резервирует цельный блок аргументов (argument block), размещает в нём hidden-result pointer (если он нужен) и explicit arguments, затем выполняет CALL. + +\subsection{Размещение блок аргументов (argument block)} + +Argument block строится от меньших offsets к большим в порядке параметров функции. Если функция возвращает aggregate, hidden result PTR64 занимает slot 0. Для каждого аргумента: + +\begin{codebox} +\begin{verbatim} +offset = align_up(offset, alignof(argument)) +argument.offset = offset +offset += sizeof(argument) + +argument_block_size = align_up(offset, 16) +\end{verbatim} +\end{codebox} + +Base блок аргументов (argument block) перед CALL должен быть выровнен на 16 bytes. CPU не знает типов аргументов и не вставляет padding автоматически: это правило assembler/compiler ABI. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,x=1cm,y=1cm] + \def\xL{2.4}\def\xR{8.3} + \fill[McpuGreenBg] (\xL,4.8) rectangle (\xR,5.6); + \fill[McpuGrayBg] (\xL,3.9) rectangle (\xR,4.8); + \fill[McpuGrayBg] (\xL,3.0) rectangle (\xR,3.9); + \fill[yellow!10] (\xL,2.2) rectangle (\xR,3.0); + \draw[McpuBlue,thick] (\xL,2.2) rectangle (\xR,5.6); + \foreach \y in {3.0,3.9,4.8} {\draw[McpuBlue2] (\xL,\y)--(\xR,\y);} + \node at (5.35,5.2) {адрес возврата (return PC) (8 bytes)}; + \node at (5.35,4.35) {блок аргументов (argument block) +0}; + \node at (5.35,3.45) {блок аргументов (argument block) +\dots}; + \node[color=McpuBlue2] at (5.35,2.6) {tail padding до 16 bytes}; + \node[anchor=west,color=McpuBlue] at (8.65,5.2) {SP + 0}; + \node[anchor=west,color=McpuBlue] at (8.65,4.35) {SP + 8}; + \node[anchor=west,color=McpuBlue] at (8.65,3.45) {SP + 8 + \dots}; + \node[anchor=west,color=McpuBlue2] at (1.0,6.05) {состояние callee сразу после CALL}; + \draw[decorate,decoration={brace,amplitude=5pt},McpuGreen] (1.95,4.8)--(1.95,2.2) + node[midway,left=7pt,align=right,color=McpuGreen]{argument\\block caller-а}; + \node[anchor=west,color=McpuBlue2] at (2.4,1.55) {base блок аргументов (argument block) = caller SP перед CALL; поэтому он выровнен на 16 bytes}; + \node[anchor=west,color=McpuBlue2] at (2.4,1.05) {после PUSHFP; SETFP тот же base находится по FP + 16}; +\end{tikzpicture} +\caption{CALL добавляет адрес возврата (return PC) перед уже сформированным блок аргументов (argument block).} +\end{figure} + +После CALL callee видит адрес возврата (return PC) по \code{SP+0}, а начало блок аргументов (argument block) --- по \code{SP+8}. RET снимает \textbf{только} адрес возврата (return PC). Весь блок аргументов (argument block) после возврата освобождает caller. + +\subsection{Простые PUSH остаются допустимым сокращением} + +Старый right-to-left PUSH spelling остаётся корректным там, где он создаёт тот же layout и оставляет SP кратным 16. Например два \code{r64} занимают ровно 16 bytes: + +\begin{lstlisting} +PUSH r64@arg2 +PUSH r64@arg1 +CALL f +ADJSP 16 +\end{lstlisting} + +Для одного \code{r64} блок аргументов (argument block) всё равно должен занимать 16 bytes: + +\begin{lstlisting} +ADJSP -16 +STSP 0, r64@arg1 +CALL f +ADJSP 16 +\end{lstlisting} + +\subsection{CALL, RET, FP и PSW} + +CALL и CALLP помещают 64-bit next PC в STACK; RET снимает его обратно в PC. Return address является raw PROGRAM byte offset (CODE64), а не PTR64. Регистра RA/LR нет. + +CALL/RET не изменяют FP и не сохраняют PSW автоматически. Arithmetic/status bits считаются caller-clobbered согласно принятому ABI, а persistent control bits должны быть восстановлены callee перед обычным возвратом, если callee их изменял. Сохранение FP --- отдельная обязанность функций, которые выбрали frame-pointer convention. + +\begin{principle} +CPU выполняет только механические действия CALL/RET. Типы аргументов, padding, hidden-result slot, владение блок аргументов (argument block) и сохранение долгоживущего состояния --- контракт ABI между caller, callee и compiler. +\end{principle} + +\section{Return Value Area} + +Верхние 8192 bytes register file зарезервированы ABI для канонического scalar return value. Это не отдельный физический регистр: результат размещается в обычном перекрывающемся register file так, чтобы \textbf{старший конец выбранного physical view совпадал с концом register file}. + +\begin{center} +\begin{tabularx}{0.82\textwidth}{@{}L{34mm}L{45mm}Y@{}} +\toprule +\textbf{View} & \textbf{Physical size} & \textbf{Канонический return register}\\ +\midrule +\code{r8} & 1 byte & \code{r8@0x7ffff}\\ +\code{r16} & 2 bytes & \code{r16@0x7fffe}\\ +\code{r32} & 4 bytes & \code{r32@0x7fffc}\\ +\code{r64} & 8 bytes & \code{r64@0x7fff8}\\ +\code{r4096} & 512 bytes & \code{r4096@0x7fe00}\\ +\code{r65536} & 8192 bytes & \code{r65536@0x7e000}\\ +\code{c64} & 8 bytes & \code{c64@0x7fff8}\\ +\code{c4096} & 512 bytes & \code{c4096@0x7fe00}\\ +\code{c65536} & 8192 bytes & \code{c65536@0x7e000}\\ +\bottomrule +\end{tabularx} +\end{center} + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,x=1cm,y=1cm] + \draw[McpuBlue,thick] (0.8,1.2) rectangle (11.5,2.55); + \fill[McpuGrayBg] (0.82,1.22) rectangle (9.5,2.53); + \fill[McpuGreenBg] (9.5,1.22) rectangle (11.48,2.53); + \draw[McpuBlue2] (9.5,1.2)--(9.5,2.55); + \node at (5.1,1.88) {обычная volatile register area}; + \node[align=center,color=McpuBlue] at (10.48,1.88) {Return Value\\Area, 8 KiB}; + \node[anchor=north,color=McpuBlue2] at (0.8,1.05) {0x00000}; + \node[anchor=north,color=McpuBlue2] at (9.5,1.05) {0x7e000}; + \node[anchor=north,color=McpuBlue2] at (11.5,1.05) {0x80000}; + \draw[->,McpuGreen,very thick] (1.3,3.15)--(8.95,3.15); + \node[color=McpuGreen,above] at (5.1,3.15) {automatic register allocation растёт вверх}; +\end{tikzpicture} +\caption{Верхние 8 KiB register file зарезервированы под канонический scalar result.} +\end{figure} + +Return Value Area является volatile across CALL. Если caller должен сохранить результат через следующий вызов функции, он обязан скопировать его в собственный register slot или memory object. + +\section{PTR64: сегментированный виртуальный} +указатель PTR64 является 64-битным архитектурным указателем, но не host pointer. Старшие 4 бита выбирают segment selector, младшие 60 - byte offset внутри сегмента. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + SEG BYTE OFFSET + bits 63..60 bits 59..0 + 4 bits 60 bits +\end{lstlisting} + +Каждый selector получает виртуальный диапазон 260 bytes = 1 EiB. Назначения 0x0..0x7 зафиксированы архитектурой; 0x8..0xF остаются резервом. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + SEG Имя Назначение Guest dereference + + 0x0 DATA static/global objects R/W + + 0x1 STACK call/automatic storage R/W + + 0x2 PROGRAM machine code R only + + 0x3 CONTROL run control / configuration R only + + 0x4 INPUT environment -> model R only + + 0x5 OUTPUT model -> environment R/W + + 0x6 TRACE current telemetry frame R/W + + 0x7 HEAP runtime dynamic storage R/W, low guard excluded + + 0x8..0xF reserved future spaces POINTER_FAULT +\end{lstlisting} + +PTR64 = (SEG << 60) | OFFSET + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + SEG(ptr) = (ptr >> 60) & 0xF +\end{lstlisting} + +OFFSET(ptr) = ptr \& 0x0FFFFFFFFFFFFFFF + +NULL остаётся единственным all-zero value. 0x0000000000000000 = PTR64(DATA,0). Назначение новых selectors не меняет NULL semantics. DATA[0..15] является NULL guard; HEAP[0..15] является отдельным heap guard, но PTR64(HEAP,0) не является NULL. + +ADDR64 и PTR64 - не одно и то же. ADDR64 в прямых LOAD/STORE остаётся raw DATA offset. PTR64 является runtime value с selector+offset и используется косвенными memory/ control-flow operations. + +\section{Создание указателей: LEA, LEASP, LEAFP} +\subsection{LEA: полный PTR64 immediate} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LEA r64@dst, symbol_or_expression +\end{lstlisting} + +machine: OPCODE16 + REG24 + PTR64IMM = 13 bytes runtime: r64@dst = decoded PTR64 immediate + +LEA сохраняет прежний размер 13 bytes, но его 64-bit machine field теперь нормативно трактуется как полный PTR64 immediate, а не как DATA-only ADDR64. Ассемблер определяет selector по section, к которой принадлежит label: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + Label section LEA result + + .data PTR64(DATA, offset) + + .control PTR64(CONTROL, offset) + + .input PTR64(INPUT, offset) + + .output PTR64(OUTPUT, offset) + + .trace PTR64(TRACE, offset) + + .init / .text / .fini PTR64(PROGRAM, offset) + + .input +\end{lstlisting} + +force: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .real 128, 0.0 + + .text +\end{lstlisting} + +\_life: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LEA r64@0x00100, force ; PTR64(INPUT, offset(force)) + LOADP r128@0x00200, r64@0x00100 +\end{lstlisting} + +Чистое absolute/.equ expression без section label сохраняет историческую DATA semantics. Для DATA-label binary encoding остаётся совместимым с прежним LEA: selector DATA равен нулю, поэтому старший nibble 64-bit field не меняет bytes. + +\subsection{LEASP и LEAFP} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LEASP r64@dst, signed_offset -> PTR64(STACK, SP + signed_offset) + LEAFP r64@dst, signed_offset -> PTR64(STACK, FP + signed_offset) +\end{lstlisting} + +Эти instructions остаются специальными быстрыми constructors для automatic stack objects. Формирование one-past pointer допустимо при offset, равном architectural segment size; dereference всё равно требует, чтобы полный transfer range был valid. + +\section{Косвенная адресация: LOADP и STOREP} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LOADP R/C, r64(PTR64) ; memory[ptr] -> register + STOREP r64(PTR64), R/C ; register -> memory[ptr] +\end{lstlisting} + +machine size = OPCODE16 + REG24 + REG24 = 8 bytes + +Pointer operand всегда является physical r64. Размер transfer задаётся шириной value-register; bytes копируются без endian conversion. + +\begin{center} +\begin{tabularx}{0.98\textwidth}{@{}L{25mm}L{24mm}L{24mm}Y@{}} +\toprule +\textbf{Сегмент} & \textbf{LOADP} & \textbf{STOREP} & \textbf{Причина политики доступа}\\ +\midrule +DATA & да & да & обычная изменяемая память\\ +STACK & да & да & автоматические объекты и кадры вызовов\\ +PROGRAM & да & нет & код доступен для чтения, запись запрещена\\ +CONTROL & да & нет & конфигурация принадлежит runtime/supervisor\\ +INPUT & да & нет & входные воздействия принадлежат среде\\ +OUTPUT & да & да & модель формирует выходные данные\\ +TRACE & да & да & модель формирует текущий telemetry frame\\ +HEAP & да & да & динамическая guest-память; offsets 0..15 защищены\\ +0x8..0xF & POINTER\_FAULT & POINTER\_FAULT & селектор не назначен\\ +\bottomrule +\end{tabularx} +\end{center} + +CPU не хранит type tag у PTR64. Pointer provenance, pointee type, object lifetime, ownership и масштабирование на sizeof(T) являются ответственностью compiler/runtime ABI. CONTROL и INPUT read-only именно для guest CPU; host runtime API имеет право обновлять их в разрешённые lifecycle points. + +\section{Pointer arithmetic} +Pointer arithmetic выполняется только над 60-битным BYTE OFFSET. Четырёхбитный SEG никогда не участвует в переносе или заёме и всегда сохраняется без изменения. Единица смещения - один байт. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,x=0.22cm,y=0.85cm,>=Latex] + \draw[fill=McpuGreenBg] (0,0) rectangle (4,1); + \draw[fill=McpuBlueBg] (4,0) rectangle (32,1); + \node at (2,0.5) {SEG}; + \node at (18,0.5) {BYTE OFFSET (60 bits)}; + \node[above] at (2,1) {4 bits}; + \draw[->,very thick,McpuGreen] (2,-0.25) -- (2,-1.05) node[below,align=center]{копируется\\без изменения}; + \draw[<->,very thick,McpuBlue] (8,-0.55) -- (28,-0.55) node[midway,below=2pt]{\(\pm\) signed byte delta}; + \node[below=13mm,text=McpuUrl,align=center] at (24,0) {перенос/заём за bit 59\\$\rightarrow$ POINTER\_FAULT}; +\end{tikzpicture} +\caption{PADD/PSUB изменяют только OFFSET; SEG остаётся неизменным.} +\end{figure} + +\subsection{Набор инструкций} +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{27mm}Y L{22mm}@{}} +\toprule +\textbf{Мнемоника} & \textbf{Семантика} & \textbf{Размер}\\ +\midrule +PADD d,p,n & \code{d = p + signed64(n)} & 11 bytes\\ +PADDI d,p,k & \code{d = p + signed OFF64(k)} & 16 bytes\\ +PSUB d,p,n & \code{d = p - signed64(n)} & 11 bytes\\ +PSUBI d,p,k & \code{d = p - signed OFF64(k)} & 16 bytes\\ +PDIFF d,a,b & \code{d = OFFSET(a) - OFFSET(b)}, signed byte count & 11 bytes\\ +\bottomrule +\end{tabularx} +\end{center} + +Во всех register-формах операнды обязаны быть физическими r64. Для PADD/PSUB третий r64 трактуется как знаковое 64-битное число в дополнительном коде. Для PADDI/PSUBI смещение кодируется существующим OFF64 в canonical MSB-first byte order. Реализация использует фиксированные типы LibMPU \_\_mpu\_int64\_t и \_\_mpu\_uint64\_t, выбранные configure с гарантированной шириной 64 бита. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + PADD r64@dst, r64@ptr, r64@delta + PADDI r64@dst, r64@ptr, 24 + PSUB r64@dst, r64@ptr, r64@delta + PSUBI r64@dst, r64@ptr, -16 + PDIFF r64@bytes, r64@p2, r64@p1 +\end{lstlisting} + +\subsection{Границы и fault} +Результирующий offset обязан лежать в диапазоне 0 .. 0x0fffffffffffffff. Попытка выйти ниже нуля или выше 60-битного предела вызывает CPU\_EXEC\_POINTER\_FAULT. Destination при fault не изменяется. PSW pointer arithmetic не изменяет. + +Важно: PADD/PSUB не выполняют dereference и поэтому не сравнивают offset с фактически выделенным размером DATA/STACK/PROGRAM. Они проверяют только архитектурную 60-битную границу PTR64. Фактические границы проверяются позднее, при выполнении \code{LOADP/STOREP}. Это позволяет формировать one-past и промежуточные указатели; их языковая допустимость остаётся задачей compiler. + +\subsection{PDIFF} +PDIFF разрешён только если segment selectors обоих PTR64 совпадают. Разность двух 60-битных offsets всегда помещается в signed 64 bits и возвращается как число байтов. Разные SEG дают CPU\_EXEC\_POINTER\_FAULT. Само значение SEG может быть и зарезервированным: арифметика его только сравнивает/сохраняет и не пытается dereference. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; conceptual C lowering + p + n -> PADDI/PADD with n * sizeof(*p) bytes + p - n -> PSUBI/PSUB with n * sizeof(*p) bytes + p2 - p1 -> PDIFF byte_delta; compiler scales by sizeof(*p) +\end{lstlisting} + +ISA сознательно не содержит операции pointer + pointer. Типовая арифметика, масштабирование элементов, provenance и правила сравнения принадлежат high-level compiler. + +\section{FP как специальное архитектурное состояние} + +\term{FP}{frame pointer, указатель кадра} --- третий специальный 64-битный координатный регистр CPU рядом с PC и SP. Он не занимает байты register file и не является PTR64. В контексте CPU FP хранит raw byte offset внутри STACK. + +\begin{center} +\begin{tabularx}{0.9\textwidth}{@{}L{22mm}L{36mm}Y@{}} +\toprule +\textbf{Состояние} & \textbf{Физический смысл} & \textbf{Назначение}\\ +\midrule +PC & 64-bit offset в PROGRAM & адрес следующей machine instruction\\ +SP & 64-bit offset в STACK & подвижная граница живой stack storage\\ +FP & 64-bit offset в STACK & стабильная база текущего stack frame\\ +PSW & 32-bit status/control word & FLAGS, traps/interrupt mode и status bits\\ +\bottomrule +\end{tabularx} +\end{center} + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,node distance=8mm] + \node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,minimum width=31mm,minimum height=10mm] (pc) {PC}; + \node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of pc,minimum width=31mm,minimum height=10mm] (sp) {SP}; + \node[draw=McpuBlue,rounded corners,fill=McpuGreenBg,right=of sp,minimum width=31mm,minimum height=10mm] (fp) {FP}; + \node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of fp,minimum width=31mm,minimum height=10mm] (psw) {PSW}; + \node[below=3mm of pc,color=McpuBlue2] {PROGRAM offset}; + \node[below=3mm of sp,color=McpuBlue2] {STACK offset}; + \node[below=3mm of fp,color=McpuBlue2] {STACK offset}; + \node[below=3mm of psw,color=McpuBlue2] {status/control}; + \node[draw=McpuBlue2,fill=McpuCode,below=15mm of $(sp)!0.5!(fp)$,minimum width=108mm,minimum height=12mm] (rf) {512 KiB перекрывающегося register file}; + \draw[McpuGreen,dashed,thick] ($(fp.south)+(0,-2mm)$) -- ($(fp.south)+(0,-8mm)$); + \node[below=2mm of rf,color=McpuGreen,align=center] {FP не является \code{r64@...} и не занимает ни одного байта register file}; +\end{tikzpicture} +\caption{FP относится к специальному состоянию CPU и не перекрывается с register file.} +\end{figure} + +При создании STACK начальное состояние равно \code{SP = FP = stack_size}. FP является optional: leaf/simple function может вообще не устанавливать frame pointer. Compiler включает FP, когда нужна стабильная база для fixed locals, VLA/runtime-sized objects, spills, сложных frames или удобной диагностики. + +\section{Кадр стека (stack frame): пролог и эпилог} + +Сразу после обычного CALL layout определяется относительно входного SP: + +\begin{center} +\begin{tabularx}{0.78\textwidth}{@{}L{34mm}Y@{}} +\toprule +\textbf{Адрес} & \textbf{Содержимое}\\ +\midrule +\code{SP + 0} & адрес возврата (return PC)\\ +\code{SP + 8} & начало блок аргументов (argument block)\\ +\code{SP + 8 + k} & argument slot с block offset \code{k}\\ +\bottomrule +\end{tabularx} +\end{center} + +Функция, использующая FP, выполняет канонический prologue: + +\begin{lstlisting} +PUSHFP +SETFP +ADJSP -fixed_frame_size +\end{lstlisting} + +\code{PUSHFP} сохраняет старый FP как 64-bit value и уменьшает SP на 8. \code{SETFP} фиксирует текущий SP как базу нового frame. После этого fixed locals получают стабильные отрицательные offsets от FP, а arguments --- стабильные положительные offsets. + +\begin{center} +\begin{tabularx}{0.88\textwidth}{@{}L{27mm}L{34mm}Y@{}} +\toprule +\textbf{Offset от FP} & \textbf{Объект} & \textbf{Комментарий}\\ +\midrule +\code{FP + 0} & сохранённый FP caller-а & значение, записанное PUSHFP\\ +\code{FP + 8} & адрес возврата (return PC) & значение, записанное CALL\\ +\code{FP + 16} & блок аргументов (argument block) +0 & начало блока аргументов caller-а\\ +\code{FP + 16 + k} & argument slot & аргумент с block offset \code{k}\\ +\code{FP - ...} & fixed locals/spills & offsets назначает compiler/frame layout\\ +\bottomrule +\end{tabularx} +\end{center} + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,x=1cm,y=1cm] + \def\xL{3.0}\def\xR{8.5} + \fill[McpuGreenBg] (\xL,5.0) rectangle (\xR,6.0); + \fill[McpuGrayBg] (\xL,4.0) rectangle (\xR,5.0); + \fill[yellow!11] (\xL,3.1) rectangle (\xR,4.0); + \fill[yellow!11] (\xL,2.2) rectangle (\xR,3.1); + \fill[McpuGrayBg] (\xL,1.2) rectangle (\xR,2.2); + \draw[McpuBlue,thick] (\xL,1.2) rectangle (\xR,6.0); + \foreach \y in {2.2,3.1,4.0,5.0} {\draw[McpuBlue2] (\xL,\y)--(\xR,\y);} + \node at (5.75,5.5) {динамические объекты / VLA}; + \node at (5.75,4.5) {фиксированные локальные объекты / spills}; + \node at (5.75,3.55) {сохранённый FP caller-а}; + \node at (5.75,2.65) {адрес возврата (return PC)}; + \node at (5.75,1.7) {блок аргументов (argument block)}; + \draw[McpuGreen,very thick] (2.55,4.0)--(8.9,4.0); + \node[anchor=east,color=McpuGreen] at (2.4,4.0) {FP}; + \draw[McpuBlue,very thick] (2.55,5.88)--(8.9,5.88); + \node[anchor=east,color=McpuBlue] at (2.4,5.88) {SP}; + \node[anchor=west,color=McpuBlue2] at (8.8,3.55) {FP + 0}; + \node[anchor=west,color=McpuBlue2] at (8.8,2.65) {FP + 8}; + \node[anchor=west,color=McpuBlue2] at (8.8,1.7) {FP + 16 + ...}; + \node[anchor=west,color=McpuBlue2] at (0.4,6.15) {малые STACK offsets}; + \node[anchor=west,color=McpuBlue2] at (0.4,1.0) {большие STACK offsets}; + \draw[->,McpuBlue,very thick] (9.8,5.45)--(9.8,4.65); + \node[anchor=west,color=McpuBlue] at (10.0,5.05) {SP может двигаться}; +\end{tikzpicture} +\caption{Frame с FP: fixed objects имеют стабильные offsets, а SP может двигаться ниже FP.} +\end{figure} + +\subsection{Инструкции управления кадром (frame instructions)} + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{20mm}L{25mm}Y@{}} +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Семантика}\\ +\midrule +0x5030 & \code{PUSHFP} & \code{SP -= 8; STACK[SP] = FP}\\ +0x5031 & \code{SETFP} & \code{FP = SP}\\ +0x5032 & \code{RESTSP} & \code{SP = FP}\\ +0x5033 & \code{POPFP} & \code{FP = STACK[SP]; SP += 8}\\ +\bottomrule +\end{tabularx} +\end{center} + +Канонический epilogue: + +\begin{lstlisting} +RESTSP ; discard dynamic and fixed frame storage below FP +POPFP ; restore caller FP; SP now points to адрес возврата (return PC) +RET ; restore PC +\end{lstlisting} + +CALL/RET сами FP не меняют. Сохранение и восстановление frame pointer является частью prologue/epilogue только тех функций, которые решили использовать FP. Leaf/simple functions могут работать только через SP. + +\begin{principle} +Главное назначение FP --- отделить стабильную геометрию frame от временных движений SP. Fixed local всегда остаётся по тому же \code{FP-offset}, даже если функция создаёт outgoing блок аргументов (argument block)s или runtime-sized temporary storage. +\end{principle} + +\section{Адресация относительно FP (FP-relative addressing)} +Три инструкции являются прямыми аналогами SP-relative операций, но используют стабильную базу FP: + +\begin{center} +\begin{tabularx}{0.97\textwidth}{@{}L{20mm}L{38mm}L{42mm}Y@{}} +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Машинный формат} & \textbf{Семантика}\\ +\midrule +0x5040 & LDFP R, OFF64 & 2 + 3 + 8 = 13 bytes & \code{R = STACK[FP + off]}\\ +0x5041 & STFP OFF64, R & 2 + 8 + 3 = 13 bytes & \code{STACK[FP + off] = R}\\ +0x5042 & LEAFP r64, OFF64 & 2 + 3 + 8 = 13 bytes & \code{r64 = PTR64(STACK, FP + off)}\\ +\bottomrule +\end{tabularx} +\end{center} + +OFF64 - signed 64-bit byte displacement в canonical MSB-first encoding. Для LDFP/STFP CPU проверяет, что полный range объекта помещается в физически allocated STACK. LEAFP проверяет вычисленный offset и разрешает pointer formation на границе stack\_size (one-past), но не выполняет dereference. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; fixed local scalar at FP-8 + STFP -8, r64@0x00100 + LDFP r64@0x00108, -8 + + ; pointer to that local object + LEAFP r64@0x00110, -8 + LOADP r64@0x00118, r64@0x00110 +\end{lstlisting} + +\subsection{Смещения блока аргументов после установки FP} +После PUSHFP; SETFP начало блок аргументов (argument block) всегда имеет фиксированный адрес FP+16. Но offsets individual arguments вычисляются внутри блока по их ABI alignment. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + FP + 0 сохранённый FP caller-а + FP + 8 адрес возврата (return PC) + FP + 16 блок аргументов (argument block) base + FP + 16 + k argument at block offset k + ... +\end{lstlisting} + +Без aggregate return первый explicit argument имеет block offset 0. При aggregate return hidden result PTR64 занимает block offset 0, а первый explicit argument начинается с align\_up(8, alignof(arg1)). Поэтому, например, для 8-byte aligned arg1 это FP+24, а для 16-byte aligned arg1 - FP+32. + +Compiler invariant: между SETFP и соответствующим POPFP FP рассматривается compiler-ом как стабильная база. PUSH/POP/CALL/ADJSP/SETSP не меняют FP. + +\section{Динамическое выделение памяти в STACK и SETSP} +Dynamic objects не требуют отдельной ALLOCA-инструкции. LibMCPU использует уже существующие PTR64 + pointer arithmetic и одну операцию установки SP: + +\begin{center} +\begin{tabularx}{0.92\textwidth}{@{}L{20mm}L{34mm}L{28mm}Y@{}} +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Машинный формат} & \textbf{Семантика}\\ +\midrule +0x5050 & SETSP r64(PTR64) & 2 + 3 = 5 bytes & если SEG=STACK и offset входит в allocated STACK, \code{SP = OFFSET(ptr)}\\ +\bottomrule +\end{tabularx} +\end{center} + +SETSP принимает только физический r64 с PTR64. DATA/PROGRAM/reserved segment дают CPU\_EXEC\_POINTER\_FAULT; STACK offset больше фактического stack\_size даёт CPU\_EXEC\_STACK\_FAULT. При fault SP не изменяется. + +\subsection{Выделение N байт во время выполнения} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; r64@0x00118 contains runtime byte count N + LEASP r64@0x00110, 0 ; mark = PTR64(STACK, текущий SP) + PSUB r64@0x00120, r64@0x00110, r64@0x00118 + SETSP r64@0x00120 ; reserve N bytes downward + LEASP r64@0x00130, 0 ; &object == new stack top + + ; ... use object through r64@0x00130 ... + + SETSP r64@0x00110 ; release this dynamic scope +\end{lstlisting} + +Pointer arithmetic работает в байтах. Масштабирование n * sizeof(T) и alignment выполняет compiler. CPU не добавляет hidden padding. + +\subsection{Понижение VLA (VLA-style lowering)} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; VLA/dynamic object lowering. + ; Assume compiler has already computed the required aligned byte count + ; into r64@0x00118 at runtime. +\end{lstlisting} + +f: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + PUSHFP + SETFP + ADJSP -16 ; fixed part of frame, if needed + + LEASP r64@0x00110, 0 ; save stack mark before dynamic object + PSUB r64@0x00120, r64@0x00110, r64@0x00118 + SETSP r64@0x00120 + LEASP r64@0x00130, 0 ; PTR64 to first byte of dynamic object + + ; ... access object through r64@0x00130 ... + + RESTSP ; releases dynamic and fixed frame storage + POPFP + RET +\end{lstlisting} + +Размер dynamic object. CPU получает число байтов уже вычисленным в обычном r64. Вычисление n * sizeof(T), overflow checks и align-up относятся к compiler lowering и могут использовать доступные integer operations. Механизм FP/SETSP от конкретного способа вычисления размера не зависит. + +\subsection{Вложенные динамические области} + +Runtime-sized objects удобно освобождать не по размеру, а восстановлением заранее сохранённой stack mark: + +\begin{lstlisting} +LEASP r64@0x00200, 0 ; внешняя отметка +; allocate object A +... +LEASP r64@0x00208, 0 ; внутренняя отметка +; allocate object B +... +SETSP r64@0x00208 ; release B-scope +... +SETSP r64@0x00200 ; release A-scope +\end{lstlisting} + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,x=1cm,y=1cm] + \def\xL{3.0}\def\xR{8.8} + \fill[McpuGreenBg] (\xL,5.1) rectangle (\xR,6.0); + \fill[McpuGreenBg] (\xL,4.15) rectangle (\xR,5.1); + \fill[McpuGrayBg] (\xL,3.15) rectangle (\xR,4.15); + \fill[yellow!11] (\xL,2.25) rectangle (\xR,3.15); + \fill[yellow!11] (\xL,1.35) rectangle (\xR,2.25); + \draw[McpuBlue,thick] (\xL,1.35) rectangle (\xR,6.0); + \foreach \y in {2.25,3.15,4.15,5.1} {\draw[McpuBlue2] (\xL,\y)--(\xR,\y);} + \node at (5.9,5.55) {внутренняя динамическая область B}; + \node at (5.9,4.62) {динамическая область A}; + \node at (5.9,3.65) {фиксированная часть frame}; + \node[color=McpuBlue2] at (5.9,3.37) {адресуется относительно FP}; + \node at (5.9,2.70) {saved FP}; + \node at (5.9,1.80) {адрес возврата (return PC)}; + \draw[McpuBlue,very thick] (2.55,5.85)--(9.15,5.85); + \node[anchor=east,color=McpuBlue] at (2.4,5.85) {текущий SP}; + \draw[McpuGreen,thick] (2.7,5.1)--(9.0,5.1); + \node[anchor=west,color=McpuGreen] at (9.2,5.1) {внутренняя отметка}; + \draw[McpuGreen,thick] (2.7,4.15)--(9.0,4.15); + \node[anchor=west,color=McpuGreen] at (9.2,4.15) {внешняя отметка}; + \draw[McpuBlue2,very thick] (2.7,3.15)--(9.0,3.15); + \node[anchor=west,color=McpuBlue2] at (9.2,3.15) {FP}; +\end{tikzpicture} +\caption{Dynamic scopes меняют SP, но FP и fixed frame остаются стабильными.} +\end{figure} + +\begin{normative} +Когда frame установлен, compiler не должен использовать SETSP для выхода выше FP и не должен захватывать caller-owned bytes. CPU аппаратно проверяет границы всего allocated STACK; принадлежность конкретных bytes текущему frame контролирует compiler/ABI. +\end{normative} + +\section{C-подобная модель автоматических объектов (automatic objects)} + +STACK является полноценной памятью automatic storage duration. Локальные структуры, union, массивы, VLA и runtime-sized temporaries живут в stack frame. Scalar locals могут оставаться в register file либо spill-иться в STACK. + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{37mm}L{58mm}Y@{}} +\toprule +\textbf{Объект} & \textbf{Рекомендуемая база} & \textbf{Время жизни}\\ +\midrule +fixed scalar spill & FP + fixed negative offset & до RESTSP / возврата\\ +fixed struct/array & FP + fixed negative offset & до RESTSP / возврата\\ +VLA/runtime object & PTR64 от LEASP после SETSP & до восстановления соответствующей stack mark / RESTSP\\ +argument & FP + positive offset; без FP --- SP-relative & в пределах call\\ +\bottomrule +\end{tabularx} +\end{center} + +PTR64 на automatic object имеет обычный C-like lifetime: после освобождения dynamic scope или frame он становится семантически недействительным, даже если underlying STACK bytes физически ещё существуют. + +Alignment не является скрытой функцией CPU. Для ABI-conforming frame/argument layout используется максимум 16 bytes natural alignment и 16-byte CALL alignment; offsets и padding явно создаются assembler/compiler. + +\section{Формальный ABI аргументов} +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{55mm}Y@{}} +\toprule +\textbf{Категория} & \textbf{ABI representation}\\ +\midrule +Integer scalar & by value в блок аргументов (argument block)\\ +Real scalar & by value в блок аргументов (argument block)\\ +Complex scalar & by value в блок аргументов (argument block)\\ +PTR64 & 8-byte scalar by value\\ +struct/union by value & полное object representation в блок аргументов (argument block)\\ +struct/union by pointer & PTR64 на исходный object\\ +array parameter в C-like semantics & PTR64 на первый element\\ +\bottomrule +\end{tabularx} +\end{center} + +Argument block base имеет alignment 16. Каждый slot получает ABI alignment своего значения; полный размер блока округляется к 16. Padding является частью call layout, но не частью значения scalar argument. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; one r64 argument + ADJSP -16 + STSP 0, r64@0x00000 + CALL f + ADJSP 16 +\end{lstlisting} + +На входе callee блок аргументов (argument block) начинается по SP+8. Если callee выполняет PUSHFP; SETFP, тот же block начинается по FP+16. First explicit argument без hidden result имеет block offset 0; при hidden result его offset вычисляется по обычному align-up rule и не обязан быть фиксированным. + +Почему это важно. Если hidden PTR64 занимает block offset 0, следующий argument с alignment 8 начнётся с +8, а argument с alignment 16 - с +16. Поэтому ABI не кодирует постоянную формулу «первый explicit argument всегда hidden+8». + +\section{Структуры и массивы} +\subsection{Fixed local struct} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + PUSHFP + SETFP + ADJSP -16 + + STFP -16, r64@0x00100 + STFP -8, r64@0x00108 + LEAFP r64@0x00110, -16 ; &local_struct + ... +\end{lstlisting} + +\subsection{Structure by value} +Caller создаёт exact copy complete object representation в argument area. Для memory-to-memory переноса используется BMOV/BMOVI, поэтому aggregate не обязан проходить через register file и его размер не ограничен 8192 bytes максимального register view. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; struct S s occupies 48 bytes in caller frame + LEAFP r64@0x00100, -96 ; src = &s + ADJSP -48 ; 48-byte блок аргументов (argument block), already 16-aligned + LEASP r64@0x00108, 0 ; dst = argument slot +0 + BMOVI r64@0x00108, r64@0x00100, 48 + CALL f + ADJSP 48 ; caller cleanup +\end{lstlisting} + +\subsection{Local array / VLA} +Массив фиксированного размера получает постоянное отрицательное смещение от FP. VLA получает динамическую область STACK через LEASP/PSUB/SETSP; compiler сохраняет PTR64 на начало массива в регистре или spill-слоте, если текущий SP затем будет двигаться дальше. + +\subsection{Array argument} +В обычной C-семантике array parameter передаётся как PTR64 на первый element. Копирование всего массива не происходит. + +\section{Aggregate return: hidden result pointer} +Scalar integer/real/complex/pointer возвращаются через Return Value Area. Structure/union произвольного размера использует caller-provided storage и hidden PTR64. + +Hidden result is argument slot 0. Caller помещает PTR64 destination в block offset 0, затем layout explicit arguments начинается после него с обычным align-up. В callee без FP block base находится по SP+8; после PUSHFP; SETFP - по FP+16. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; Example: hidden result PTR64 + aggregate argument aligned to 8 + ; block offset +0 hidden result PTR64 + ; block offset +8 explicit aggregate + ; block is rounded up to 16-byte total size + + ; callee with FP + PUSHFP + SETFP + LDFP r64@0x00100, 16 ; hidden result = block +0 + ; explicit offsets are determined by ABI layout, not by a universal constant + ... + RESTSP + POPFP + RET +\end{lstlisting} + +Callee записывает aggregate bytes через hidden PTR64. RET не копирует aggregate и не трогает Return Value Area для такого результата. Caller освобождает весь блок аргументов (argument block) одним ADJSP. + +\section{Block copy: BMOV и BMOVI} +Block-copy переносит произвольное число байтов непосредственно между архитектурными memory spaces через PTR64. Register file используется только для самих указателей и, в форме BMOV, для runtime byte count. Содержимое копируемого объекта не проходит через REG24. + +\begin{center} +\begin{tabularx}{0.97\textwidth}{@{}L{20mm}L{45mm}Y L{18mm}@{}} +\toprule +\textbf{Код операции} & \textbf{Мнемоника} & \textbf{Машинный формат} & \textbf{Размер}\\ +\midrule +0x0150 & BMOV dst, src, count & OPCODE16 + REG24 + REG24 + REG24 & 11 bytes\\ +0x0151 & BMOVI dst, src, IMM64 & OPCODE16 + REG24 + REG24 + IMM64 & 16 bytes\\ +\bottomrule +\end{tabularx} +\end{center} + +Все register operands этих двух инструкций обязаны быть физическими r64. Первые два r64 содержат PTR64 destination и source. Третий r64 у BMOV интерпретируется как unsigned 64-bit byte count (\_\_mpu\_uint64\_t). У BMOVI byte count находится непосредственно в PROGRAM как unsigned IMM64, MSB-first. + +Семантика всегда memmove. Если source и destination ranges перекрываются в одном сегменте, результат обязан быть таким же, как у C memmove(). Направление физического копирования не является частью ISA и выбирается реализацией. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + BMOVI r64@dst_ptr, r64@src_ptr, 64 + ; copies exactly 64 bytes + + LDI r64@size, 4096 + BMOV r64@dst_ptr, r64@src_ptr, r64@size + ; runtime-sized 4096-byte copy +\end{lstlisting} + +\subsection{Разрешённые memory spaces} +\begin{center} +\begin{tabularx}{0.82\textwidth}{@{}L{38mm}L{35mm}Y@{}} +\toprule +\textbf{Segment} & \textbf{Source} & \textbf{Destination}\\ +\midrule +DATA (0x0) & да & да\\ +STACK (0x1) & да & да\\ +PROGRAM (0x2) & да & нет\\ +CONTROL (0x3) & да & нет\\ +INPUT (0x4) & да & нет\\ +OUTPUT (0x5) & да & да\\ +TRACE (0x6) & да & да\\ +HEAP (0x7) & да, кроме low guard & да, кроме low guard\\ +0x8..0xF & POINTER_FAULT & POINTER_FAULT\\ +\bottomrule +\end{tabularx} +\end{center} + +BMOV/BMOVI используют те же segment access rules, что LOADP/STOREP. CONTROL и INPUT могут быть sources, но не destinations. OUTPUT/TRACE/HEAP являются обычными writable data-object spaces. PROGRAM остаётся read-only source. + +\subsection{Проверка ranges и atomicity} +До первого изменения destination CPU обязан: + +1. прочитать оба PTR64 и byte count; 2. проверить source segment и полный range [src, src+count); 3. проверить destination segment, write permission и полный range [dst, dst+count); 4. только после успешных проверок выполнить block move. + +Правило атомарной ошибки: если диапазон source или destination недопустим, байты destination не изменяются. BMOV/BMOVI не меняют PSW, SP, FP и сами PTR64-регистры. + +PTR64 offset может быть one-past физического сегмента только при нулевом размере. count == 0 является корректным no-op после проверки segment/access policy; запись в PROGRAM остаётся запрещённой даже для destination PROGRAM. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,x=1cm,y=1cm] + \node[anchor=west,color=McpuBlue2] at (0.2,2.7) {До \code{BMOVI dst=src+8, count=16}:}; + \foreach \i/\lab in {0/A,1/B,2/C,3/D} { + \draw[McpuBlue] (1.0+1.5*\i,1.55) rectangle ++(1.5,0.72); + \node at (1.75+1.5*\i,1.91) {\lab}; + } + \draw[->,McpuGreen,thick] (1.0,1.3)--(1.0,0.92) node[below,color=McpuGreen]{source}; + \draw[->,McpuBlue,thick] (2.5,1.3)--(2.5,0.92) node[below,color=McpuBlue]{destination}; + \node[anchor=west,color=McpuBlue2] at (0.2,0.10) {После memmove-semantics:}; + \foreach \i/\lab in {0/A,1/A,2/B,3/D} { + \draw[McpuBlue] (6.8+1.5*\i,0.0) rectangle ++(1.5,0.72); + \node at (7.55+1.5*\i,0.36) {\lab}; + } +\end{tikzpicture} +\caption{BMOV/BMOVI определены как memmove, поэтому overlapping ranges обрабатываются корректно.} +\end{figure} + +\subsection{Lowering: assignment структуры} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; C-like: dst = src; sizeof(struct S) = 64 + LEAFP r64@0x00100, -64 ; &dst + LEAFP r64@0x00108, -128 ; &src + BMOVI r64@0x00100, r64@0x00108, 64 +\end{lstlisting} + +CPU копирует complete object representation, включая padding bytes. Понимание полей структуры остаётся задачей compiler. + +\subsection{Lowering: aggregate argument by value} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; source aggregate S lives at FP-96, sizeof(S)=48, align <=16 + LEAFP r64@0x00100, -96 + ADJSP -48 ; complete 16-aligned блок аргументов (argument block) + LEASP r64@0x00108, 0 + BMOVI r64@0x00108, r64@0x00100, 48 + CALL consume_S + ADJSP 48 +\end{lstlisting} + +Для нескольких arguments assembler/compiler вычисляет offsets внутри цельного блок аргументов (argument block) в declaration order, соблюдая alignment каждого slot; общий размер округляется к 16. + +\subsection{Lowering: aggregate return через hidden PTR64} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; callee with FP; hidden result PTR64 at FP+16 + LDFP r64@0x00100, 16 ; destination supplied by caller + LEAFP r64@0x00108, -128 ; local result object + BMOVI r64@0x00100, r64@0x00108, 128 + RESTSP + POPFP + RET +\end{lstlisting} + +RET по-прежнему не знает о структуре. BMOVI просто переносит готовый object representation в caller-provided storage. + +\subsection{Runtime-sized arrays и VLA} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; dst_ptr and src_ptr are PTR64; r64@0x00110 = runtime byte count + BMOV r64@0x00100, r64@0x00108, r64@0x00110 +\end{lstlisting} + +Compiler предварительно вычисляет element\_count * sizeof(T), выполняет требуемые overflow checks и передаёт итоговый byte count. BMOV не знает element type и не выполняет масштабирование. + +\subsection{memcpy и memmove в C-like frontend} +Одна архитектурная операция достаточна для обеих high-level семантик. Вызов memmove естественно lowering-ится в BMOV/BMOVI. memcpy также может lowering-иться в ту же инструкцию: memmove-semantics являются более сильной гарантией и не меняют результат программы при неперекрывающихся ranges. Frontend всё равно может диагностировать нарушение своих собственных правил aliasing/overlap. + +\section{ABI data layout и assembler alignment} +\subsection{Natural alignment} +Базовое правило LibMCPU ABI для обычного scalar/object storage: + +natural\_alignment = min(sizeof(object), 16) + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ABI_MAX_ALIGN = 16 + STACK/CALL_ALIGN = 16 +\end{lstlisting} + +Это означает, например: r8 -> align 1, r32 -> align 4, r64/PTR64 -> align 8, r128 и все более крупные numeric objects -> align 16. Размер объекта при этом не меняется: real4096 занимает 512 bytes, но ABI-natural alignment равен 16, а не 512. + +\subsection{Assembler не вставляет hidden alignment} +.integer, .real и .complex записывают bytes непосредственно в текущую DATA position. Только явный .align N меняет position. Благодаря этому один и тот же assembler поддерживает normal и packed layout. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; normal ABI-like layout + .data + .align 16 +\end{lstlisting} + +obj: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 8, 1 ; offset +0 + .align 4 + .integer 32, 2 ; next 4-byte aligned field + .align 2 + .integer 16, 3 + .align 4 ; trailing struct padding + + ; packed binary layout: no implicit padding +\end{lstlisting} + +packed\_obj: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 8, 1 + .integer 32, 2 + .integer 16, 3 +\end{lstlisting} + +Explicit .align может быть больше 16 (например 64, 512 или 4096) для специальных таблиц, cache/page oriented data или внешнего формата. Такое требование относится к guest offset и не увеличивает ABI natural alignment типа. + +\subsection{Normal и packed aggregate layout} +Для normal aggregate поля размещаются с их natural alignment, alignment aggregate равен максимуму alignment полей (не более 16), а sizeof округляется вверх до aggregate alignment. Packed aggregate имеет alignment 1, не имеет automatic internal/trailing padding и сохраняет внутренний layout вложенного normal aggregate как самостоятельного типа. + +Bit-fields. LibMCPU ABI не требует отдельного bit-field layout: необходимые операции представляются обычными integer masks/shifts. Это сохраняет binary layout явным и переносимым. + diff --git a/doc/src/libmcpu-architecture-runtime-ru.tex b/doc/src/libmcpu-architecture-runtime-ru.tex new file mode 100644 index 0000000..2ecf4cb --- /dev/null +++ b/doc/src/libmcpu-architecture-runtime-ru.tex @@ -0,0 +1,349 @@ +\section{Host backing memory spaces и loader} +Host allocation не является частью PTR64. Активные architectural memory spaces имеют независимый anonymous mmap() backing; guest pointer содержит selector+offset и никогда не содержит host virtual address. + +\subsection{Anonymous mmap only} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + mmap(NULL, capacity, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0) +\end{lstlisting} + +PROGRAM, DATA, STACK, CONTROL, INPUT, OUTPUT, TRACE и HEAP получают отдельные mappings. Loader читает image bytes обычным read() в anonymous memory. PROGRAM после загрузки переводится host-side в read-only mapping; guest access policy дополнительно проверяется instruction resolver. CONTROL/INPUT сохраняются host-writable, потому что runtime должен иметь возможность менять configuration/input между фазами исполнения, но guest STOREP в них запрещён. + +\subsection{Architectural size, capacity и HEAP limit} +\begin{center} +\begin{tabularx}{0.92\textwidth}{@{}L{34mm}Y@{}} +\toprule +\textbf{Величина} & \textbf{Смысл}\\ +\midrule +\code{segment.size} & точное число байтов, доступных guest-программе\\ +\code{segment.capacity} & округлённый по страницам размер host mapping\\ +\code{heap.size} & текущий guest-visible размер HEAP\\ +\code{heap.capacity} & текущая вместимость host backing HEAP\\ +\code{heap.limit} & настроенный неизменяемый максимальный размер HEAP\\ +\bottomrule +\end{tabularx} +\end{center} + +Все CPU bounds checks используют architectural size, а не host capacity. HEAP additionally reserves offsets 0..15; первый ordinary heap byte имеет offset CPU\_HEAP\_BEGIN = 16. + +Relocatable host backing. PTR64(HEAP,offset) не зависит от host base. Поэтому будущая реализация heap growth может создать larger anonymous mapping, скопировать bytes и заменить host base, не меняя ни одного guest pointer. + +\subsection{MELF loader и окончательный process image} +Начиная с MELF ABI, development sidecar images не являются форматом запуска. \code{mcpu-ld} создаёт ET_EXEC/ET_DYN с segment metadata, а \code{mcpu-run} валидирует target description, program-model metadata, program headers и relocation records до передачи управления guest. Для ABI v2 все preload-модули сначала полностью читаются и валидируются, затем назначаются независимые PROGRAM/DATA bases, после чего применяются retained relocations. PROGRAM после relocation phase переводится в read-only host mapping. + +\section{Fault, atomicity и invariants} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + • REG24 проверяет width, natural alignment и границы register file. + • JMPP/CALLP требуют PROGRAM PTR64: NULL, другой SEG или offset вне program.size дают + POINTER_FAULT до изменения PC/SP/STACK. + • CALLP сначала валидирует target и stack space; return PC записывается только после + успешной полной проверки. + • All-zero PTR64 является NULL и даёт POINTER_FAULT при indirect dereference. + • Assembler резервирует DATA[0..15]; ordinary DATA labels начинаются не раньше 0x10. + • CODE64 target должен ссылаться внутрь PROGRAM. + • STACK operations сначала проверяют bounds, затем меняют SP/FP/memory. + • PUSHFP проверяет место и корректность текущего FP до записи. + • POPFP сначала читает saved value и проверяет saved_fp <= stack_size; при fault ни FP, + ни SP не меняются. + • SETFP требует allocated STACK и корректный SP. + • RESTSP требует FP <= stack_size. + • LDFP/STFP/LEAFP используют signed OFF64 относительно FP и выполняют bounds + checking. + • SETSP принимает только STACK PTR64; wrong segment -> pointer fault, out-of-range offset + -> stack fault. + • Ни одна FP/SP management instruction не меняет PSW. + • CALL/CALLP/RET сами PSW-neutral; normal-function ABI считает PSW[15:0] volatile, TF/IF/ + MODE persistent control state, HF отдельным execution state. + • PADD/PADDI/PSUB/PSUBI проверяют 60-bit PTR64 offset, но не object lifetime. + + + + • BMOV/BMOVI сначала проверяют complete source и destination ranges; при fault destination + memory не изменяется. Overlap разрешён и имеет memmove semantics. + • CPU не обеспечивает ownership текущего frame: правило SP <= FP внутри FP-frame и + stack-scope discipline обеспечиваются compiler/ABI. +\end{lstlisting} + +Нельзя хранить долгоживущий указатель на automatic object после release scope/frame. PTR64 остаётся битово корректным, но high-level program нарушает lifetime. Это семантическая ошибка compiler/program, а не PTR64 encoding fault. + +\section{Byte order и architectural object representation} +LibMCPU намеренно разделяет два независимых byte-order domain. Это один из фундаментальных ABI contracts: PROGRAM является переносимым сериализованным instruction stream, а register file и memory segments содержат runtime objects в target representation, совместимом с LibMPU. + +\begin{figure}[ht] +\centering +\begin{tikzpicture}[font=\sffamily\small,>=Latex,node distance=12mm and 15mm] + \node[draw=McpuBlue,very thick,rounded corners,fill=McpuBlueBg,minimum width=72mm,minimum height=22mm,align=center] (prog) + {\textbf{PROGRAM / machine fields}\\[-1mm]\scriptsize OPCODE16, REG24, IMM64, ADDR64, CODE64, OFF64\\\textbf{канонический MSB-first}}; + \node[draw=McpuGreen,very thick,rounded corners,fill=McpuGreenBg,right=of prog,minimum width=72mm,minimum height=22mm,align=center] (data) + {\textbf{Архитектурные объекты данных}\\[-1mm]\scriptsize register file, DATA, STACK, CONTROL, INPUT, OUTPUT, TRACE, HEAP\\\textbf{target representation LibMPU}}; + \draw[->,thick,McpuBlue2] (prog) -- node[above]{decode / execute} (data); + \node[below=11mm of prog,align=center,font=\ttfamily\small] (pb) {0x1122334455667788\\11 22 33 44 55 66 77 88}; + \node[below=11mm of data,align=center,font=\ttfamily\small] (db) {тот же u64 на текущем LE target\\88 77 66 55 44 33 22 11}; + \draw[->,McpuBlue] (prog.south) -- (pb.north); + \draw[->,McpuGreen] (data.south) -- (db.north); +\end{tikzpicture} +\caption{Сериализация PROGRAM и целевое представление объектов данных являются разными byte-order domains.} +\end{figure} + +\subsection{PROGRAM: canonical MSB-first} +Все multi-byte machine fields внутри PROGRAM кодируются старшим байтом вперёд. Это правило не зависит от host CPU, LibMPU byte order или будущего object-file container. + +value = 0x1122334455667788 + +IMM64 / CODE64 / ADDR64 / OFF64 bytes: 11 22 33 44 55 66 77 88 + +REG24 также является canonical machine field: его три байта формируются из WIDTH и ADDRESS по уже определённому битовому layout. Decoder не делает C-cast на packed host structure. + +\subsection{Data-object domain} +Register file, DATA, STACK, CONTROL, INPUT, OUTPUT, TRACE и HEAP используют одно target object representation. Для integer-like objects byte order берётся из target profile LibMCPU, который совпадает с configured LibMPU: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + CPU_DATA_BYTE_ORDER = MPU_BYTE_ORDER + CPU_DATA_WORD_ORDER = MPU_WORD_ORDER + CPU_DATA_BYTE_ORDER_* = corresponding LibMPU settings + CPU_DATA_WORD_ORDER_* = corresponding LibMPU settings +\end{lstlisting} + +На текущей little-endian конфигурации: + +u64 value 0x1122334455667788 address+0 88 address+1 77 address+2 66 address+3 55 address+4 44 address+5 33 address+6 22 address+7 11 + +Общее representation. Если один object скопирован между register file или любыми data-object spaces без числового преобразования, его bytes не переставляются. Endian conversion не является скрытым side effect memory instructions. + +\subsection{Явные helper families в реализации} +Чтобы source code executor/assembler визуально не смешивал два domain, используются две группы accessors: + +\_\_cpu\_code\_get\_u16 / \_\_cpu\_code\_put\_u16 \_\_cpu\_code\_get\_u32 / \_\_cpu\_code\_put\_u32 \_\_cpu\_code\_get\_u64 / \_\_cpu\_code\_put\_u64 + +\_\_cpu\_data\_get\_u16 / \_\_cpu\_data\_put\_u16 \_\_cpu\_data\_get\_u32 / \_\_cpu\_data\_put\_u32 \_\_cpu\_data\_get\_u64 / \_\_cpu\_data\_put\_u64 + +code-helpers явно собирают/разбирают MSB-first fields. data-helpers работают с target object representation через byte-safe copy semantics. Слово data здесь означает architectural data-object domain, а не только PTR64 segment DATA=0x0; эти helpers применимы также к register-file и STACK bytes. + +Именно поэтому выбрано имя \_\_cpu\_data\_get\_u*, а не \_\_cpu\_object\_get\_u*: в исходниках сразу виден контраст code vs data. Во избежание путаницы с segment DATA это значение термина закреплено в ABI documentation. + +\subsection{Integer, PTR64, return PC и overlapping registers} +Signed integer использует two's-complement; unsigned - binary modulo 2\textasciicircum{}N. Их физический byte/word order является target data profile. PTR64 логически остаётся 4-bit SEG + 60-bit OFFSET, но когда он находится в r64, DATA field, STACK argument или structure member, это обычный 64-bit data object. + +PTR64(PROGRAM, 0x1234) = 0x2000000000001234 + +current LE target bytes: 34 12 00 00 00 00 00 20 + +Return PC, который CALL/CALLP помещают в STACK, тоже является 64-bit STACK data object. В самой CALL instruction CODE64 target encoded MSB-first; pushed return PC хранится в target data representation. RET читает его как data object и устанавливает логический PC. + +Overlapping register views физически наблюдают одни и те же bytes. Поэтому endian-sensitive assembler code, который разбирает широкое integer value через меньшие overlapping views, является target-specific low-level code. Это допустимо и сознательно является частью ABI. + +\subsection{Real и Complex} +LibMCPU не вводит отдельный формат floating/complex objects поверх LibMPU. Для real<bits> применяется external object representation соответствующего LibMPU real type при текущем target profile. Для complex<bits> используется LibMPU complex representation двух real components половинной ширины. + +Complex physical half order не фиксируется независимым правилом LibMCPU. Он следует configured LibMPU word-order profile. Нельзя считать универсальной истиной, что первые bytes complex object всегда являются real component, а вторые - imaginary component. Complex arithmetic должен использовать C-opcodes/LibMPU representation либо явно target-specific byte code. + +\subsection{Assembler data directives} +Directive inside .data создаёт target data object либо явно заданную raw byte sequence, а не canonical machine field: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data + .align 8 +\end{lstlisting} + +x: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 64, 0x1122334455667788 +\end{lstlisting} + +text16: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .ucs2 "Андрей" +\end{lstlisting} + +text8: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .utf8 "Андрей" +\end{lstlisting} + +raw: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .byte 0x11, 0x22, 0x33 + + .align 8 +\end{lstlisting} + +jump: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .cptr target + + .text +\end{lstlisting} + +target: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + HALT +\end{lstlisting} + +На текущем LE target bytes объекта x идут как 88 77 66 55 44 33 22 11. Но literal того же значения в LDI находится в PROGRAM как canonical 11 22 33 44 55 66 77 88. .integer/.int, .real и .complex генерируют target/LibMPU object representation. .ucs2 пишет target-representation 16-bit code units, тогда как .utf8 и .byte являются raw byte sequences без endian conversion. .cptr генерирует target-representation PTR64(PROGRAM,label/ expression). + +.cptr является каноническим mnemonic directive. Исторический .codeptr принимается assembler как compatibility alias. .label не используется: запись name: уже определяет label, тогда как .cptr создаёт объект-указатель. Полные правила строк, .equ и expressions приведены в разделе 34. + +\subsection{Byte-preserving memory operations} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LOAD / STORE + LOADP / STOREP + PUSH / POP + LDSP / STSP + LDFP / STFP + BMOV / BMOVI +\end{lstlisting} + +Эти операции не знают endian semantics конкретного объекта. Они переносят physical bytes. В частности: + +DATA source --LOAD--> register A DATA source --BMOV--> DATA/STACK destination --LOAD--> register B + +bytes(register A) == bytes(register B) + +Точно так же structure/array/packed object может быть скопирован BMOV без type metadata и без byte swap. Padding bytes, если они являются частью complete object representation, тоже сохраняются. + +\subsection{Raw bytes, packed I/O и external byte order} +char, byte arrays, UTF-8 и arbitrary binary blobs являются последовательностями байтов и сами по себе endian не имеют. packed означает отсутствие layout padding, но не означает network/ big-endian или little-endian protocol representation. + +Если внешний файл/протокол требует конкретный byte order, assembler/program должен выполнить явное преобразование. Автоматическая endian conversion при LOAD/STORE запрещена этой ABI-моделью. Для явного разворота физического порядка байтов LibMCPU предоставляет универсальную инструкцию BSWAP, подробно определённую в разделе 32. Она не подменяет понятие external byte order: решение о необходимости swap принимает программа или инструмент. + +\subsection{Target metadata в MELF} +MELF уже содержит нормативную target metadata: byte order/container encoding, machine id и MCPU target description. Loader не пытается эвристически переконвертировать DATA/STACK-compatible objects при несовместимом profile. Образ либо совместим с текущей LibMPU target representation, либо отвергается до исполнения. PROGRAM machine fields при этом сохраняют отдельное canonical MSB-first кодирование. + +\subsection{Host alignment и unaligned accesses} +Byte order не меняет ранее принятые alignment rules. Guest memory остаётся byte-addressable; unaligned accesses разрешены ISA. Реализация не должна читать произвольную guest memory через alignment-sensitive или strict-aliasing-unsafe casts. \_\_cpu\_data\_get\_u*/put используют + +byte-safe copy semantics, а большие arbitrary objects перемещаются memcpy/memmove или LibMPU routines. + +\section{Pointer comparison, red zone, active/reserved} +PTR64 и BSWAP Этот раздел фиксирует четыре низкоуровневых соглашения CPU/assembler ABI, необходимые до появления object/executable format: сравнение PTR64, отсутствие stack red zone, поведение активных/зарезервированных segment selectors и универсальное преобразование порядка физических байтов. + +\subsection{Equality и ordering для PTR64} +PTR64 остаётся обычным 64-битным архитектурным значением. Для равенства/неравенства сравниваются все 64 бита: selector и 60-bit offset. Поэтому существующего integer compare достаточно: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ICMP r64@p, r64@q + JZ equal + JNZ not_equal +\end{lstlisting} + +Это правило корректно и для разных selector: DATA:0x100 и STACK:0x100 не равны, поскольку их полные PTR64 различаются. Обычный ICMP может также выдавать signed integer flags для двух pointer bit patterns, однако ABI не придаёт этому результату смысла pointer ordering. + +Pointer ordering определяется только внутри одного segment selector и выполняется через PDIFF. Если selectors различны, PDIFF возвращает CPU\_EXEC\_POINTER\_FAULT и destination остаётся неизменным. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + PDIFF r64@delta, r64@p, r64@q ; signed byte difference + ITEST r64@delta, r64@delta + JS p_less_than_q + JZ p_equal_q +\end{lstlisting} + +Разность двух 60-bit offsets всегда помещается в signed 64-bit диапазон. CPU не знает границ high-level объектов/массивов: same-segment ordering является низкоуровневой адресной операцией, а object-domain restrictions будущего языка остаются задачей compiler/program. + +\subsection{Stack red zone отсутствует} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + CPU_ABI_STACK_RED_ZONE_SIZE = 0 +\end{lstlisting} + +STACK растёт вниз. Если текущий SP = X, байты ниже X не считаются принадлежащими функции как скрытая scratch-area. Функция должна сначала явно изменить SP через ADJSP или валидированный SETSP, а уже затем использовать выделенную область. + +Важно: ISA может физически позволить SP-relative address с отрицательным OFF64, если он попадает в allocated STACK. Это не превращает область ниже текущего SP в ABI red zone. Использование невыделенных bytes является ABI violation, а не обязательным аппаратным fault. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; неправильно как normal ABI scratch + STSP -8, r64@tmp + + ; правильно + ADJSP -16 + STSP 0, r64@tmp + ... + ADJSP 16 +\end{lstlisting} + +Отсутствие red zone упрощает будущие traps/interrupts: обработчик может строить собственный frame ниже текущего SP, не уничтожая скрытые temporaries leaf-функции. + +\subsection{Active и reserved PTR64 selectors} +Selectors 0x0..0x7 имеют назначенную address-space semantics. Selectors 0x8..0xF остаются структурно допустимыми PTR64 values, но не имеют memory semantics. Это сохраняет возможность будущего расширения без изменения PTR64 encoding. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + Операция над reserved PTR64 Правило +\end{lstlisting} + +(0x8..0xF) + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + MOV / SWAP / byte storage разрешено: bit pattern можно копировать и хранить + + ICMP equality / inequality разрешено как full 64-bit comparison + + PADD/PADDI/PSUB/PSUBI разрешено; selector сохраняется, arithmetic только по 60-bit + offset + + PDIFF разрешено только при одинаковом selector + + LOADP / STOREP / BMOV / BMOVI CPU_EXEC_POINTER_FAULT + + JMPP / CALLP CPU_EXEC_POINTER_FAULT + + SETSP CPU_EXEC_POINTER_FAULT +\end{lstlisting} + +HEAP теперь является активным selector 0x7. Его low guard 0..15 недоступен для dereference, но это не делает HEAP:0 значением NULL. All-zero DATA:0 остаётся единственным NULL PTR64. + +\subsection{BSWAP: raw byte reversal} +BSWAP имеет opcode 0x0103 и 8-byte machine form: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + BSWAP r<bits>@dst, r<bits>@src +\end{lstlisting} + +OPCODE16 + REG24(dst) + REG24(src) + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + 2 bytes + 3 bytes + 3 bytes = 8 bytes +\end{lstlisting} + +Оба operands обязаны иметь одинаковую физическую ширину. Ассемблер использует именно r<bits> syntax, подчёркивая raw/non-complex interpretation. Допустимы все существующие widths от r8 до r65536. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + source: b0 b1 b2 ... b(N-2) b(N-1) +\end{lstlisting} + +destination: b(N-1) b(N-2) ... b1 b0 + +r8 является identity. Для r65536 разворачиваются все 8192 bytes. BSWAP не знает, является ли содержимое integer, PTR64, real, complex или частью packed record: операция определена только над физическими байтами. + +PSW invariant. BSWAP не изменяет ни volatile status flags, ни TF/IF/MODE/HF. Width mismatch возвращает CPU\_EXEC\_WIDTH\_FAULT до изменения destination. + +\subsection{In-place и snapshot semantics} +Архитектурно BSWAP определяется как чтение полного source snapshot и только затем запись reversed bytes в destination. Поэтому in-place форма полностью определена: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + BSWAP r64@0x00100, r64@0x00100 +\end{lstlisting} + +При текущем natural alignment equal-width register views не могут частично перекрываться иначе, чем полностью совпасть. Тем не менее snapshot formulation является нормативной и не зависит от внутренних оптимизаций исполнителя. + +\subsection{External binary formats} +BSWAP не означает «to little endian» или «to big endian». Она лишь разворачивает bytes. Решение о swap принимает программа/tool, сравнивая external format с текущим CPU\_DATA\_BYTE\_ORDER. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + ; native target-order value + LDI r64@0x00000, 42 + + ; физически reversed representation (например wire order, если он противоположен target) + BSWAP r64@0x00008, r64@0x00000 + + ; обратное преобразование + BSWAP r64@0x00010, r64@0x00008 +\end{lstlisting} + +Для packed file/protocol records это даёт явное и предсказуемое преобразование. Packed layout и byte order остаются независимыми понятиями: packed убирает padding, BSWAP меняет порядок bytes конкретного field. + diff --git a/doc/src/libmcpu-assembler-details-ru.tex b/doc/src/libmcpu-assembler-details-ru.tex new file mode 100644 index 0000000..75a5c4a --- /dev/null +++ b/doc/src/libmcpu-assembler-details-ru.tex @@ -0,0 +1,233 @@ +\section{Ассемблер: UTF-8 source, строки, .equ и arithmetic expressions} +Низкоуровневый mcpu-as обязан уметь описывать binary images data-like sections, labels и relocation-like address expressions без обязательного текстового препроцессора. Текстовая метапрограмма (\#define, \#include, conditional compilation, parameterized macros) остаётся отдельным будущим слоем. В assembler входят только механизмы, непосредственно связанные с machine/data representation и разрешением символов. + +\subsection{Кодировка assembler source} +Исходный файл mcpu-as всегда UTF-8. Результат сборки не зависит от LANG, LC\_CTYPE или другой locale host-системы. Перед разбором assembler проверяет source как well-formed UTF-8 через LibMPUIO. + +Это особенно важно для строковых директив: одинаковый .s обязан создавать одинаковые image bytes на любых build hosts при одинаковом LibMCPU target profile. + +\subsection{Командная строка mcpu-as} +Ассемблер всегда создаёт один перемещаемый объект MELF ET\_REL, поэтому отдельный переключатель режима сборки не нужен. Выходной файл задаётся обычной UNIX-опцией \code{-o}, а единственный исходный файл является позиционным аргументом: + +\begin{lstlisting}[language={}] +mcpu-as -o file.o file.s +mcpu-as file.s -o file.o +\end{lstlisting} + +Обе формы полностью эквивалентны: порядок \code{-o} и входного файла свободный. Ровно один входной файл и ровно один выходной файл обязательны. Опции \code{-h} и \code{--help} печатают справку. Историческая форма \code{mcpu-as -c input.s output.o} удалена: \code{-c} больше не является опцией, поскольку другого режима работы у assembler нет. + +\subsection{.utf8 - NUL-terminated UTF-8 byte string} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data +\end{lstlisting} + +name\_utf8: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .utf8 "Андрей" +\end{lstlisting} + +.utf8 записывает UTF-8 payload буквально как bytes и добавляет один завершающий 0x00. Никакого target endian преобразования и никакой locale conversion нет. + +"Андрей" -> D0 90 D0 BD D0 B4 D1 80 D0 B5 D0 B9 00 + +Поддерживаются escapes \textbackslash{}\textbackslash{}, \textbackslash{}", \textbackslash{}n, \textbackslash{}r, \textbackslash{}t, \textbackslash{}b, \textbackslash{}f, \textbackslash{}v, \textbackslash{}a, byte escape \textbackslash{}xHH, а также Unicode scalar escapes \textbackslash{}uXXXX и \textbackslash{}UXXXXXXXX. Результирующая последовательность снова проверяется как UTF-8. + +Встроенный NUL внутри .utf8/.ucs2 намеренно не поддерживается: эти директивы определяют C-style NUL-terminated strings. Для произвольного binary layout с внутренними нулями используется .byte или .integer/.int. + +\subsection{.ucs2 - UTF-8 source literal в strict UCS-2 target objects} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .data +\end{lstlisting} + +name\_ucs2: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .ucs2 "Андрей" +\end{lstlisting} + +Assembler сначала получает UTF-8 literal, затем использует strict LibMPUIO UTF-8 -> UCS-2 conversion. Каждый UCS-2 code unit записывается как отдельный 16-bit architectural data object с помощью target data byte order; в конце добавляется U+0000. + +U+0410 U+043D U+0434 U+0440 U+0435 U+0439 U+0000 + +current little-endian target bytes: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + 10 04 3D 04 34 04 40 04 35 04 39 04 00 00 +\end{lstlisting} + +Strict UCS-2 допускает scalar values U+0000..U+FFFF, кроме surrogate range U+D800..U+DFFF. UTF-8 characters выше U+FFFF (например emoji) не раскладываются на UTF-16 surrogate pairs, а дают assembler error. Таким образом .ucs2 точно соответствует принятой в LibMCPU/LibMPUIO модели UCS-2, а не UTF-16. + +\subsection{.byte, .integer и .int} +.byte создаёт raw bytes без implicit terminator, alignment или endian conversion: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .byte 0x4c, 0x43, 0x50, 0x55 + .byte 1, 2+3, BLOCK_SIZE/512 +\end{lstlisting} + +Каждый элемент должен находиться в диапазоне 0..255. .integer сохраняет прежний смысл typed integer object, а .int является полным синонимом. Обе директивы принимают список значений одной ширины: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 16, 0x0410, 0x043d, 0x0000 + .int 8, 65, 66, 0 +\end{lstlisting} + +Каждое значение формирует отдельный object указанной width непосредственно в текущей data-like section position; hidden padding отсутствует. + +\subsection{.equ - абсолютные assembler symbols} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .equ table_ptr, 0x03000 + .equ block_size, 4 * 512 + .equ next_reg, table_ptr + 8 +\end{lstlisting} + +.equ section-independent и не создаёт bytes. Имена symbols case-sensitive. Все .equ definitions собираются до emission, поэтому разрешены forward references между .equ symbols. + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .equ является absolute constant symbol. В текущем low-level assembler выражение +\end{lstlisting} + +справа может ссылаться на integer literals и другие .equ, но не на DATA/CODE labels. Это сохраняет различие между absolute assembler symbols и section-relative labels/relocations MELF. + +Имя label не может совпадать с именем .equ. + +\subsection{Integer expression grammar и precedence} +primary := integer | symbol | '(' expression ')' + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + unary := ['+' | '-'] unary | primary +\end{lstlisting} + +product := unary \{ ('*' | '/' | '\%') unary \} expression := product \{ ('+' | '-') product \} + +Операции имеют обычный arithmetic precedence: unary, затем multiply/divide/remainder, затем add/subtract. Division by zero, overflow internal expression domain и значение вне требуемой width дают assembler error. + +Expressions используются для absolute numeric operands: register byte address, LDI, stack/pointer signed offsets, BMOVI count, .align, .byte, integer widths/values и других соответствующих immediate fields. + +\subsection{Label expressions и fixups} +Address expressions дополнительно получают labels тех sections, которые допустимы для конкретного operand class. Поэтому assembler непосредственно поддерживает: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LEA r64@table_ptr, input_vector+8 ; selector follows label section + LOAD r64@next_reg, data_object+16 ; direct LOAD remains DATA-relative + JMP loop+0 ; PROGRAM CODE64 + CALL function + .cptr handler+0 +\end{lstlisting} + +LEA принимает labels из DATA/CONTROL/INPUT/OUTPUT/TRACE и code sections и создаёт полный PTR64 selector+offset. Direct LOAD/STORE остаются в namespace DATA labels + .equ. CODE64 operands и .cptr используют PROGRAM labels + .equ. Forward labels работают через fixups. CPU по-прежнему не хранит instruction-boundary metadata: arithmetic CODE expression обязано использоваться программистом осмысленно. + +\subsection{Symbolic register addresses} +REG24 byte address может быть integer expression из absolute .equ symbols: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .equ table_ptr, 0x03000 + .equ temp_ptr, table_ptr + 8 + + LEA r64@table_ptr, table + LDI r64@temp_ptr, 42 + LDI r64@(table_ptr + 16), 7 +\end{lstlisting} + +После вычисления expression assembler выполняет обычную проверку register width, natural alignment и границ 512 KiB register file. DATA/CODE labels в register-address expression не участвуют: label address и register-file byte address являются разными namespaces. + +\subsection{Граница mcpu-as и будущего препроцессора} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + Механизм Уровень Причина + + .init/.text/.fini/.data/.control/.input/.output/.trace, mcpu-as определяют layout + labels, .align executable/data + images + + .integer/.int/.real/.complex/.byte/.utf8/.ucs2/.cptr mcpu-as создают data-like + objects/bytes + + + + + + .equ, arithmetic expressions, symbol fixups mcpu-as необходимы для + адресов и будущих + relocations + + #define/#undef/#include/#if/#ifdef отдельный текстовая + preprocessor metaprogramming не + является machine + encoding + + parameterized macros / repetition отдельный source transformation + preprocessor до mcpu-as +\end{lstlisting} + +Таким образом обычный symbolic assembler остаётся самодостаточным, а будущая схема .S -> cpu-cpp -> mcpu-as может добавляться независимо и не усложняет binary semantics cpu-as. + +\subsection{Полный пример} +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .equ table_ptr, 0x03000 + .equ next_reg, table_ptr + 8 + .equ block_size, 4 * 512 + + .data +\end{lstlisting} + +name16: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .ucs2 "Андрей" +\end{lstlisting} + +name8: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .utf8 "Андрей" +\end{lstlisting} + +header: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .byte 0x4c, 0x43, 0x50, 0x55, block_size/512 +\end{lstlisting} + +letters: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .int 16, 0x0410, 0x043d, 0x0434, 0 + .align 16 +\end{lstlisting} + +answer: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + .integer 64, 42 + + .text +\end{lstlisting} + +start: + +\begin{lstlisting}[language={},basicstyle=\ttfamily\scriptsize] + LEA r64@table_ptr, name16 + LOAD r64@next_reg, answer + HALT +\end{lstlisting} + +Здесь ни один identifier не требует textual macro substitution: table\_ptr/next\_reg - absolute assembler symbols, name16/answer - DATA labels, а arithmetic expression вычисляется самим assembler. + + +\subsection{Маркеры строк препроцессора и логические координаты diagnostics} +После появления \code{mcpu-cpp} assembler не использует собственную директиву \code{\#line} для управления source coordinates. Вместо неё \code{mcpu-as} распознаёт маркеры строк, оставляемые препроцессором в выходном потоке: +\begin{lstlisting}[language={}] +# digit-sequence +# digit-sequence "filename" +# digit-sequence "filename" flags... +\end{lstlisting} +\code{digit-sequence} содержит как минимум одну decimal digit и всегда разбирается в основании 10, даже при leading zeroes. Допустимый диапазон - 0..2147483647. Значение задаёт logical line number для physical source line, непосредственно следующей за marker. Filename optional; при его отсутствии сохраняется предыдущий logical filename. Всё после закрывающей кавычки filename считается полем flags препроцессора и полностью игнорируется assembler. + +Marker не создаёт bytes, symbols, \code{__LINE__} или \code{__FILE__}, не участвует в expression evaluation и влияет только на source coordinates последующих diagnostics. Empty и comment-only ordinary lines увеличивают logical counter обычным образом. + +Строки \code{\#pragma} и \code{\#lang} предназначены для других участников toolchain: \code{mcpu-as} полностью игнорирует их и не увеличивает logical line counter. Любая другая строка, начинающаяся с \code{\#}, также удаляется из assembler token stream, но учитывается как одна ordinary logical source line. + +\begin{normative} +\textbf{Историческая форма \#line.} Запись \code{\#line N "file"} больше не является source-location directive \code{mcpu-as}. Она обрабатывается как обычная неизвестная строка \code{\#...}: игнорируется как assembler syntax и учитывается при продвижении logical counter. Координаты source задаются только preprocessing line marker формой \code{\# N "file" flags...}. Это diagnostics contract и не часть MELF ABI. +\end{normative} diff --git a/doc/src/libmcpu-assembler-directives-table.tex b/doc/src/libmcpu-assembler-directives-table.tex new file mode 100644 index 0000000..e7200b9 --- /dev/null +++ b/doc/src/libmcpu-assembler-directives-table.tex @@ -0,0 +1,37 @@ +\begin{longtable}{@{}L{35mm}L{48mm}L{76mm}@{}} +\toprule +\textbf{Директива} & \textbf{Форма} & \textbf{Назначение}\\ +\midrule +\endfirsthead +\toprule +\textbf{Директива} & \textbf{Форма} & \textbf{Назначение}\\ +\midrule +\endhead +\code{.init} & без аргументов & Переключает текущую code section на INIT. Для final low-level ET_EXEC здесь определяется \code{_start}; ET_DYN такую секцию иметь не может.\\ +\code{.text} & без аргументов & Основная PROGRAM code section. Здесь находится \code{_life}, а PROGRAM без отдельного INIT имеет \code{_start == _life}.\\ +\code{.fini} & без аргументов & FINI code section; low-level entry symbol --- \code{_fini}. HLL finalization создаётся CRT автоматически.\\ +\code{.data} & без аргументов & Инициализированные writable DATA objects.\\ +\code{.bss} & без аргументов & Zero-initialized DATA, сериализуется как NOBITS.\\ +\code{.control} & без аргументов & Model CONTROL space contribution; guest read-only во время исполнения. Только main ET_EXEC.\\ +\code{.input} & без аргументов & Model INPUT space contribution. Только main ET_EXEC.\\ +\code{.output} & без аргументов & Model OUTPUT space contribution. Только main ET_EXEC.\\ +\code{.trace} & без аргументов & Model TRACE space contribution. Только main ET_EXEC.\\ +\code{.align} & \code{.align N} & Выравнивает следующую позицию текущей section до степени/границы, проверяемой assembler-ом; добавляет padding либо увеличивает BSS size.\\ +\code{.zero} & \code{.zero N} & Резервирует N нулевых байтов; особенно естественна в \code{.bss}.\\ +\code{.byte} & \code{.byte expr[, ...]} & Записывает raw bytes 0..255 без terminator, alignment и endian conversion.\\ +\code{.integer}, \code{.int} & \code{.int bits, expr[, ...]} & Создаёт целые target objects заданной ширины. \code{.int} --- полный синоним \code{.integer}.\\ +\code{.real} & \code{.real bits, value} & Создаёт target Real object указанной physical width через LibMPU representation.\\ +\code{.complex} & \code{.complex bits, real, imag} & Создаёт target Complex object; \code{bits} задаёт physical width всего Complex object.\\ +\code{.utf8} & \code{.utf8 "text"} & Записывает проверенную UTF-8 NUL-terminated byte string. Embedded NUL не допускается.\\ +\code{.ucs2} & \code{.ucs2 "text"} & Преобразует UTF-8 source literal в strict UCS-2 target code units и добавляет U+0000. Surrogate range и scalar values выше U+FFFF запрещены.\\ +\code{.cptr}, \code{.codeptr} & \code{.cptr code-expr} & Создаёт PROGRAM/CODE pointer object с relocation при необходимости. \code{.codeptr} --- синоним.\\ +\code{.ptr} & \code{.ptr pointer-expr} & Создаёт полный PTR64 на допустимый target segment/label с relocation при необходимости.\\ +\code{.equ} & \code{.equ name, expr} & Определяет absolute assembler symbol, не создающий bytes. Допускает forward references между \code{.equ}; section labels в таком выражении не используются.\\ +\code{.global}, \code{.globl} & \code{.global name} & Делает symbol GLOBAL. \code{.globl} --- синоним.\\ +\code{.extern} & \code{.extern name} & Объявляет внешний undefined symbol для последующей компоновки.\\ +\code{.weak} & \code{.weak name} & Объявляет/помечает symbol как WEAK согласно MELF symbol binding.\\ +\bottomrule +\end{longtable} + +\paragraph{Особые синтаксические формы.} +\code{_start_life:} --- assembler pseudo-label, эквивалентный последовательным \code{_start:} и \code{_life:} по одному адресу в \code{.text}. Он не является директивой и не создаёт отдельный MELF symbol \code{_start_life}. Preprocessor line markers \code{\# N "file" flags...} меняют только logical coordinates diagnostics; \code{\#pragma} и \code{\#lang} игнорируются assembler-ом как строки, принадлежащие другим стадиям toolchain. diff --git a/doc/src/libmcpu-bytecode-architecture-ru.tex b/doc/src/libmcpu-bytecode-architecture-ru.tex new file mode 100644 index 0000000..cbf9268 --- /dev/null +++ b/doc/src/libmcpu-bytecode-architecture-ru.tex @@ -0,0 +1,230 @@ +\documentclass[10pt,a4paper,oneside,openany]{memoir} +\newcommand{\DocShortTitle}{LibMCPU: архитектура машинного кода и ABI} +\input{libmcpu-doc-common.tex} +\hypersetup{pdftitle={LibMCPU: архитектура машинного кода, памяти и ABI вызовов},pdfsubject={Технический справочник по архитектуре LibMCPU}} +\begin{document} +\DocTitlePage{LibMCPU: архитектура машинного кода,\\памяти и ABI вызовов}{Регистровая модель, ISA, PTR64, CALL ABI, lifecycle и runtime}{Техническое справочное руководство} + +\ManualIntro{Документ фиксирует текущий архитектурный контракт LibMCPU: register model, ISA, memory spaces, PTR64, CALL ABI, MELF lifecycle, syscall/error ABI, dynamic startup linking и подписанный HLL Runtime ABI между mcpu-ld, CRT и MCPU Libc. Документ намеренно не связан с номером выпуска пакета. Для бинарного формата MELF действует отдельное руководство \code{libmcpu-melf-abi-ru.pdf}.} + +\begin{principle} +\textbf{Главный принцип.} Физический регистр LibMCPU нетипизирован. \REG{} задаёт только физическую ширину и байтовый адрес в едином register file. Integer/Real/Complex смысл определяется opcode; запись \code{c<bits>@addr} является semantic view того же физического регистра. Архитектурный \PTR{} также является обычным 64-битным значением, но его декодирование и права доступа задаются ABI. +\end{principle} + +\tableofcontents +\clearpage + +\part{Базовая архитектура, ISA и CALL ABI} +\input{libmcpu-architecture-core-ru.tex} + +\part{Memory backing, представление объектов и assembler} +\input{libmcpu-architecture-runtime-ru.tex} +\input{libmcpu-isa-coverage-ru.tex} +\input{libmcpu-assembler-details-ru.tex} + +\part{Program Model ABI, runtime и динамическая загрузка} +\section{Program Model Lifecycle ABI} +Каждый исполняемый MELF-файл имеет обязательные lifecycle symbols \code{_start} и \code{_life}; \code{e_entry} всегда указывает на \code{_start}. Секция \code{.init} и символ \code{_fini} необязательны. Эти точки входа принадлежат MELF/runtime ABI и не должны смешиваться с функциями будущего языка высокого уровня. + +\subsection{С отдельным INIT} +\begin{lstlisting} +.init +_start: + ... one-time startup ... + END + +.text +_life: + ... resumable LIFE phase ... + END +\end{lstlisting} +Тогда \code{e_init_entry=_start}, а \code{e_life_entry=_life}. Первый \code{END} завершает INIT; runtime устанавливает PC в \code{_life} и начинает LIFE. Последующие LIFE \code{END} возвращают управление supervisor-у, а следующий resume продолжается с инструкции после соответствующего \code{END}. + +\subsection{Без INIT} +\begin{lstlisting} +.text +_start_life: + ... startup / ordinary program trampoline ... +\end{lstlisting} +Псевдометка \code{_start_life:} эквивалентна двум последовательным labels \code{_start:} и \code{_life:} по одному адресу. В final executable \code{e_init_entry=0} и \code{e_entry == e_life_entry}. Эта форма особенно естественна для обычной PROGRAM, которая заканчивается через \code{EXIT} и не создаёт LIFE boundaries. + +\subsection{FINI, END и EXIT} +\code{END} завершает текущую управляемую фазу и возвращает управление supervisor-у. Graceful \code{EXIT(status)} завершает normal execution; если имеется \code{.fini}/\code{_fini}, runtime сохраняет status, входит в FINI и требует завершить FINI инструкцией \code{END}. Второй \code{EXIT} внутри FINI не является нормальным контрактом. Diagnostic stop по \code{--steps} не симулирует graceful \code{EXIT} и потому сам по себе FINI не запускает. + +\input{libmcpu-hll-crt-contract-ru.tex} + +\section{McpuStartup и argc/argv} +Перед первой guest-инструкцией загрузчик создаёт постоянную область запуска (startup area) в верхней части STACK. Заголовок имеет размер 32 байта и выравнивание 16 байт: +\par\medskip +\noindent\begin{tabularx}{\textwidth}{@{}L{20mm}L{30mm}L{24mm}Y@{}} +\toprule +\textbf{Смещение} & \textbf{Поле} & \textbf{Размер} & \textbf{Значение}\\ +\midrule +0x00 & version & 4 & \code{MCPU_STARTUP_VERSION_1}\\ +0x04 & size & 4 & 32\\ +0x08 & argc & 8 & число аргументов guest-программы\\ +0x10 & argv & 8 & \PTR(STACK, массив argv)\\ +0x18 & reserved & 8 & ноль\\ +\bottomrule +\end{tabularx} +После заголовка расположен массив \code{argv[0..argc]} из PTR64, завершающий NULL, затем NUL-terminated строки аргументов. Эта область остаётся действительной всё время жизни executable. Начальное состояние: \code{PC=e_entry}, \code{SP=startup_base}, \code{FP=stack_size}. + +\section{HEAP и program break} +HEAP --- отдельный runtime-сегмент SEG=0x7. Он не расширяет DATA и не имеет assembler payload. Определяемый компоновщиком неподменяемый символ \code{_end} равен \PTR(HEAP,16); это начальный и минимальный program break. + +Runtime хранит \code{_heap_brk}, \code{_heap_size}, \code{_heap_capacity}, immutable \code{_heap_limit}. Запрос ниже 16 или выше limit отклоняется и возвращает прежний break. Shrink не обязан уменьшать host mapping/capacity; освобождённый range немедленно zeroes. Regrow в уже существующий backing снова открывает deterministic zero memory. При backing relocation guest pointers остаются valid, потому что содержат segment+offset. + +\section{SYSCALL ABI и SYS_brk} +Zero-operand instruction \code{SYSCALL} использует fixed overlapping register area в верхней части register file. +\par\medskip +\noindent\begin{tabularx}{\textwidth}{@{}L{32mm}L{32mm}Y@{}} +\toprule +\textbf{Role} & \textbf{Address/view} & \textbf{Meaning}\\ +\midrule +SYSNO & \code{r32@0x7fffc} & syscall number\\ +NARGS & \code{r32@0x7fff8} & argument count\\ +RET & \code{r64@0x7fff8} & return value; overlaps NARGS\\ +ARG0..ARG5 & \code{r64@0x7fff0} ... \code{r64@0x7ffc8} & up to six arguments\\ +\bottomrule +\end{tabularx} + +Первый syscall --- \code{SYS_brk}, number 10. Он требует один argument: NULL означает query, HEAP PTR64 requests absolute new break. Общее правило syscall ABI использует стабильные host-independent MCPU errno: неуспех возвращает отрицательное \code{-MCPU_errno}, а host errno преобразуется на sysdeps boundary и наружу не выходит. \code{SYS_brk} является специальным исключением: он возвращает фактический/current HEAP PTR64 и при accepted, и при rejected request. Unsupported syscall number возвращает \code{-ENOSYS} из MCPU errno namespace. + +\begin{lstlisting} +; query current break +MOV r32@0x7fff8, 1 +LDI r32@0x7fffc, 10 +CLR r64@0x7fff0 +SYSCALL +; result: r64@0x7fff8 +\end{lstlisting} + +\section{Startup dynamic linking: архитектурный взгляд} +Текущий normal dynamic contract --- frozen MELF ABI v3. \code{mcpu-ld --dynamic} создаёт ABI-v3 ET_EXEC, а \code{mcpu-ld --shared --soname=NAME} --- ABI-v3 ET_DYN. В отличие от исторического ABI v2, normal dependencies записываются в canonical non-ALLOC \code{.dynamic} как \code{DT_NEEDED}, а shared object имеет обязательный \code{DT_SONAME}. ABI v2 остаётся читаемым как historical explicit-preload input format. + +\code{mcpu-run} обнаруживает NEEDED graph до исполнения guest-кода, проверяет SONAME identity, загружает dependencies breadth-first/left-to-right и завершает symbol resolution/RELA до первой инструкции \code{_start}. Явный \code{--ldpreload} и \code{MCPU_LD_PRELOAD} остаются override/interposition mechanisms. PLT/GOT, lazy binding, \code{dlopen()}, \code{dlsym()} и runtime lookup после старта отсутствуют. + +ET_DYN содержит только загружаемое PROGRAM/DATA содержимое \code{.text/.data/.bss} плюс non-ALLOC metadata; lifecycle, CONTROL/INPUT/OUTPUT/TRACE, STACK и HEAP принадлежат главному executable. + +\subsection{GLOBAL/WEAK interposition} +Сильный GLOBAL имеет приоритет над WEAK. Для equal-strength definitions highest scope имеет explicit preload с установленным rightmost priority, затем main executable, затем normal NEEDED graph в breadth-first/left-to-right order. Lifecycle symbols \code{_start/_life/_fini} остаются частными для executable и не участвуют в interposition. + +\subsection{LOCAL ET_DYN runtime rebasing} +\begin{normative} +LOCAL symbol остаётся private и non-preemptible, но ссылка на него внутри ET_DYN \textbf{не может быть окончательно превращена в process address при static link}: final PROGRAM/DATA base shared object ещё неизвестна. Поэтому такая ссылка сохраняется как LOCAL runtime RELA. Startup linker разрешает её строго против originating module и добавляет runtime segment base. LOCAL symbols не попадают в GLOBAL/WEAK winner namespace. +\end{normative} + +Правило возникло как исправление runtime-address contract ещё в ABI v2 и является нормативной частью frozen ABI v3. Оно не открывает LOCAL symbol для interposition. + +\section{mcpu-run как host-side test bench} +Помимо one-shot inspection options, runtime поддерживает четыре lifecycle stages: +\par\medskip +\noindent\begin{tabularx}{\textwidth}{@{}L{36mm}Y@{}} +\toprule +\textbf{Опция} & \textbf{Граница выполнения}\\ +\midrule +\code{--before-run=<action>} & after load/preload/relocations/startup, before first guest instruction\\ +\code{--after-init=<action>} & after INIT END; при отсутствии .init --- один раз на logical empty INIT boundary\\ +\code{--on-step=<action>} & after every LIFE END\\ +\code{--after-run=<action>} & after final normal stop; graceful FINI уже завершён\\ +\bottomrule +\end{tabularx} + +Stage-опции можно повторять; они выполняются слева направо. Фильтры по номеру шага намеренно отсутствуют. + +\subsection{Typed actions} +\begin{lstlisting}[language={}] +print-int-regs:r64@0x100,r64@0x108 +print-real-regs:r128@0x200,r256@0x300 +set-int-regs:r64@0x100=123,r64@0x108=-17 +set-real-regs:r128@0x200=1.25,r128@0x220=-2.5 + +print-int-<memory>:64@16,64@24 +print-real-<memory>:128@32,128@48 +set-int-<memory>:64@16=123,64@24=456 +set-real-<memory>:128@32=1.25,128@48=2.5 +\end{lstlisting} +\code{<memory>} --- data, control, heap, input, output, trace. Один scalar print-action печатает comma-list одной строкой через spaces. Set values разбираются через LibMPUIO \code{mpu_sscanf()}; whole action валидируется до первой записи, а guest PSW сохраняется вокруг host-side numeric parsing. + +\subsection{Raw actions} +\code{print-raw-<memory>:<bytes>@<addr>} read-only и описывает ровно один dump. Comma-list запрещён; для нескольких dumps повторяется stage option. \code{set-raw-*} не существует. Size принимает raw bytes и K/KiB, M/MiB, G/GiB с binary multipliers. DATA raw view ограничен linked \code{.data} и не перелезает в \code{.bss}; HEAP host view ограничен prepared backing, тогда как guest access ограничен current break. + +\subsection{Двойной дефис как разделитель} +Preferred CLI: +\begin{lstlisting}[language={}] +mcpu-run [runtime-options] -- executable [program-args...] +\end{lstlisting} +После separator \lstinline|--| tokens не интерпретируются как runner options. Первый token становится executable spelling и guest \code{argv[0]}. Legacy form без separator сохранена. + + +\section{Бинарные утилиты toolchain} +Системные инструменты MELF используют единый public format contract и не вводят альтернативного представления машинного кода. +\par\medskip +\noindent\begin{tabularx}{\textwidth}{@{}L{36mm}Y@{}} +\toprule +\textbf{Команда} & \textbf{Назначение}\\ +\midrule +\code{mcpu-readelf} & Структурный read-only просмотр MELF headers, sections, symbols, RELA, dynamic и MCPU metadata.\\ +\code{mcpu-ar} & Deterministic UNIX static archives из MELF ET\_REL с System-V/GNU-style symbol index.\\ +\code{mcpu-nm} & Symbol-table inspection для объектов, executables, shared objects и archives.\\ +\code{mcpu-objdump} & Section/relocation inspection и дизассемблирование через тот же decoder, который используется CPU runtime.\\ +\code{mcpu-strip} & Консервативное удаление только non-runtime symbol metadata; link/runtime-critical sections сохраняются.\\ +\code{mcpu-objcopy} & MELF-to-MELF structural copy и safe editing non-ALLOC metadata; runtime-visible image защищён.\\ +\bottomrule +\end{tabularx} + +\begin{principle} +MELF уже является native object/executable container виртуальной MCPU. Поэтому \code{mcpu-objcopy} не имеет режимов flat binary, Intel HEX, S-record, VMA/LMA или подготовки firmware image для SPI NOR. Metadata-only edit обязан сохранять guest-visible allocated image и frozen ABI v3 execution semantics. +\end{principle} + +Английские и русские manual pages устанавливаются как section 1 для каждой команды; обзор архитектуры и toolchain доступен как \code{libmcpu(7)}. + +\section{Инварианты реализации} +\begin{enumerate} +\item PROGRAM machine fields всегда MSB-first; data representation не смешивается с code representation. +\item Register address и PTR64 offset не являются host pointers. +\item Bounds/permission validation precedes guest-visible writes, где instruction contract требует atomicity. +\item DATA имеет один process-owned 16-byte NULL guard; ET_DYN не получает собственного guard. +\item HEAP имеет immutable configured limit и minimum break 16; released bytes zeroed on shrink. +\item ABI-v1 static executable полностью linked; ordinary loader его не relink-ит. +\item ABI-v2/v3 startup linking завершается до \code{_start}; после старта symbol lookup отсутствует. +\item LOCAL ET_DYN references runtime-rebased, но никогда не interpose. +\item Lifecycle boundaries определяются guest \code{END/EXIT}; stage actions лишь наблюдают/модифицируют state на host side. +\end{enumerate} + + +\appendix +\section{Полный справочник директив mcpu-as} +Этот appendix перечисляет assembler directives и специальные формы, которые являются частью текущего source contract. Детальная grammar выражений и ограничения sections приведены в основной части документа. +\input{libmcpu-assembler-directives-table.tex} + +\section{Полная таблица OPCODE16} +Таблица перечисляет все значения public \code{cpu_opcode}. Каждый opcode однозначно задаёт число и тип последующих operands; PROGRAM machine fields сериализуются MSB-first. Operand spellings показаны в терминах assembler ABI. +\input{libmcpu-opcode-table.tex} + +\section{PSW selectors и RCONST} +\subsection{PSW bit selectors} +\input{libmcpu-psw-table.tex} +\subsection{RCONST selectors} +\input{libmcpu-rconst-table.tex} + +\section{Краткая памятка ABI} +\par\medskip +\noindent\begin{tabularx}{\textwidth}{@{}L{42mm}Y@{}} +\toprule +Register file & 512 KiB, overlapping REG24 views\\ +Return Value Area & top 8192 bytes, scalar result at \code{0x80000-size}\\ +PTR64 & SEG4:OFF60; DATA=0, STACK=1, PROGRAM=2, CONTROL=3, INPUT=4, OUTPUT=5, TRACE=6, HEAP=7\\ +CALL alignment & 16 bytes; CALL pushes 8-byte return PC; caller owns argument block\\ +PSW & bits 0..15 volatile across call; TF/IF/MODE preserved if changed\\ +DATA guard & process offsets 0..15 zero\\ +HEAP & begin/break minimum 16; \code{_end=HEAP:16}\\ +Startup & 32-byte McpuStartup + argv PTR64 array + strings; persistent\\ +Low-level lifecycle & mandatory \code{_start}, \code{_life}; optional \code{_fini}; \code{e_entry=_start}\\ +HLL PROGRAM & defining ET_REL: \code{main+fini}; automatic \code{crt0.o+crti.o+crtn.o}\\ +HLL MODEL & defining ET_REL: \code{init+life+fini}; automatic \code{crt1.o+crti.o+crtn.o}\\ +Dynamic & frozen normal ABI v3 with SONAME/NEEDED; ABI v2 remains historical explicit-preload input format\\ +\bottomrule +\end{tabularx} + +\end{document} diff --git a/doc/src/libmcpu-doc-common.tex b/doc/src/libmcpu-doc-common.tex new file mode 100644 index 0000000..c588991 --- /dev/null +++ b/doc/src/libmcpu-doc-common.tex @@ -0,0 +1,169 @@ +% Common memoir-based style for LibMCPU reference manuals. +% Shared XeLaTeX style for LibMCPU reference manuals. + + +\usepackage{fontspec} +\defaultfontfeatures{Ligatures=TeX,Scale=MatchLowercase} +\setmainfont{Roboto} +\setsansfont{Roboto} +\setmonofont{DejaVu Sans Mono}[Scale=0.86] + +\usepackage{polyglossia} +\setdefaultlanguage{russian} +\setotherlanguage{english} +\usepackage{microtype} +\usepackage[strings]{underscore} +\usepackage{xcolor} + +\definecolor{McpuBlue}{HTML}{1F3556} +\definecolor{McpuBlue2}{HTML}{526A89} +\definecolor{McpuGreen}{HTML}{2F8A57} +\definecolor{McpuGreenBg}{HTML}{EDF6F0} +\definecolor{McpuGrayBg}{HTML}{F4F6F8} +\definecolor{McpuBlueBg}{HTML}{EEF3F8} +\definecolor{McpuGray}{HTML}{5C6673} +\definecolor{McpuRule}{HTML}{B9C6D8} +\definecolor{McpuCode}{HTML}{F6F7F8} +\definecolor{McpuUrl}{HTML}{B40B22} + +% A4 layout shared with the restyled LibMCPU book: generous text block, +% but enough outer whitespace for technical figures and annotations. +\setstocksize{297mm}{210mm} +\settrimmedsize{297mm}{210mm}{*} +\setlrmarginsandblock{18mm}{15mm}{*} +\setulmarginsandblock{17mm}{19mm}{*} +\setheadfoot{9mm}{8mm} +\setheaderspaces{4mm}{*}{*} +\checkandfixthelayout + +\usepackage{graphicx} +\usepackage{tikz} +\usetikzlibrary{arrows.meta,positioning,fit,calc,shapes.geometric,decorations.pathreplacing} +\usepackage{array} +\usepackage{booktabs} +\usepackage{tabularx} +\usepackage{longtable} +\usepackage{multirow} +\usepackage{enumitem} +\setlist{nosep,leftmargin=2em} +\setlist[itemize]{label=\textcolor{McpuBlue}{\small\textbullet}} +\usepackage[most]{tcolorbox} +\usepackage{listings} +\usepackage{fvextra} +\usepackage{hyperref} +\usepackage{bookmark} +\usepackage{needspace} +\usepackage{ragged2e} + +\hypersetup{ + unicode=true, + colorlinks=true, + linkcolor=McpuBlue, + urlcolor=McpuUrl, + citecolor=McpuBlue, + pdfauthor={Andrew V. Kosteltsev}, + pdflang={ru-RU} +} +\bookmarksetup{open,numbered} + +% memoir section and page styles. +\setsecheadstyle{\Large\sffamily\bfseries\color{McpuBlue}} +\setsubsecheadstyle{\large\sffamily\bfseries\color{McpuBlue}} +\setsubsubsecheadstyle{\normalsize\sffamily\bfseries\color{McpuBlue2}} +\setbeforesecskip{1.45\onelineskip} +\setaftersecskip{0.55\onelineskip} +\setbeforesubsecskip{1.05\onelineskip} +\setaftersubsecskip{0.35\onelineskip} +\setbeforesubsubsecskip{0.8\onelineskip} +\setaftersubsubsecskip{0.25\onelineskip} + +\makepagestyle{libmcpu} +\makeoddhead{libmcpu}{\small\sffamily\color{McpuGray}\DocShortTitle}{}{\small\sffamily\color{McpuGray}LibMCPU} +\makeoddfoot{libmcpu}{}{\small\sffamily\thepage}{} +\makeheadrule{libmcpu}{\textwidth}{0.3pt} +\pagestyle{libmcpu} + +\setlength{\parindent}{1.25em} +\setlength{\parskip}{0.20em} +\setlength{\cftsectionnumwidth}{3.2em} +\setlength{\cftsubsectionnumwidth}{4.2em} +\setlength{\cftsubsubsectionnumwidth}{5.0em} + +\newtcolorbox{principle}{enhanced,breakable,colback=McpuGreenBg,colframe=McpuGreen,boxrule=0pt,leftrule=3pt,arc=0pt,left=10pt,right=10pt,top=8pt,bottom=8pt,before skip=8pt,after skip=8pt} +\newtcolorbox{normative}{enhanced,breakable,colback=McpuBlueBg,colframe=McpuBlue,boxrule=0pt,leftrule=3pt,arc=0pt,left=10pt,right=10pt,top=8pt,bottom=8pt,before skip=8pt,after skip=8pt} +\newtcolorbox{warningbox}{enhanced,breakable,colback=yellow!8,colframe=orange!75!black,boxrule=0pt,leftrule=3pt,arc=0pt,left=10pt,right=10pt,top=8pt,bottom=8pt,before skip=8pt,after skip=8pt} +\newtcolorbox{codebox}{enhanced,breakable,colback=McpuCode,colframe=McpuRule,boxrule=0.4pt,arc=1pt,left=7pt,right=7pt,top=5pt,bottom=5pt,before skip=7pt,after skip=7pt} + +\lstdefinelanguage{MCPUAsm}{ + morekeywords={LDI,LDR,LDC,MOV,IADD,ISUB,IAND,IOR,IXOR,INOT,ICMP,ITEST,ISHL,ISHR,ISAL,ISAR,IROL,IROR,IRCL,IRCR,ISHLN,ISHRN,ISALN,ISARN,IROLN,IRORN,IRCLN,IRCRN,IINC,IDEC,IXCHG,ICPY,ICVT,IMUL,ISMUL,IDIV,ISDIV,IBITSLEN,RADD,RSUB,RMUL,RDIV,RSQRT,RSIN,RCOS,RTAN,RASIN,RACOS,RATAN,RLOG,RLOG10,RLOG2,REXP,RSINH,RCOSH,RTANH,RPOW,RHYPOT,RATAN2,RNEG,RABS,RCMP,RCPY,RCVT,RFLOOR,RCEIL,RROUND,RFREXP,RLDEXP,RLOGB,RMODF,RREMAIN,RLOG1P,REXPM1,RASINH,RACOSH,RATANH,ITOR,UITOR,RTOI,RTOUI,RISNEG,RSIGN,RISIND,RISNAN,RISNANMAX,RISNANMIN,RISINF,RISSIGNULL,RCONST,CADD,CSUB,CMUL,CDIV,CEXP,CSIN,CCOS,CSINH,CCOSH,CLOG,CSQRT,CPOW,CREAL,CIMAG,CRTOC,CGEN,CPOLAR,CCONJ,CABS,CNORM,CARG,CISEQ,CISNE,CCPY,CCVT,JMP,JSET,JCLR,JMPP,CALL,CALLP,RET,PUSH,POP,LDSP,STSP,ADJSP,PUSHFP,SETFP,RESTSP,POPFP,LDFP,STFP,LEAFP,SETSP,LOAD,STORE,LEA,LEASP,LOADP,STOREP,PTRADD,PTRSUB,PTRDIFF,BMOV,BMOVI,BSWAP,END,EXIT,HALT,SYSCALL}, + sensitive=false, + morecomment=[l]{;}, + morecomment=[l]{\#}, + morestring=[b]" +} +\lstset{ + language=MCPUAsm, + basicstyle=\ttfamily\small, + columns=fullflexible, + keepspaces=true, + showstringspaces=false, + breaklines=true, + breakatwhitespace=false, + postbreak=\mbox{\textcolor{McpuGray}{$\hookrightarrow$}\space}, + frame=single, + rulecolor=\color{McpuRule}, + backgroundcolor=\color{McpuCode}, + aboveskip=7pt, + belowskip=7pt, + framerule=0.4pt +} + +% Long shell commands and verbatim data must never run outside the page. +\DefineVerbatimEnvironment{McpuCommand}{Verbatim}{fontsize=\small,frame=single,framesep=3mm,rulecolor=\color{McpuBlue!35},breaklines=true,breakanywhere=true,breaksymbolleft={},breaksymbolright={},breakindent=1.5em} +\DefineVerbatimEnvironment{McpuCode}{Verbatim}{fontsize=\small,frame=single,framesep=3mm,rulecolor=\color{McpuGray!35},breaklines=true,breakanywhere=true,breaksymbolleft={},breaksymbolright={}} + +\newcolumntype{Y}{>{\raggedright\arraybackslash}X} +\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}} +\urlstyle{tt}\newcommand{\code}[1]{\nolinkurl{#1}} +\newcommand{\field}[1]{\texttt{#1}} +\newcommand{\MCPU}{LibMCPU} +\newcommand{\MELF}{MELF} +\newcommand{\PTR}{PTR64} +\newcommand{\REG}{REG24} +\newcommand{\term}[2]{\textbf{#1} (\textit{#2})} +\newcommand{\figlabel}[1]{\sffamily\small\color{McpuGray}#1} +\newcommand{\tabhead}[1]{\sffamily\bfseries #1} + +\newcommand{\DocTitlePage}[3]{% + \begin{titlingpage} + \thispagestyle{empty} + \vspace*{30mm} + {\sffamily\fontsize{29}{34}\selectfont\bfseries\color{McpuBlue} #1\par} + \vspace{8mm} + {\sffamily\fontsize{16}{21}\selectfont\color{McpuBlue2} #2\par} + \vspace{4mm} + {\sffamily\large\color{McpuGray} #3\par} + \vfill + \begin{tcolorbox}[width=0.86\textwidth,colback=McpuGreenBg,colframe=McpuGreen,boxrule=0pt,leftrule=4pt,arc=0pt] + \textbf{Нормативное техническое руководство LibMCPU.} Документ описывает текущий архитектурный контракт и намеренно не привязан к номеру выпуска пакета. + \end{tcolorbox} + \vfill + {\small\sffamily\color{McpuGray}Техническая редакция, октябрь 2026\par} + \end{titlingpage} +} +\setcounter{tocdepth}{2} +\setcounter{secnumdepth}{3} +% Reference manuals have no chapter level; memoir otherwise prefixes sections +% with the implicit chapter number 0. +\renewcommand{\thesection}{\arabic{section}} +\renewcommand{\thesubsection}{\thesection.\arabic{subsection}} +\renewcommand{\thesubsubsection}{\thesubsection.\arabic{subsubsection}} +\renewcommand{\thefigure}{\arabic{figure}} +\renewcommand{\thetable}{\arabic{table}} +\renewcommand{\contentsname}{Содержание} +\newcommand{\ManualIntro}[1]{\begin{principle}\textbf{Статус документа.} #1\end{principle}} +\newcommand{\smallcapslabel}[1]{\textcolor{McpuBlue}{\textbf{#1}}} +\newenvironment{compactdesc}{\begin{description}[style=multiline,leftmargin=48mm,labelwidth=44mm,labelsep=4mm,labelindent=0pt,font=\normalfont\bfseries\color{McpuBlue}]}{\end{description}} + +\emergencystretch=4em\tolerance=1800 +\raggedbottom diff --git a/doc/src/libmcpu-hll-crt-contract-ru.tex b/doc/src/libmcpu-hll-crt-contract-ru.tex new file mode 100644 index 0000000..c2a3c3d --- /dev/null +++ b/doc/src/libmcpu-hll-crt-contract-ru.tex @@ -0,0 +1,181 @@ +\section{HLL Runtime ABI: PROGRAM, MODEL, CRT и MCPU Libc} +\label{sec:hll-crt-contract} + +Этот раздел фиксирует подписанный HLL Runtime ABI. Он описывает границу между объектами, которые в будущем генерирует \code{mcpu-cc}, существующим \code{mcpu-ld}, CRT, MCPU Libc и уже действующим MELF lifecycle. Контракт не зависит от номера выпуска LibMCPU. + +\begin{principle} +\textbf{Разделение уровней.} HLL-функции \code{main()}, \code{init()}, \code{life()} и \code{fini()} являются обычными функциями CALL ABI и завершаются \code{RET}. Машинные точки \code{_start}, \code{_life}, \code{_fini}, а также lifecycle-инструкции \code{END}/\code{EXIT} принадлежат CRT и MELF runtime. Пользовательская HLL-функция не должна исполнять raw \code{END} или \code{EXIT} из открытого CALL frame. +\end{principle} + +\subsection{Целевая integer-модель HLL ABI} + +HLL ABI использует фиксированные целевые типы \code{int8/int16/int32/int64}, соответствующие unsigned-типы и \code{PTR64}. Исторические C-имена \code{char/short/int/long} не определяют бинарный ABI. \code{PTR64} --- обозначение бинарного pointer object, а не синоним \code{int64*}. + +Канонические compiler-visible пределы публикуются препроцессором целевой среды. Для жизненного цикла важны определения: +\begin{lstlisting}[language={}] +#define LIFE_END 0 +#define LIFE_CONTINUE (-__INT32_MAX__ - 1) +\end{lstlisting} +Таким образом минимальное значение signed int32 выражается непосредственно через target predefined macro \code{__INT32_MAX__}. + +\subsection{Две формы законченной HLL-программы} + +Исходный compilation unit определяет ровно одну из двух форм: +\begin{center} +\begin{tabularx}{0.94\textwidth}{@{}L{27mm}L{66mm}Y@{}} +\toprule +\textbf{Форма} & \textbf{Функции HLL ABI} & \textbf{Назначение}\\ +\midrule +PROGRAM & \code{int32 main(int64 argc, PTR64 argv)}; optional source-level \code{void fini(void)} & однократная обычная программа\\ +MODEL & \code{int32 init(int64 argc, PTR64 argv)}; \code{int32 life(void)}; optional source-level \code{void fini(void)} & модель с INIT и повторяющимися LIFE-фазами\\ +\bottomrule +\end{tabularx} +\end{center} + +Frontend нормализует optional source-level \code{fini}: если программист её не определил, compiler создаёт пустую strong GLOBAL/FUNC \code{fini}. Поэтому defining ET_REL всегда содержит: +\begin{itemize} +\item PROGRAM: strong GLOBAL/FUNC \code{main} и \code{fini}; +\item MODEL: strong GLOBAL/FUNC \code{init}, \code{life} и \code{fini}. +\end{itemize} +Все complete-program definitions одной формы принадлежат \textbf{одному} defining ET_REL. Другие translation units могут их объявлять, но не определять. \code{main} несовместим с парой \code{init/life}; неполная или разделённая между несколькими ET_REL форма является ошибкой final link. + +\subsection{Автоматическая классификация в mcpu-ld} + +Для final ET_EXEC \code{mcpu-ld} классифицирует обычные входные ET_REL до разрешения библиотек. Никаких ключей \code{--program} или \code{--model} нет: +\begin{center} +\begin{tabularx}{0.88\textwidth}{@{}L{54mm}Y@{}} +\toprule +\textbf{Определения defining ET_REL} & \textbf{Режим}\\ +\midrule +\code{main + fini} & HLL PROGRAM\\ +\code{init + life + fini} & HLL MODEL\\ +\code{_start/_life[/_fini]} без HLL roots & low-level MELF executable; automatic CRT не добавляется\\ +\bottomrule +\end{tabularx} +\end{center} + +Смешение raw lifecycle definitions с HLL complete-program roots запрещено. Символы из \code{-l...} не используются для классификации и потому библиотека не может случайно превратить link в PROGRAM или MODEL. + +После классификации linker автоматически вставляет CRT из активного MCPU system root: +\begin{McpuCode} +PROGRAM: <root>/lib/mcpu/crt0.o crti.o <user objects/libraries> crtn.o +MODEL: <root>/lib/mcpu/crt1.o crti.o <user objects/libraries> crtn.o +\end{McpuCode} +Отсутствие любого обязательного CRT object является fatal link error. Переход к другому root или деградация в low-level link не выполняются. + +\subsection{Распределение ответственности CRT} + +Канонические исходники принадлежат LibMCPU и устанавливаются как target runtime objects: +\begin{center} +\begin{tabularx}{0.92\textwidth}{@{}L{26mm}Y@{}} +\toprule +\code{crt0.o} & PROGRAM adapter; формирует \code{_start == _life} в \code{.text} и вызывает \code{main}.\\ +\code{crt1.o} & MODEL adapter; формирует \code{_start} в \code{.init} и \code{_life} в \code{.text}, вызывает \code{init}/\code{life}.\\ +\code{crti.o} & общая startup state/validation и вызовы начала MCPU Libc.\\ +\code{crtn.o} & обязательная HLL \code{_fini}, PRE_RUNTIME/RUNNING branch и graceful finalization.\\ +\bottomrule +\end{tabularx} +\end{center} + +HLL ET_EXEC всегда получает \code{_fini}, даже если source-level \code{fini()} была опущена и нормализована frontend-ом в пустую функцию. + +\subsection{McpuStartup, argc и argv} + +Loader строит \code{McpuStartup} один раз до первой guest instruction. Заголовок, массив \code{argv[argc+1]} и строки аргументов остаются действительными до конца процесса. CRT проверяет version/size/representation, затем проверяет, что \code{argc} не превышает \code{__INT64_MAX__}, и преобразует unsigned startup field в target signed \code{int64}. Существующий \code{PTR64 argv} переиспользуется; MCPU Libc не копирует и не владеет \code{argc/argv}. + +Для \code{main()} и \code{init()} CRT создаёт обычный 16-байтовый CALL argument block: +\begin{center} +\begin{tabularx}{0.72\textwidth}{@{}L{24mm}L{30mm}Y@{}} +\toprule +\textbf{До CALL} & \textbf{Объект} & \textbf{После push return PC callee видит}\\ +\midrule +SP+0 & int64 \code{argc} & SP+8\\ +SP+8 & PTR64 \code{argv} & SP+16\\ +\bottomrule +\end{tabularx} +\end{center} +Возврат \code{int32} из \code{main/init/life} находится в канонической Return Value Area \code{r32@0x7fffc}. + +\subsection{Внутренние hooks MCPU Libc} + +CRT использует ровно четыре reserved internal hooks: +\begin{lstlisting}[language={}] +void __mcpu_libc_init(void); +void __mcpu_init_array(void); +void __mcpu_fini_array(void); +void __mcpu_libc_fini(void); +\end{lstlisting} +Это обычные no-argument CALL ABI functions с \code{RET}. Startup order после успешной validation: +\begin{McpuCode} +__mcpu_libc_init() +__mcpu_init_array() +main(...) или init(...) +\end{McpuCode} +Graceful HLL finalization в состоянии RUNNING: +\begin{McpuCode} +fini() +__mcpu_fini_array() +__mcpu_libc_fini() +END +\end{McpuCode} +Physical ABI init/fini arrays и constructor priorities могут развиваться отдельно; наличие hooks уже фиксирует границу CRT и Libc. + +Обычная ABI-v3 DT_NEEDED библиотека MCPU Libc имеет право предоставить эти четыре symbols. Explicit preload не имеет права их подменять. Complete-program roots \code{main/init/life/fini}, lifecycle symbols и CRT-private names также не являются пользовательским interposition API. + +\subsection{PRE_RUNTIME и RUNNING} + +CRT хранит private logical state \code{PRE_RUNTIME} / \code{RUNNING}; его физическое представление не является public ABI. До успешного завершения \code{__mcpu_libc_init()} и \code{__mcpu_init_array()} состояние остаётся PRE_RUNTIME. + +Если validation startup area или диапазона \code{argc} завершается ошибкой, CRT выполняет graceful \code{EXIT(startup_failure_status)}. Supervisor входит в \code{_fini}, но PRE_RUNTIME branch выполняет только \code{END}: пользовательская \code{fini}, fini-array и libc-fini не вызываются. Namespace startup-failure status не выводится из host errno. + +После startup hooks CRT устанавливает RUNNING. С этого момента normal graceful EXIT всегда приводит к полному HLL finalization. Поэтому ненулевой возврат \code{init()} уже находится в RUNNING и вызывает пользовательскую \code{fini()}; MODEL fini должна допускать частично инициализированную модель. + +\subsection{PROGRAM lifecycle} + +PROGRAM не имеет отдельной \code{.init}. \code{_start == _life} находится в \code{.text}. После validation и startup hooks CRT вызывает +\begin{lstlisting}[language={}] +int32 main(int64 argc, PTR64 argv); +\end{lstlisting} +и после \code{RET} выполняет \code{EXIT(main_status)}. Дополнительного LIFE \code{END} после \code{main()} нет. + +\subsection{MODEL lifecycle} + +MODEL использует \code{_start} в \code{.init} и \code{_life} в \code{.text}. В INIT CRT вызывает +\begin{lstlisting}[language={}] +int32 init(int64 argc, PTR64 argv); +\end{lstlisting} +Возврат 0 создаёт ровно одну INIT boundary через \code{END}. Ненулевой status выполняет \code{EXIT(status)} и переходит к полной HLL finalization, поскольку runtime уже RUNNING. + +Каждая LIFE-фаза является отдельным обычным вызовом: +\begin{lstlisting}[language={}] +int32 life(void); +\end{lstlisting} +Return namespace фиксирован: +\begin{center} +\begin{tabularx}{0.94\textwidth}{@{}L{44mm}L{34mm}Y@{}} +\toprule +\textbf{int32 return} & \textbf{Имя} & \textbf{Действие CRT}\\ +\midrule +\code{-__INT32_MAX__ - 1} & \code{LIFE_CONTINUE} & выполнить ровно один LIFE \code{END}; после resume снова вызвать \code{life()}\\ +0 & \code{LIFE_END} & \code{EXIT(0)} без дополнительного END\\ +1..\code{__INT32_MAX__} & error status & \code{EXIT(status)} без дополнительного END\\ +\code{-__INT32_MAX__}..-1 & reserved & не использовать без будущего расширения ABI\\ +\bottomrule +\end{tabularx} +\end{center} +Это гарантирует, что естественное завершение модели не создаёт фиктивной последней LIFE boundary и, например, лишней строки TRACE. + +\subsection{HLL finalization и сохранение status} + +В RUNNING каноническая \code{_fini} концептуально выполняет: +\begin{McpuCode} +CALL fini +CALL __mcpu_fini_array +CALL __mcpu_libc_fini +END +\end{McpuCode} +Original EXIT status сохраняется runtime через всю finalization sequence. Второй \code{EXIT} из \code{_fini} не выполняется. Диагностическая остановка \code{mcpu-run --steps=...} не является graceful exit и не синтезирует HLL finalization. + +\begin{normative} +\textbf{Главный итог.} HLL-программа определяет только обычные functions. \code{mcpu-ld} распознаёт нормализованную форму ET_REL и выбирает CRT автоматически. CRT владеет MELF lifecycle, MCPU Libc владеет библиотечным runtime, а loader владеет persistent startup area. Ни один слой не дублирует ответственность соседнего. +\end{normative} diff --git a/doc/src/libmcpu-isa-coverage-ru.tex b/doc/src/libmcpu-isa-coverage-ru.tex new file mode 100644 index 0000000..0851aea --- /dev/null +++ b/doc/src/libmcpu-isa-coverage-ru.tex @@ -0,0 +1,66 @@ +\section{Актуальное покрытие LibMPU и семейства ISA} +Вычислительное ядро ISA не является минимальным proof-of-concept. Оно содержит полноценные integer, Real и Complex families, а также отдельные группы управления потоком, стеком, указателями и runtime boundary. Этот раздел фиксирует именно архитектурную группировку; точные значения всех OPCODE16 приведены в приложении B и генерируются из public \code{cpu_opcode} в \code{include/libmcpu.h}. + +\subsection{System и data-movement family} +Системная группа содержит \code{NOP}, \code{HALT}, lifecycle instruction \code{END}, graceful \code{EXIT}, zero-operand \code{SYSCALL} и отдельную PSW/status subgroup: \code{SETF}, \code{CLRF}, \code{CLRCPUF}, \code{CLRMPUF}. Data-movement/address family содержит \code{MOV}, \code{CLR}, \code{SWAP}, raw-byte \code{BSWAP}, immediate forms \code{LDI/LDR/LDC}, direct DATA access \code{LOAD/STORE}, pointer construction/dereference \code{LEA/LEASP/LOADP/STOREP}, pointer arithmetic \code{PADD/PADDI/PSUB/PSUBI/PDIFF} и block move \code{BMOV/BMOVI}. + +\begin{normative} +\textbf{Тип operands задаёт opcode.} REG24 не содержит integer/Real/Complex tag. Поэтому один и тот же physical register может последовательно участвовать в разных domains, но assembler проверяет semantic view там, где signature требует \code{c<bits>} либо конкретный \code{r64} carrier. Executor независимо повторяет width/signature validation и не доверяет исходному тексту assembler. +\end{normative} + +\subsection{Integer family} +Integer operations работают с physical widths от 8 до 65536 bits. Базовые arithmetic/logical operations включают \code{IADD/IADC/ISUB/ISBB}, \code{IAND/IOR/IXOR/INOT}, \code{INEG}, compare/test, increment/decrement и exchange. Shift/rotate представлены как single-bit forms и variants с count в \code{r64}: logical/arithmetic shifts, ordinary rotates и rotates through carry. + +Width-changing operations намеренно разделены на unsigned copy \code{ICPY} и signed conversion \code{ICVT}. Full multiply возвращает product расширенной ширины через \code{IMUL/ISMUL}; division имеет отдельные unsigned/signed четырехоперандные формы \code{IDIV/ISDIV} с quotient и remainder. \code{IBITSLEN} выдаёт длину integer в bits в \code{r64}. + +Модульная арифметика LibMPU (например modular multiply/power и GCD-related higher-level routines) намеренно не превращена в CPU opcodes. Она остаётся library-level functionality: ISA предоставляет primitives, а не дублирует всю API-поверхность LibMPU. + +\subsection{Real family} +Real arithmetic работает непосредственно с LibMPU objects требуемой physical precision. Простые operations (copy, conversion, add/sub/mul/div, sign/abs, decomposition, predicates) поддерживают архитектурно допустимые Real widths. Transcendental family ограничена тем же верхним пределом, что и настроенная LibMPU math backend; в проверенной конфигурации проекта это real16384. + +В ISA присутствуют: +\begin{itemize} +\item arithmetic и square root; +\item trigonometric/inverse trigonometric functions; +\item logarithms, exponentials, hyperbolic и inverse hyperbolic functions; +\item \code{pow}, \code{hypot}, \code{atan2}; +\item \code{floor/ceil/round}, \code{frexp/ldexp/logb/modf/remainder}; +\item signed/unsigned integer-to-Real и Real-to-integer conversions; +\item classification/predicate family для sign, IND, NaN classes, infinity и signed zero; +\item \code{RCONST}, создающий predefined values непосредственно в precision destination. +\end{itemize} + +\begin{principle} +Широкий Real register не проходит через host \code{double}. Там, где instruction содержит immediate, exactness проверяется assembler-ом до emission; для произвольной высокой точности значение хранится как target Real object в data-like section и загружается byte-preserving instruction \code{LOAD/LOADP}. +\end{principle} + +\subsection{Complex family} +Complex register view имеет полный physical width от c64 до c65536, а каждая компонента занимает половину. Arithmetic \code{CADD/CSUB/CMUL/CDIV} использует LibMPU complex primitives. Math family содержит \code{CEXP/CSIN/CCOS/CSINH/CCOSH/CLOG/CSQRT/CPOW}; для функций, требующих math backend, предел component precision соответствует Real math limit (то есть c32768 при real16384 components). + +Отдельно представлены extraction/construction/conversion operations: \code{CREAL/CIMAG}, \code{CRTOC}, \code{CGEN}, \code{CPOLAR}, conjugation, absolute value/norm/argument, equality predicates и copy/precision conversion. Для mixed-domain signatures Real component register обязан иметь ровно половинную physical width соответствующего Complex object. + +\subsection{Control-flow и stack family} +Прямые targets представлены CODE64; indirect targets - PROGRAM PTR64 в \code{r64}. Branch family состоит из \code{JMP}, \code{JSET/JCLR}, \code{JMPP}; call family - \code{CALL}, \code{CALLP}, \code{RET}. Условия \code{JZ/JNZ/JC/JNC/...} являются assembler aliases над PSW bits, а не отдельными opcodes. + +Stack family содержит object push/pop, SP-relative и FP-relative load/store, signed \code{ADJSP}, canonical frame operations \code{PUSHFP/SETFP/RESTSP/POPFP}, \code{LEAFP} и validated \code{SETSP}. Эти instructions работают с raw STACK offsets/PTR64 и не вводят скрытого frame metadata в CPU. + + +\subsection{Явное управление arithmetic/status flags} +PSW разделён на два writable byte domains: CPU flags \code{PSW[7:0]} и MPU flags \code{PSW[15:8]}. Инструкции \code{SETF flag} и \code{CLRF flag} изменяют ровно один именованный bit из диапазона AF..INXF и сохраняют все остальные bits PSW. \code{CLRCPUF} очищает только \code{PSW[7:0]}, а \code{CLRMPUF} --- только \code{PSW[15:8]}. + +\begin{normative} +HF, TF, IF и многобитовое поле MODE не принадлежат writable arithmetic/status domain. \code{SETF/CLRF} обязаны отвергать selectors HF/TF/IF; bulk-clear instructions также не изменяют PSW bits 16 и выше. \code{JSET/JCLR} при этом сохраняют более широкий read-only selector contract и могут проверять HF/TF/IF. +\end{normative} + +Явная установка CF предназначена, в частности, для подготовки входного carry/borrow state перед \code{IADC/ISBB} и rotate-through-carry family. Сами integer instructions сохраняют установленную LibMPU semantics; новые flag instructions только дают assembler-программе прямой способ подготовить их входное состояние. + +\subsection{PSW-neutral conversion class} +Conversion-class instructions сохраняют incoming \code{PSW[15:0]}, даже если внутренний LibMPU helper меняет library flags. К этой категории относятся непосредственные numeric loads и width/domain conversions, в частности \code{LDI}, \code{LDR}, \code{LDC}, \code{ICVT}, \code{RCVT}, \code{ITOR}, \code{UITOR}, \code{RTOI}, \code{RTOUI}, \code{CCVT}, \code{CRTOC}. Arithmetic instructions, напротив, публикуют обычные LibMPU status effects. + +Это различие важно для compiler backend: преобразование representation не должно разрушать condition state предыдущего сравнения, тогда как arithmetic operation по определению может менять flags. + +\subsection{Неинструкционные функции} +Text parsing/formatting, format introspection, diagnostics и library context management не являются CPU operations. Они принадлежат assembler, LibMPUIO, будущей guest library либо host runtime. Такая граница сохраняет ISA вычислительной и не привязывает bytecode к host textual API. + +\subsection{Regression contract} +Нормативное поведение instruction family проверяется не только unit tests decoder-а. Regression suite сравнивает CPU execution с соответствующими LibMPU primitives, проверяет malformed widths/operands, exact-immediate diagnostics, PSW preservation для conversions, pointer/stack faults и no-partial-write invariants. Отдельный пакет model examples дополнительно проверяет композицию ISA + CALL ABI + MELF + loader на длинном execution path. diff --git a/doc/src/libmcpu-melf-abi-ru.tex b/doc/src/libmcpu-melf-abi-ru.tex new file mode 100644 index 0000000..e7a73b3 --- /dev/null +++ b/doc/src/libmcpu-melf-abi-ru.tex @@ -0,0 +1,661 @@ +\documentclass[10pt,a4paper,oneside,openany]{memoir} +\newcommand{\DocShortTitle}{LibMCPU MELF ABI} +\input{libmcpu-doc-common.tex} +\hypersetup{ + pdftitle={LibMCPU MELF ABI}, + pdfsubject={Формат объектов и исполняемых файлов MCPU, контракт компоновщика и загрузчика} +} +\begin{document} + +\DocTitlePage + {LibMCPU MELF ABI} + {Формат объектов и исполняемых файлов MCPU, контракт компоновщика (linker) и загрузчика (loader)} + {Самостоятельное справочное руководство; нумерация разделов начинается с 1} + +\ManualIntro{Документ является самостоятельным описанием текущего MELF-контракта LibMCPU и намеренно не связан с номером выпуска пакета. Он фиксирует статический ABI v1, исторический explicit-preload ABI v2, frozen normal dynamic ABI v3 с SONAME/NEEDED, lifecycle, STACK/HEAP, MCPU static archives и partial ET_REL linking. HLL PROGRAM/MODEL classification и automatic CRT insertion описаны как linker layer над MELF container ABI.} + +\begin{principle} +\textbf{MELF --- не системный ELF.} Формат намеренно использует сигнатуру \code{_ELF}, частное значение \code{e_machine=MCPU} и специфические для MCPU секции и заголовков сегментов (Program Headers). Ядро host-системы и системный \code{ld.so} не участвуют в запуске. \code{mcpu-ld} и \code{mcpu-run} являются частями одного целевого ABI. +\end{principle} + +\tableofcontents +\clearpage + +\section{Назначение и границы формата} + +MELF хранит три вида файлов MCPU: +\begin{itemize} +\item перемещаемый объект (\term{relocatable object}{перемещаемый объект}) \code{ET_REL}; +\item исполняемый образ (\term{executable}{исполняемый файл}) \code{ET_EXEC}; +\item разделяемый объект (\term{shared object}{разделяемый объект}) \code{ET_DYN}, явно загружаемый при запуске программы. +\end{itemize} + +От ELF заимствованы общие идеи заголовков Ehdr, Shdr и Phdr, таблиц символов и строк, а также relocation-записей RELA. Архитектурные пространства памяти, точки входа lifecycle и метаданные профиля целевой архитектуры определяются самим MCPU ABI. + +Текущая реализация использует только MELF64. Имена и структуры MELF32 зарезервированы, но ABI v1, ABI v2 и ABI v3 их не принимают. C-структуры из \code{mcpu-elf.h} описывают логические поля, но не являются готовой сериализацией на диске (on-disk serialization): код записи и чтения явно кодирует и декодирует многобайтовые поля с учётом \code{EI_DATA}. + +PROGRAM образует отдельную область с собственным порядком байтов: машинные поля MCPU внутри PROGRAM всегда записываются MSB-first независимо от \code{EI_DATA} контейнера. + +\section{Идентификация, класс и e\_machine} + +\subsection{Поле e\_ident} + +\begin{center} +\begin{tabularx}{0.95\textwidth}{@{}L{28mm}L{28mm}Y@{}} +\toprule +\textbf{Поле} & \textbf{Значение} & \textbf{Смысл}\\ +\midrule +MAG0..3 & \code{'_','E','L','F'} & сигнатура MELF; это не обычный \code{0x7fELF}\\ +EI\_CLASS & 2 & \code{MELF_CLASS_64}\\ +EI\_DATA & 1 или 2 & порядок байтов LSB/MSB для метаданных и объектов данных целевой архитектуры\\ +EI\_VERSION & 1 & текущая версия формата\\ +EI\_OSABI & 64 & \code{MELF_OSABI_MCPU}\\ +EI\_ABIVERSION & 1, 2 или 3 & статический ABI v1 / исторический dynamic ABI v2 / frozen dynamic ABI v3\\ +\bottomrule +\end{tabularx} +\end{center} + +\subsection{e\_machine и e\_flags} + +\code{e_machine = 0x4d43} (ASCII ``MC''). Это частное значение MELF, а не официальное значение системного ELF. В текущем ABI \code{e_flags=0}. Неизвестные биты загрузчик (loader) обязан отвергать, а не молча игнорировать. + +\section{Типы файлов и версии ABI} + +В MELF номер ABI относится не к версии инструмента, а к конкретному контракту файла. Текущий toolchain продолжает читать исторические ABI v1/v2 и выпускает ABI v1 для ET_REL/статического ET_EXEC и frozen ABI v3 для новых dynamic ET_EXEC/ET_DYN. + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{43mm}L{24mm}L{18mm}Y@{}} +\toprule +\textbf{Режим формирования} & \textbf{e\_type} & \textbf{ABI} & \textbf{Назначение}\\ +\midrule +\code{mcpu-as} & ET\_REL & 1 & перемещаемый входной объект\\ +\code{mcpu-ld -r} & ET\_REL & 1 & частично скомпонованный перемещаемый объект\\ +\code{mcpu-ld} & ET\_EXEC & 1 & полностью статический исполняемый файл\\ +исторический dynamic output & ET\_EXEC / ET\_DYN & 2 & explicit-preload startup ABI, сохраняемый загрузчиком для совместимости\\ +\code{mcpu-ld --dynamic} & ET\_EXEC & 3 & главный startup-dynamic исполняемый файл с \code{.dynamic}\\ +\code{mcpu-ld --shared} & ET\_DYN & 3 & shared object с обязательным SONAME и возможными NEEDED\\ +ET\_CORE & зарезервировано & --- & пока не поддерживается\\ +\bottomrule +\end{tabularx} +\end{center} + +ABI v3 является frozen normal dynamic ABI. Его несовместимое изменение требует нового номера ABI. ABI v3 не меняет CPU ISA, CALL ABI, PTR64 или базовые типы RELA; он расширяет startup dynamic-link contract метаданными \code{.dynamic}, SONAME/NEEDED, поиском библиотек и детерминированным runtime symbol scope. + +\section{Заголовок MELF64} + +Сериализованный \code{MElf64_Ehdr} имеет размер 88 байт. Поля точек входа lifecycle содержат полные архитектурные \code{PTR64(PROGRAM,offset)}, а не смещения внутри файла. + +\begin{longtable}{@{}L{32mm}L{20mm}L{102mm}@{}} +\toprule +\textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\ +\midrule +\endfirsthead +\toprule +\textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\ +\midrule +\endhead +\code{e_ident} & 16 & сигнатура, класс, порядок данных, версия, OSABI, версия ABI\\ +\code{e_type} & 2 & ET\_REL / ET\_EXEC / ET\_DYN\\ +\code{e_machine} & 2 & MCPU\\ +\code{e_version} & 4 & \code{MELF_EV_CURRENT}\\ +\code{e_entry} & 8 & обязательная точка входа исполняемого файла; всегда \code{_start}\\ +\code{e_init_entry} & 8 & \code{_start}, если существует \code{.init}; иначе 0\\ +\code{e_life_entry} & 8 & обязательный \code{_life}\\ +\code{e_fini_entry} & 8 & необязательный \code{_fini}; иначе 0\\ +\code{e_phoff} & 8 & смещение в файле до таблицы заголовков сегментов (Program Headers)\\ +\code{e_shoff} & 8 & смещение в файле до таблицы заголовков секций (Section Headers)\\ +\code{e_flags} & 4 & в текущем ABI равен 0\\ +\code{e_ehsize} & 2 & 88\\ +\code{e_phentsize} & 2 & 64 для MELF64\\ +\code{e_phnum} & 2 & число записей заголовков сегментов\\ +\code{e_shentsize} & 2 & 64 для MELF64\\ +\code{e_shnum} & 2 & число записей заголовков секций\\ +\code{e_shstrndx} & 2 & индекс секции \code{.shstrtab}\\ +\bottomrule +\end{longtable} + +У \code{ET_REL} окончательных адресов lifecycle ещё нет, поэтому четыре поля точек входа равны нулю. \code{ET_DYN} не является самостоятельной программой и также не имеет исполняемых точек входа lifecycle. + +\section{Архитектурные адреса внутри MELF} + +Для окончательно размещённых загружаемых секций (allocated sections) поле \code{sh_addr} содержит полный \code{PTR64(segment,final_offset)}. Используется следующая таблица селекторов (selectors): + +\begin{center} +\begin{tabularx}{0.84\textwidth}{@{}L{26mm}L{18mm}Y@{}} +\toprule +\textbf{Пространство} & \textbf{SEG} & \textbf{Секции / роль}\\ +\midrule +DATA & 0x0 & \code{.data}, \code{.bss}\\ +STACK & 0x1 & только дескриптор времени выполнения; полезные данные объекта отсутствуют\\ +PROGRAM & 0x2 & \code{.init}, \code{.text}, \code{.fini}\\ +CONTROL & 0x3 & \code{.control}\\ +INPUT & 0x4 & \code{.input}\\ +OUTPUT & 0x5 & \code{.output}\\ +TRACE & 0x6 & \code{.trace}\\ +HEAP & 0x7 & только дескриптор времени выполнения; данных ассемблерного объекта нет\\ +\bottomrule +\end{tabularx} +\end{center} + +В \code{ET_REL} символы и секции используют смещения относительно своей секции и ещё не имеют окончательной базы процесса. В \code{ET_DYN} адреса также остаются относительными к модулю; окончательные базы PROGRAM и DATA назначает компоновщик запуска (startup linker). + +\section{Секции и флаги секций} + +MELF использует типы секций, близкие к ELF: \code{SHT_NULL}, \code{SHT_PROGBITS}, \code{SHT_SYMTAB}, \code{SHT_STRTAB}, \code{SHT_RELA}, \code{SHT_NOBITS}, \code{SHT_DYNSYM} и \code{SHT_DYNAMIC}.\par +Кроме того, определены два специфических для MCPU типа: +\begin{center} +\begin{tabularx}{0.82\textwidth}{@{}L{54mm}Y@{}} +\toprule +\textbf{Тип секции} & \textbf{Числовое значение}\\ +\midrule +\code{SHT_MCPU_TARGET} & 0x70000000\\ +\code{SHT_MCPU_LIFECYCLE} & 0x70000001\\ +\bottomrule +\end{tabularx} +\end{center} + +Загружаемые секции получают обычные признаки R/W/X через \code{SHF_WRITE/ALLOC/EXECINSTR}; тег архитектурного сегмента MCPU кодируется в процессорных битах флагов. + +\begin{center} +\begin{tabularx}{0.94\textwidth}{@{}L{24mm}L{24mm}L{26mm}Y@{}} +\toprule +\textbf{Секция} & \textbf{Тип} & \textbf{Пространство} & \textbf{Атрибуты}\\ +\midrule +.init & PROGBITS & PROGRAM & ALLOC + EXEC\\ +.text & PROGBITS & PROGRAM & ALLOC + EXEC\\ +.fini & PROGBITS & PROGRAM & ALLOC + EXEC\\ +.data & PROGBITS & DATA & ALLOC + WRITE\\ +.bss & NOBITS & DATA & ALLOC + WRITE\\ +.control & PROGBITS & CONTROL & ALLOC, только чтение для guest-программы\\ +.input & PROGBITS & INPUT & ALLOC, только чтение для guest-программы\\ +.output & PROGBITS & OUTPUT & ALLOC + WRITE\\ +.trace & PROGBITS & TRACE & ALLOC + WRITE\\ +\bottomrule +\end{tabularx} +\end{center} + +\code{sh_addralign} задаёт требование выравнивания guest-адреса. Значения 0/1 означают отсутствие специального требования, остальные допустимые значения являются степенями двойки. \code{SHT_NOBITS} занимает архитектурную память, но не содержит данных в файле. + +\section{Объектная модель ET\_REL} + +Ассемблер формирует символы со смещениями относительно секций и явные записи RELA. Типовой путь выглядит так: + +\begin{center} +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,node distance=4mm] +\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,minimum width=24mm] (src) {исходник .s}; +\node[draw=McpuBlue,rounded corners,fill=McpuGreenBg,right=of src,minimum width=25mm] (as) {mcpu-as}; +\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of as,minimum width=31mm] (obj) {object.o / ET\_REL}; +\node[draw=McpuBlue,rounded corners,fill=McpuGreenBg,right=of obj,minimum width=24mm] (ld) {mcpu-ld}; +\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,right=of ld,minimum width=31mm] (exe) {ET\_EXEC}; +\draw[->,thick] (src)--(as); +\draw[->,thick] (as)--(obj); +\draw[->,thick] (obj)--(ld); +\draw[->,thick] (ld)--(exe); +\end{tikzpicture} +\end{center} + +В каждом \code{ET_REL}, включая результат \code{mcpu-ld -r}, имеется ровно одна \code{.mcpu.target}. Окончательная \code{.mcpu.lifecycle} ещё отсутствует: формирование lifecycle принадлежит компоновщику (linker), а в перемещаемом объекте представлено каноническими символами \code{_start}, \code{_life} и необязательным \code{_fini}. + +\section{Таблицы символов ABI} + +Запись MELF64 в таблице символов имеет размер 24 байта. Символ 0 --- полностью нулевая запись неопределённого символа. В \code{st_info} привязка (binding) хранится в старшей тетраде, тип --- в младшей. + +Значения binding: LOCAL=0, GLOBAL=1, WEAK=2. Типы символов: NOTYPE, OBJECT, FUNC, SECTION, FILE. Для обычных символов времени запуска используется visibility DEFAULT; в подстановке символов при запуске (interposition) участвуют только имена DEFAULT GLOBAL/WEAK. + +\subsection{st\_value в ET\_REL} + +Для определённого символа \code{st_shndx} содержит индекс секции, а \code{st_value} --- байтовое смещение от её начала. Для неопределённого символа используется \code{SHN_UNDEF} и нулевое значение. Директива \code{.equ} остаётся механизмом абсолютных выражений времени ассемблирования и не обязана создавать запись MELF symbol table. + +\subsection{Статическое разрешение символов} + +LOCAL никогда не разрешается через границу object file. Сильный GLOBAL имеет приоритет над WEAK. Несколько сильных GLOBAL-определений являются ошибкой. Если сильное определение отсутствует, несколько WEAK-определений выбираются детерминированно по порядку входных файлов компоновщика. Неопределённый сильный GLOBAL после окончательной компоновки является ошибкой. При \code{mcpu-ld -r} такой символ может оставаться неопределённым и переносится вместе с RELA в новый ET_REL. + +\subsection{Lifecycle-символы} + +\code{_start} и \code{_life} обязательны как GLOBAL/FUNC для каждого исполняемого файла; \code{_fini} --- необязательный GLOBAL/FUNC. Lifecycle-символы не могут быть WEAK. Псевдометка исходного текста \code{_start_life} существует только в синтаксисе ассемблера и эквивалентна двум символам \code{_start} и \code{_life} с одним смещением в секции \code{.text}, когда \code{.init} отсутствует. + +\section{RELA ABI} + +Запись MELF64 RELA имеет размер 24 байта: \code{r_offset}, \code{r_info} и знаковый 64-битный \code{r_addend}. Базовое выражение relocation: \code{S + A}. Все текущие MCPU relocation исправляют ровно 8 байт. + +\begin{longtable}{@{}L{38mm}L{28mm}L{30mm}L{58mm}@{}} +\toprule +\textbf{Relocation} & \textbf{Где находится поле} & \textbf{Цель} & \textbf{Записываемое значение}\\ +\midrule +\endfirsthead +\toprule +\textbf{Relocation} & \textbf{Где находится поле} & \textbf{Цель} & \textbf{Записываемое значение}\\ +\midrule +\endhead +R\_MCPU\_CODE64 & PROGRAM & PROGRAM & окончательное необработанное байтовое смещение PROGRAM\\ +R\_MCPU\_DATA64 & PROGRAM & DATA/.bss & окончательное необработанное байтовое смещение DATA\\ +R\_MCPU\_PTR64\_CODE & PROGRAM & загружаемый сегмент & PTR64(segment,offset) в порядке байтов машинного кода\\ +R\_MCPU\_PTR64\_DATA & секция данных & загружаемый сегмент & PTR64 в представлении данных целевой архитектуры\\ +R\_MCPU\_CPTR64\_DATA & секция данных & только PROGRAM & PTR64(PROGRAM,offset)\\ +\bottomrule +\end{longtable} + +В \code{ET_REL} поле \code{r_offset} является байтовым смещением внутри целевой секции, указанной через \code{sh_info}; \code{sh_link} указывает на таблицу символов. Все 8 байт исправляемого поля обязаны помещаться в сохранённой секции. Relocation непосредственно в область NOBITS запрещена: в файле нет байтов, которые можно исправить. + +Relocation неопределённого WEAK-указателя с нулевым addend может дать канонический полностью нулевой NULL. Для необработанных CODE64/DATA64 такое молчаливое преобразование в zero запрещено, потому что offset 0 является допустимым архитектурным адресом. + + +\section{Частичная компоновка mcpu-ld -r} + +Режим \code{mcpu-ld -r} объединяет несколько MELF \code{ET_REL} в один новый \code{ET_REL}. Это именно \term{partial link}{частичная компоновка}, а не построение исполняемого образа. + +Для каждой одноимённой секции вклады входных объектов конкатенируются в порядке входа с соблюдением их \code{sh_addralign}. Значения определённых символов и \code{r_offset} пересчитываются в координаты объединённой секции. LOCAL-символы разных объектов остаются раздельными даже при одинаковом имени. Для GLOBAL/WEAK действует обычное правило силы: сильный GLOBAL заменяет WEAK; два сильных GLOBAL одного имени являются ошибкой. + +RELA при \code{-r} не превращаются в окончательные архитектурные адреса. Они переносятся в выходной объект с новым section-relative offset и ссылкой на канонический символ результирующего ET_REL. Неопределённые GLOBAL/WEAK допускаются и могут быть разрешены последующей окончательной компоновкой. + +\begin{McpuCommand} +mcpu-ld -r -o combined.o a.o b.o c.o +mcpu-ld --stack-size=64K -o program main.o combined.o +\end{McpuCommand} + +STACK/HEAP, lifecycle-финализация, Program Headers, SONAME/NEEDED и runtime image в режиме \code{-r} не создаются. Поэтому \code{-r} взаимоисключён с \code{--dynamic}/\code{--shared}; опции размеров STACK/HEAP и \code{--soname} для него недопустимы. + +\section{Статические библиотеки lib*.a} + +Статическая библиотека MCPU не является новым типом MELF-файла. Это обычный UNIX \code{ar}-контейнер, чьи ordinary members являются независимыми текущими MELF \code{ET_REL}. Утилита \code{mcpu-ar} создаёт deterministic archives и при модификаторе \code{s} записывает настоящий System-V/GNU-style symbol index. + +\begin{McpuCommand} +mcpu-ar rcs libmodel.a model.o solver.o helpers.o +mcpu-ar t libmodel.a +\end{McpuCommand} + +При линковке из архива извлекается только member, определяющий текущий неразрешённый сильный GLOBAL. Неопределённый WEAK сам по себе member не вытягивает. После каждого извлечения текущий архив повторно сканируется до устойчивого состояния, поэтому новый member может породить ссылку на member, расположенный раньше в том же архиве. Уже пройденный отдельный \code{-l} archive автоматически после следующей библиотеки не пересматривается; повторное \code{-la} имеет реальный смысл. + +Для ABI-v1 и для \code{-r} \code{-lfoo} ищет только \code{libfoo.a}. Для ABI-v3 \code{--dynamic}/\code{--shared} поиск является directory-major: в каждом каталоге сначала проверяется \code{libfoo.so}, затем \code{libfoo.a}. Статически извлечённые members становятся частью результирующего MELF и не создают \code{DT_NEEDED}. + +\section{Метаданные профиля целевой архитектуры} + +\code{.mcpu.target} обязательна в \code{ET_REL} и \code{ET_EXEC}; модули ABI v2/v3 несут тот же профиль совместимости. Запись имеет размер 64 байта, не является ALLOC и выровнена на 8. + +\begin{longtable}{@{}L{38mm}L{18mm}L{94mm}@{}} +\toprule +\textbf{Поле} & \textbf{Смещение} & \textbf{Смысл}\\ +\midrule +\endfirsthead +\toprule +\textbf{Поле} & \textbf{Смещение} & \textbf{Смысл}\\ +\midrule +\endhead +mt\_version & 0 & версия структуры профиля, сейчас 1\\ +mt\_size & 4 & размер записи, сейчас 64\\ +mt\_isa\_revision & 8 & ревизия ISA, сейчас 1\\ +mt\_abi\_revision & 12 & ревизия программного ABI, сейчас 1\\ +mt\_program\_model & 16 & профиль ILP32/LP64/LLP64\\ +mt\_data\_byte\_order & 20 & порядок байтов объектов данных; согласован с EI\_DATA\\ +mt\_data\_word\_order & 24 & порядок слов LibMPU\\ +mt\_integer\_model & 28 & дополнительный код (дополнительный код)\\ +mt\_address\_model & 32 & PTR64 SEG4:OFF60\\ +mt\_register\_model & 36 & REG24 / регистровый пул 512 KiB\\ +mt\_real\_model & 40 & LibMPU\\ +mt\_complex\_model & 44 & LibMPU\\ +mt\_max\_align & 48 & максимальное обычное выравнивание ABI = 16\\ +mt\_flags & 52 & пока 0\\ +mt\_required\_features & 56 & пока 0\\ +\bottomrule +\end{longtable} + +Компоновщик требует совместимости профилей целевой архитектуры. Загрузчик повторно проверяет окончательный профиль до создания guest-областей памяти. Среда выполнения не исправляет несовместимый профиль и не конвертирует порядок байтов данных автоматически. + +\section{Метаданные lifecycle} + +Окончательный \code{ET_EXEC} содержит \code{.mcpu.lifecycle} фиксированного размера 32 байта. Запись описывает \textbf{семантику жизненного цикла}, но не дублирует адреса точек входа: единственным нормативным источником адресов остаётся Ehdr. + +Флаги ABI v1 фиксируют: START обязателен, LIFE обязателен, INIT и FINI необязательны; \code{e_entry} указывает на START; без INIT START совпадает с LIFE; LIFE завершается END и может быть продолжен; штатный EXIT переходит в FINI; область запуска (startup area) остаётся действительной всё время жизни программы. + +\begin{normative} +Метаданные lifecycle намеренно не содержат копий указателей на \code{_start/_life/_fini}. Благодаря этому в образе нет двух независимо перемещаемых источников истины. Загрузчик проверяет согласованность Ehdr и записи lifecycle, после чего использует числовые поля точек входа из Ehdr. +\end{normative} + +\section{Таблица заголовков сегментов (Program Headers)} + +Запись MELF64 Phdr имеет размер 64 байта и расширяет привычную ELF-подобную форму полем \code{p_maxsz}. \code{p_paddr=0}: отдельного пространства физических адресов у текущего MCPU ABI нет. \code{p_align} относится к выравниванию guest-адреса и файла, а не к размеру страницы host-системы. + +\begin{center} +\begin{tabularx}{0.96\textwidth}{@{}L{28mm}L{34mm}L{24mm}Y@{}} +\toprule +\textbf{Пространство} & \textbf{p\_type} & \textbf{Флаги} & \textbf{Правило размеров}\\ +\midrule +PROGRAM & PT\_LOAD & R|X & filesz=memsz=maxsz\\ +DATA & PT\_LOAD & R|W & filesz <= memsz; maxsz=memsz\\ +CONTROL & PT\_LOAD & R & сохранённый и runtime-размеры равны\\ +INPUT & PT\_LOAD & R & сохранённый и runtime-размеры равны\\ +OUTPUT & PT\_LOAD & R|W & сохранённый и runtime-размеры равны\\ +TRACE & PT\_LOAD & R|W & сохранённый и runtime-размеры равны\\ +STACK & PT\_MCPU\_STACK & R|W & filesz=0; memsz=maxsz\\ +HEAP & PT\_MCPU\_HEAP & R|W & filesz=0; memsz <= maxsz\\ +\bottomrule +\end{tabularx} +\end{center} + +Для пространств, загружаемых из образа, \code{p_vaddr=PTR64(segment,0)} в координатах окончательного образа исполняемого файла или модуля. Дескриптор STACK обязателен в \code{ET_EXEC}; дескриптор HEAP необязателен. Округление host-mmap к размеру страницы не является частью ABI. + +\section{Статический ET\_EXEC ABI v1} + +Обычный \code{mcpu-ld} завершает всю работу времени компоновки до запуска: +\begin{enumerate} +\item проверяет профиль целевой архитектуры каждого \code{ET_REL}; +\item размещает вклады секций с учётом \code{sh_addralign}; +\item создаёт единственную 16-байтовую защитную нулевую область DATA (NULL guard) по смещениям 0..15; +\item разрешает символы GLOBAL/WEAK/UNDEF; +\item применяет все RELA с проверкой диапазона и сегмента; +\item проверяет обязательные определения lifecycle; +\item назначает окончательные PTR64-адреса секций и символов; +\item формирует окончательные заголовков сегментов (Program Headers) и метаданные. +\end{enumerate} + +Исполняемый файл ABI v1 не нуждается в поиске символов при запуске. Любая попытка использовать \code{--ldpreload} или \code{MCPU_LD_PRELOAD} с ABI v1 является ошибкой, а не поводом неявно превратить программу в dynamic ABI. + +\section{Точки входа lifecycle исполняемого файла} + +\subsection{С секцией .init} +\code{_start} принадлежит \code{.init}; поля \code{e_entry} и \code{e_init_entry} указывают на \code{_start}. \code{_life} принадлежит \code{.text}, а \code{e_life_entry} указывает на \code{_life}. После \code{END} в INIT супервизор начинает повторяющиеся фазы LIFE. + +\subsection{Без секции .init} +\code{_start} и \code{_life} обязаны находиться по одному адресу в \code{.text}. Псевдометка \code{_start_life:} создаёт именно эту пару символов. В окончательном исполняемом файле \code{e_init_entry=0} и \code{e_entry == e_life_entry}. + +\subsection{FINI} +Если существует \code{.fini}/\code{_fini}, поле \code{e_fini_entry} указывает на него; иначе оно равно 0. Штатный \code{EXIT} после LIFE входит в FINI. Диагностическая остановка по внешнему лимиту шагов не имитирует \code{EXIT} и не обязана запускать FINI. + +\subsection{Связь MELF lifecycle с HLL Runtime ABI} +Сам MELF container определяет машинные entry points \code{_start}, \code{_life} и optional \code{_fini}. Поверх этого container contract существующий \code{mcpu-ld} реализует HLL complete-program layer: strong GLOBAL/FUNC \code{main+fini} в одном defining ET_REL классифицирует PROGRAM, а \code{init+life+fini} --- MODEL. Linker автоматически добавляет соответствующий CRT из \code{<MCPU-root>/lib/mcpu/}; отсутствие обязательного CRT является fatal error. Raw low-level objects с собственными \code{_start/_life[/_fini]} продолжают линковаться без automatic CRT, но смешивать оба режима запрещено. + +\begin{normative} +Это не меняет wire format MELF: HLL names являются linker policy над обычной symbol table, а окончательный ET_EXEC по-прежнему исполняется через нормативные lifecycle entry points. Loader не классифицирует HLL source form. +\end{normative} + +Полный контракт HLL + CRT + MCPU Libc, включая \code{McpuStartup}, PRE_RUNTIME/RUNNING, internal Libc hooks и MODEL return namespace, приведён в \code{libmcpu-bytecode-architecture-ru.pdf}. + +\section{Постоянная область запуска McpuStartup} + +До первой guest-инструкции загрузчик строит в верхней части STACK структуру \code{McpuStartup}. Она имеет поле версии, поэтому имя C-типа намеренно не содержит суффикс V1. + +\begin{center} +\begin{tabularx}{0.88\textwidth}{@{}L{20mm}L{30mm}L{18mm}Y@{}} +\toprule +\textbf{Смещение} & \textbf{Поле} & \textbf{Размер} & \textbf{Смысл}\\ +\midrule +0x00 & version & 4 & \code{MCPU_STARTUP_VERSION_1}\\ +0x04 & size & 4 & 32\\ +0x08 & argc & 8 & число аргументов guest-программы\\ +0x10 & argv & 8 & PTR64(STACK, массив argv)\\ +0x18 & зарезервировано & 8 & 0\\ +\bottomrule +\end{tabularx} +\end{center} + +После заголовка располагается массив \code{argv[argc+1]} из PTR64, завершающий NULL, затем строки аргументов, завершённые NUL, и нулевое дополнение. \code{startup_base} выровнен на 16 байт. Начальное состояние: \code{PC=e_entry}, \code{SP=startup_base}, \code{FP=stack_size}. Искусственного CALL-frame для \code{_start} нет. + +\section{Исторический MELF ABI v2} + +ABI v2 ввёл \code{ET_DYN}, \code{.dynsym/.dynstr} и сохранённые runtime RELA, но не имел SONAME/NEEDED. Полный набор shared objects задавался явным \code{mcpu-run --ldpreload=a.so:b.so}; вся startup-компоновка завершалась до первой инструкции \code{_start}. ABI v2 остаётся читаемым для совместимости, тогда как текущие \code{mcpu-ld --dynamic}/\code{--shared} выпускают ABI v3. + +\section{Frozen MELF ABI v3} + +ABI v3 сохраняет image/symbol/RELA-модель ABI v2 и добавляет нормальную модель зависимостей. Каждый dynamic ABI-v3 \code{ET_EXEC}/\code{ET_DYN} содержит ровно одну не-ALLOC секцию \code{.dynamic} типа \code{SHT_DYNAMIC}, связанную через \code{sh_link} с \code{.dynstr}. + +Запись \code{MElf64_Dyn} имеет размер 16 байт: знаковый 64-битный \code{d_tag} и беззнаковый 64-битный \code{d_val}. Текущие теги: + +\begin{center} +\begin{tabularx}{0.82\textwidth}{@{}L{42mm}L{22mm}Y@{}} +\toprule +\textbf{Тег} & \textbf{Значение} & \textbf{Смысл}\\ +\midrule +\code{DT_NULL} & 0 & обязательный единственный терминатор canonical stream\\ +\code{DT_NEEDED} & 1 & offset имени требуемого SONAME в \code{.dynstr}\\ +\code{DT_SONAME} & 14 & offset собственного SONAME shared object в \code{.dynstr}\\ +\bottomrule +\end{tabularx} +\end{center} + +После \code{DT_NULL} записей быть не должно. ABI-v3 \code{ET_DYN}, используемый как normal dependency, имеет ровно один SONAME. \code{ET_EXEC} не имеет собственного SONAME. Оба типа могут иметь ноль или более NEEDED в записанном порядке. + +\section{SONAME, NEEDED и link-time -L/-l} + +Имена development link, runtime identity и physical file разделены. Типичная установка: + +\begin{McpuCode} +libfoo.so -> libfoo.so.1 +libfoo.so.1 -> libfoo.so.1.2.3 +libfoo.so.1.2.3 # DT_SONAME = libfoo.so.1 +\end{McpuCode} + +При \code{-lfoo} linker находит development name \code{libfoo.so}, полностью валидирует выбранный ABI-v3 ET_DYN, читает его SONAME и записывает в потребитель именно \code{DT_NEEDED [libfoo.so.1]}. Абсолютный путь, имя symlink и physical filename в NEEDED не попадают. + +ABI-v3 dynamic output в каждом search directory предпочитает \code{libfoo.so}, затем \code{libfoo.a}. Если выбран archive, нужные ET_REL members встраиваются статически и никакого NEEDED для них нет. ABI-v1 и \code{-r} shared candidate не рассматривают. + +\section{Поиск библиотек и runtime root} + +\code{mcpu-ld} и \code{mcpu-run} используют общую relocatable root/config policy. Базовый system directory равен \code{<runtime-root>/lib}; конфигурационная цепочка в порядке роста приоритета: + +\begin{McpuCode} +<runtime-root>/etc/mcpu-ld.conf +/etc/mcpu/mcpu-ld.conf +$HOME/.mcpu/etc/mcpu-ld.conf +\end{McpuCode} + +Переменная конфигурации \code{MCPU_LD_SYSTEM_LIBRARY_PATH} заменяет system path; пустое значение отключает его. \code{--no-config} не читает config layers, но сохраняет executable-derived default. \code{--sys-root=PATH} подразумевает \code{--no-config} и использует \code{PATH/lib}. Для linker явные \code{-L} идут раньше system path; для runtime явный \code{--library-path} также имеет более высокий search priority. + +\section{Рекурсивная загрузка NEEDED} + +\code{mcpu-run} сначала читает прямые \code{DT_NEEDED} главного ET_EXEC, ищет каждый SONAME по runtime search policy, валидирует ABI-v3 ET_DYN и требует точного совпадения внутреннего \code{DT_SONAME} с запрошенным именем. Затем так же обрабатываются транзитивные NEEDED. + +Граф зависимостей строится breadth-first и дедуплицируется по SONAME. Direct dependencies предшествуют transitive; siblings сохраняют порядок NEEDED слева направо. Цикл вида \code{A -> B -> A} допустим и завершается через предварительную регистрацию SONAME. + +\section{.dynsym/.dynstr и runtime RELA} + +\code{.dynsym/.dynstr} являются частью startup-link ABI, в отличие от developer/debug \code{.symtab/.strtab}. DEFAULT GLOBAL/WEAK участвуют в выборе определения; LOCAL никогда не входит в interposition namespace. Lifecycle-имена \code{_start/_life/_fini} принадлежат главному executable и не являются runtime-preemptible symbols. + +Runtime \code{SHT_RELA} использует тот же \code{MElf64_Rela}. \code{sh_link} указывает на \code{.dynsym}, \code{sh_info} --- на allocated section с исправляемым полем, а \code{r_offset} остаётся offset относительно output section. Все runtime RELA выполняются до \code{_start}; lazy binding отсутствует. + +\section{Детерминированный runtime symbol scope} + +Для одного имени сначала сравнивается binding strength: GLOBAL всегда сильнее WEAK. Среди определений одинаковой силы действует scope: + +\begin{enumerate} +\item explicit preload modules --- наивысший scope, внутри списка правый элемент имеет больший приоритет; +\item главный ET_EXEC; +\item normal DT_NEEDED graph в breadth-first, left-to-right порядке. +\end{enumerate} + +Таким образом direct dependency выигрывает у конфликтующей transitive dependency той же силы, а первый sibling в NEEDED order выигрывает у следующего. Если GLOBAL нет вообще, тот же scope применяется к WEAK. + +\code{MCPU_LD_PRELOAD} является environment counterpart для \code{--ldpreload}. Environment entries добавляются первыми, command-line entries --- после них; существующее rightmost-wins правило поэтому естественно делает command line сильнее environment. Эта переменная не является частью \code{mcpu-ld.conf} и не подавляется \code{--no-config}. + +\section{Контракт ET_DYN} + +ABI-v2/v3 \code{ET_DYN} содержит только library \code{.text/.data/.bss} плюс non-ALLOC metadata. Он не владеет \code{.init}, \code{.fini}, \code{.control}, \code{.input}, \code{.output}, \code{.trace}, lifecycle definitions, \code{PT_MCPU_STACK} или \code{PT_MCPU_HEAP}. STACK, HEAP и model spaces принадлежат главному \code{ET_EXEC}. Для ABI v3 normal shared object SONAME обязателен. + +\section{LOCAL relocation внутри ET_DYN} + +LOCAL-символ остаётся частным и неподменяемым, но окончательная process base модуля заранее неизвестна. Поэтому relocation внутри ET_DYN, которой нужен окончательный PROGRAM/DATA address, сохраняется как LOCAL runtime RELA. Startup linker разрешает её строго внутри исходного модуля и добавляет runtime base соответствующего сегмента. Эта коррекция является нормативной частью runtime relocation contract и полностью сохраняется в ABI v3. + +\begin{center} +\begin{tikzpicture}[font=\sffamily\small,>=Stealth,node distance=7mm] +\node[draw=McpuBlue,rounded corners,fill=McpuBlueBg,minimum width=46mm] (so) {ET\_DYN после mcpu-ld}; +\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,below=of so,minimum width=62mm] (rel) {LOCAL runtime RELA + module-relative symbol}; +\node[draw=McpuGreen,rounded corners,fill=McpuGreenBg,below=of rel,minimum width=56mm] (run) {startup linker в mcpu-run}; +\node[draw=McpuBlue,rounded corners,fill=McpuGrayBg,below=of run,minimum width=62mm] (final) {process PTR64 с PROGRAM/DATA base}; +\draw[->,thick] (so)--(rel); +\draw[->,thick] (rel)--(run); +\draw[->,thick] (run)--(final); +\end{tikzpicture} +\end{center} + +\section{Размещение образа процесса и единственный DATA guard} + +У MCPU нет единого ELF-подобного смещения загрузки (load bias): PTR64 имеет независимые селекторы сегментов. Компоновщик запуска назначает отдельную базу для каждого архитектурного сегмента. + +\begin{center} +\begin{tabularx}{0.9\textwidth}{@{}L{48mm}Y@{}} +\toprule +\textbf{Вклад} & \textbf{База}\\ +\midrule +main PROGRAM & 0\\ +lib1 PROGRAM & \code{align_up(main_program_end, lib1_align)}\\ +lib2 PROGRAM & \code{align_up(lib1_program_end, lib2_align)}\\ +main DATA & 0\\ +первая DATA-библиотека & после окончательного DATA main; минимум 16, если DATA main отсутствует\\ +\bottomrule +\end{tabularx} +\end{center} + +В \code{ET_DYN} нет собственного DATA NULL guard. Во всём образе процесса существует ровно одна нулевая область offsets 0..15. Поэтому локальный символ библиотеки с относительным к модулю DATA offset 0 после размещения при запуске закономерно получает process offset 16 или больше. + +\section{BSS и соотношение filesz/memsz} + +\code{.bss} имеет тип \code{SHT_NOBITS}. Она участвует в расчёте адресов и увеличивает DATA \code{p_memsz}, но не увеличивает объём данных в файле \code{p_filesz}. Статический и startup-загрузчики сначала получают изначально обнулённую память, затем копируют сохранённые байты, поэтому NOBITS детерминированно начинается с нулей. + +Для PROGRAM хранится только машинный код, поэтому \code{filesz=memsz}. Для DATA обычно \code{filesz < memsz}. LOCAL-ссылки из \code{ET_DYN} в DATA/.bss всё равно требуют перебазирования по базе модуля, даже если целевые байты относятся к NOBITS. + +\section{Дескриптор STACK и командная строка} + +Размер STACK является частью ABI исполняемого файла. Он задаётся компоновщиком через \code{--stack-size=N} и записывается в \code{PT_MCPU_STACK}; \code{mcpu-run} не может его переопределить. Разделяемые объекты ABI v2 не задают политику STACK. + +Предпочтительный синтаксис запуска использует явный разделитель: +\begin{lstlisting}[language={}] +mcpu-run [runtime-options] -- executable [program-args...] +\end{lstlisting} + +Все параметры после \code{--} передаются в guest \code{argv} без повторного разбора программой \code{mcpu-run}; текстовое имя исполняемого файла становится \code{argv[0]}. Старая форма без разделителя сохранена для совместимости. + +\section{Дескриптор HEAP, _end и SYS\_brk} + +Необязательный \code{PT_MCPU_HEAP} хранит начальный подготовленный размер в \code{p_memsz} и неизменяемый предел в \code{p_maxsz}; оба значения не меньше 16, причём max >= initial. Определяемый компоновщиком символ \code{_end=PTR64(HEAP,16)} является частным для исполняемого файла, неподменяемым и задаёт начальный и минимальный program break. + +\code{SYS_brk} имеет номер 10. NULL-аргумент запрашивает текущее значение; HEAP PTR64 задаёт абсолютный новый break. В отличие от общего stable syscall rule \code{-MCPU_errno}, \code{SYS_brk} возвращает фактический текущий HEAP PTR64. При отклонённом запросе break не меняется. Shrink зануляет освобождённый диапазон, но не обязан уменьшать host-отображение памяти; последующий рост остаётся детерминированным. Guest PTR64 остаётся корректным при перемещении host backing, поскольку содержит segment+offset, а не host-адрес. + +\section{Дисциплина проверки загрузчика} + +Загрузчик сначала полностью проверяет структуру файла и только затем создаёт guest-области памяти. В частности проверяются: +\begin{itemize} +\item сигнатура, класс, порядок данных, версия, OSABI, ABI/machine, размеры заголовков и границы таблиц; +\item обязательные метаданные target/lifecycle и зарезервированные поля; +\item уникальность заголовков сегментов (Program Headers), права доступа, соотношения размеров, выравнивание и границы OFF60; +\item соответствие каждой ALLOC-секции её архитектурному сегменту; +\item selector/range точек входа lifecycle; +\item нулевые байты DATA guard в статическом исполняемом образе; +\item для ABI v2/v3 --- структура dynsym/RELA, диапазоны символов, границы исправляемых полей и семантика целевого сегмента; для ABI v3 дополнительно canonical .dynamic, SONAME/NEEDED и соответствие identity загруженного ET_DYN запрошенному SONAME. +\end{itemize} + +\begin{principle} +\textbf{Загрузчик проверяет, но не «чинит».} Он не выводит lifecycle из названий секций, не создаёт недостающий guard, не меняет порядок байтов PROGRAM, не увеличивает STACK, не ослабляет HEAP limit и не переинтерпретирует несовместимый профиль целевой архитектуры. Компоновщик запуска ABI v2/v3 выполняет только явно определённые сохранённые relocation, dependency discovery и разрешение символов. +\end{principle} + +\section{Режимы команды mcpu-ld} + +\begin{lstlisting}[language={}] +# partial ET_REL +mcpu-ld -r -o combined.o a.o b.o + +# статический ABI v1 +mcpu-ld --stack-size=4096 --heap-size=64K --heap-limit=1M \ + -L$HOME/.mcpu/lib -lmodel -o app main.o + +# главный исполняемый файл frozen ABI v3 +mcpu-ld --dynamic --stack-size=64K --no-heap \ + -L$HOME/.mcpu/lib -lrk4 -o model pendulum.o + +# shared object ABI v3 +mcpu-ld --shared --soname=librk4.so.1 \ + -o librk4.so.1.0.0 rk4.o +\end{lstlisting} + +STACK/HEAP принадлежат только \code{ET_EXEC}. \code{--soname} допустим только для \code{--shared}. \code{-r} не создаёт executable/runtime metadata и использует для \code{-l} только static archives. Суффиксы размера K/KiB, M/MiB, G/GiB используют двоичные множители. + + +\section{Инструменты анализа и безопасного редактирования MELF} +Binary utilities работают поверх того же MELF contract и не создают отдельного container ABI. + +\subsection{Read-only inspection} +\code{mcpu-readelf} показывает file/program/section headers, symbol tables, RELA, \code{.dynamic} и MCPU-specific metadata. \code{mcpu-nm} выводит \code{.symtab} или \code{.dynsym} и умеет читать static archives. \code{mcpu-objdump} объединяет section/relocation views с instruction disassembly; decoder общий с CPU runtime через \code{__cpu_decode_at()}, поэтому ISA не дублируется отдельным parser-ом. + +\subsection{mcpu-strip} +Текущая policy намеренно консервативна. В ET\_REL ordinary \code{.symtab/.strtab} сохраняются, потому что они являются частью последующей link semantics. В ET\_EXEC/ET\_DYN ordinary non-ALLOC \code{SHT_SYMTAB} может быть удалена только если retained sections от неё не зависят; \code{.dynsym/.dynstr/.dynamic}, RELA, MCPU metadata и allocated image всегда сохраняются. Современные final-image writers уже компактны, поэтому для обычного ET\_EXEC/ET\_DYN strip часто является byte-for-byte no-op. + +\subsection{mcpu-objcopy} +\code{mcpu-objcopy} выполняет только MELF-to-MELF structural copy/edit. Safe interface умеет выбирать/удалять sections и dump/add/update/rename для metadata, но запрещает разрушать allocated image, frozen dynamic metadata, runtime relocations и ET\_REL link-critical dependencies. Новая section через \code{--add-section} является non-ALLOC \code{SHT_PROGBITS}. Metadata tail может быть repacked, но program headers и runtime-visible PT\_LOAD bytes должны оставаться неизменными. + +Flat binary, Intel HEX, S-record, VMA/LMA и firmware-image conversion намеренно отсутствуют: виртуальная MCPU исполняет MELF напрямую. + +\subsection{Non-ALLOC debug metadata и frozen ABI v3} +\begin{normative} +Будущий debug format не обязан менять MELF ABI v3, если его sections остаются non-ALLOC, не входят в PT\_LOAD, не требуются loader/runtime для исполнения и могут быть полностью удалены без изменения guest-visible поведения. Версия такого debug format должна быть самостоятельной и не кодироваться повышением \code{EI_ABIVERSION} MELF. +\end{normative} + +В ET\_REL debug sections при необходимости могут иметь link-time RELA к code/data symbols; такие relocations являются metadata link-editor contract и не должны становиться обязательными runtime relocations final ET\_EXEC/ET\_DYN. + + +\section{Правила совместимости} + +\begin{enumerate} +\item Статический \code{ET_EXEC} ABI v1 и \code{ET_REL} ABI v1 остаются основой статического/разработческого пути; ABI-v1 executable отвергает preload. +\item Исторический ABI v2 остаётся читаемым и использует explicit-preload startup model без SONAME/NEEDED. +\item Frozen ABI v3 является текущим normal dynamic ABI. Несовместимое изменение \code{.dynamic}, NEEDED/SONAME, runtime scope или retained-relocation contract требует нового номера ABI. +\item Static \code{lib*.a} и \code{mcpu-ld -r} являются link-time механизмами над ABI-v1 ET_REL и не требуют ABI v4. +\item Ревизия ISA и CALL ABI остаются равны 1 независимо от версии контейнерного dynamic ABI. +\item Будущие расширения должны использовать явные version/feature поля, а не менять смысл зарезервированных битов или записей молча. Non-ALLOC debug metadata с самостоятельной версией формата не требует нового MELF ABI, пока loader/runtime semantics не зависят от неё. +\end{enumerate} + + +\appendix + +\section{Размеры сериализованных записей} + +\begin{center} +\begin{tabularx}{0.9\textwidth}{@{}L{48mm}L{22mm}Y@{}} +\toprule +\textbf{Запись} & \textbf{Байт} & \textbf{Назначение}\\ +\midrule +MElf64\_Ehdr & 88 & заголовок файла\\ +MElf64\_Shdr & 64 & заголовок секции\\ +MElf64\_Sym & 24 & запись таблицы символов\\ +MElf64\_Rela & 24 & запись RELA\\ +MElf64\_Dyn & 16 & запись \code{.dynamic} ABI v3\\ +MElf64\_Phdr & 64 & заголовок сегмента (Program Header) с \code{p_maxsz}\\ +MElf\_McpuTarget & 64 & метаданные профиля целевой архитектуры\\ +MElf\_McpuLifecycle & 32 & метаданные lifecycle\\ +McpuStartup & 32 & заголовок области запуска (startup) в STACK guest-программы; это не сериализованные метаданные MELF\\ +\bottomrule +\end{tabularx} +\end{center} + +\section{Канонические имена секций} + +\begin{center} +\begin{tabularx}{\textwidth}{@{}L{62mm}Y@{}} +\code{.init}, \code{.text}, \code{.fini} & Секции машинного кода PROGRAM.\\ +\code{.data}, \code{.bss} & Объекты DATA; \code{.bss} имеет тип NOBITS.\\ +\code{.control}, \code{.input}, \code{.output}, \code{.trace} & Модельные пространства, принадлежащие ET\_EXEC.\\ +\code{.symtab}, \code{.strtab} & Информация о символах для разработки и статической компоновки.\\ +\code{.dynsym}, \code{.dynstr} & Runtime symbol/string tables ABI v2/v3.\\ +\code{.dynamic} & Non-ALLOC dependency metadata ABI v3: SONAME/NEEDED/NULL.\\ +\code{.rela.init}, \code{.rela.text}, \code{.rela.fini} & Секции relocation для PROGRAM.\\ +RELA секций данных & \code{.rela.data}, \code{.rela.control}, \code{.rela.input}, \code{.rela.output}, \code{.rela.trace}.\\ +\code{.mcpu.target} & Обязательный профиль целевой архитектуры.\\ +\code{.mcpu.lifecycle} & Окончательный lifecycle-контракт исполняемого файла.\\ +\code{.shstrtab} & Таблица строк с именами секций.\\ +\end{tabularx} +\end{center} + +\section{Нормативная памятка frozen dynamic ABI v3} + +\begin{normative} +\begin{itemize} +\item New dynamic output использует ABI v3; ABI v2 поддерживается как исторический explicit-preload input format. +\item ABI-v3 ET_DYN имеет обязательный SONAME и не владеет lifecycle, model spaces, STACK или HEAP. +\item ABI-v3 ET_EXEC/ET_DYN имеют canonical non-ALLOC \code{.dynamic}; NEEDED содержит SONAME, а не pathname или development symlink name. +\item Normal dependencies обнаруживаются рекурсивно по SONAME, deduplicate/cycle handling выполняются до guest execution. +\item GLOBAL сильнее WEAK; explicit preload имеет наивысший equal-strength scope и rightmost priority; затем main executable; затем breadth-first/left-to-right NEEDED graph. +\item LOCAL никогда не участвует в name interposition; нуждающиеся в process base LOCAL ET_DYN relocations сохраняются и rebased внутри исходного модуля. +\item Все runtime relocation и symbol resolution заканчиваются до \code{_start}; PLT/GOT, lazy binding, \code{dlopen()}, \code{dlsym()} и \code{dlclose()} отсутствуют. +\item Во всём process DATA существует один NULL guard; отдельный ET_DYN guard не создаётся. +\item Static archives и \code{mcpu-ld -r} работают на link-time поверх ET_REL и не меняют frozen ABI v3. +\end{itemize} +\end{normative} + +\end{document} diff --git a/doc/src/libmcpu-opcode-table.tex b/doc/src/libmcpu-opcode-table.tex new file mode 100644 index 0000000..33d0bc4 --- /dev/null +++ b/doc/src/libmcpu-opcode-table.tex @@ -0,0 +1,174 @@ +\begin{longtable}{@{}L{20mm}L{19mm}L{43mm}L{77mm}@{}} +\toprule +\textbf{Mnemonic} & \textbf{OPCODE16} & \textbf{Operands} & \textbf{Назначение} \\ +\midrule +\endfirsthead +\toprule +\textbf{Mnemonic} & \textbf{OPCODE16} & \textbf{Operands} & \textbf{Назначение} \\ +\midrule +\endhead +NOP & \code{0x0000} & \code{---} & Нет операции; PC переходит к следующей инструкции. \\ +HALT & \code{0x0001} & \code{---} & Устанавливает machine halt state; используется как низкоуровневая остановка CPU. \\ +END & \code{0x0002} & \code{---} & Завершает текущую externally managed INIT/LIFE/FINI phase и возвращает управление supervisor-у. \\ +EXIT & \code{0x0003} & \code{r32 status} & Graceful завершение программы/модели с signed int32 status; при наличии FINI runtime переходит к _fini. \\ +SYSCALL & \code{0x0004} & \code{---} & Выполняет системный вызов через фиксированную register ABI area. \\ +SETF & \code{0x0010} & \code{PSWBIT8} & Устанавливает ровно один writable arithmetic/status flag в диапазоне PSW[15:0]; HF/TF/IF недопустимы. \\ +CLRF & \code{0x0011} & \code{PSWBIT8} & Очищает ровно один writable arithmetic/status flag в диапазоне PSW[15:0]; HF/TF/IF недопустимы. \\ +CLRCPUF & \code{0x0012} & \code{---} & Очищает CPU flag byte PSW[7:0], сохраняя PSW[15:8] и control/execution state. \\ +CLRMPUF & \code{0x0013} & \code{---} & Очищает MPU flag byte PSW[15:8], сохраняя PSW[7:0] и control/execution state. \\ +MOV & \code{0x0100} & \code{Rdst, Rsrc} & Копирует объект между регистрами одинаковой физической ширины. \\ +CLR & \code{0x0101} & \code{Rdst} & Заполняет выбранный регистр нулями. \\ +SWAP & \code{0x0102} & \code{Ra, Rb} & Обменивает содержимое двух регистров одинаковой ширины. \\ +BSWAP & \code{0x0103} & \code{Rdst, Rsrc} & Разворачивает порядок байтов source object; raw byte reversal без числовой интерпретации. \\ +LDI & \code{0x0110} & \code{Rdst, imm64} & Загружает signed integer immediate с приведением к ширине integer register; conversion PSW-neutral. \\ +LDR & \code{0x0111} & \code{Rdst, real literal} & Загружает exactly representable immediate Real32/Real64; более широкие constants следует хранить в DATA. \\ +LDC & \code{0x0112} & \code{Cdst, complex literal} & Загружает immediate Complex64 как две точно представимые Real32 components. \\ +LOAD & \code{0x0120} & \code{Rdst, DATA64} & Копирует объект из DATA по прямому DATA-relative адресу в регистр. \\ +STORE & \code{0x0121} & \code{DATA64, Rsrc} & Копирует регистр в DATA по прямому DATA-relative адресу. \\ +LEA & \code{0x0130} & \code{r64 dst, PTR64} & Формирует полный segment-aware PTR64 на label/target object. \\ +LEASP & \code{0x0131} & \code{r64 dst, OFF64} & Формирует STACK PTR64 как SP плюс signed byte offset. \\ +LOADP & \code{0x0132} & \code{R/C dst, r64 ptr} & Читает объект через PTR64 после проверки segment rights и bounds. \\ +STOREP & \code{0x0133} & \code{r64 ptr, R/C src} & Записывает объект через PTR64 после проверки segment rights и bounds. \\ +PADD & \code{0x0140} & \code{r64 dst, r64 ptr, r64 delta} & Прибавляет signed byte delta из r64 к PTR64 с сохранением segment selector. \\ +PADDI & \code{0x0141} & \code{r64 dst, r64 ptr, OFF64} & Прибавляет signed immediate byte offset к PTR64. \\ +PSUB & \code{0x0142} & \code{r64 dst, r64 ptr, r64 delta} & Вычитает signed byte delta из PTR64. \\ +PSUBI & \code{0x0143} & \code{r64 dst, r64 ptr, OFF64} & Вычитает signed immediate byte offset из PTR64. \\ +PDIFF & \code{0x0144} & \code{r64 dst, r64 a, r64 b} & Вычисляет signed разность byte offsets двух совместимых PTR64. \\ +BMOV & \code{0x0150} & \code{r64 dst, r64 src, r64 count} & Перемещает count байтов между PTR64 ranges с memmove-семантикой и полной предварительной проверкой. \\ +BMOVI & \code{0x0151} & \code{r64 dst, r64 src, IMM64 count} & То же, но byte count задан immediate. \\ +IADD & \code{0x1000} & \code{Idst, Ia, Ib} & Беззнаковое/битовое integer сложение выбранной ширины с публикацией integer flags. \\ +IADC & \code{0x1001} & \code{Idst, Ia, Ib} & Integer сложение с входным carry CF. \\ +ISUB & \code{0x1002} & \code{Idst, Ia, Ib} & Integer вычитание выбранной ширины. \\ +ISBB & \code{0x1003} & \code{Idst, Ia, Ib} & Integer вычитание с borrow/carry state. \\ +IAND & \code{0x1004} & \code{Idst, Ia, Ib} & Побитовое AND. \\ +IOR & \code{0x1005} & \code{Idst, Ia, Ib} & Побитовое OR. \\ +IXOR & \code{0x1006} & \code{Idst, Ia, Ib} & Побитовое XOR. \\ +INOT & \code{0x1010} & \code{Idst, Isrc} & Побитовое дополнение integer object. \\ +INEG & \code{0x1011} & \code{Idst, Isrc} & Двухкомплементарное отрицание integer object. \\ +ICMP & \code{0x1020} & \code{Ia, Ib} & Сравнивает integer operands одинаковой ширины и обновляет comparison flags без сохранения результата. \\ +ITEST & \code{0x1021} & \code{Ia, Ib} & Выполняет AND только для формирования integer condition flags. \\ +ISHL & \code{0x1030} & \code{Idst, Isrc} & Logical shift left на один bit. \\ +ISHR & \code{0x1031} & \code{Idst, Isrc} & Logical shift right на один bit. \\ +ISAL & \code{0x1032} & \code{Idst, Isrc} & Arithmetic shift left на один bit. \\ +ISAR & \code{0x1033} & \code{Idst, Isrc} & Arithmetic shift right на один bit с сохранением знака. \\ +IROL & \code{0x1034} & \code{Idst, Isrc} & Rotate left на один bit. \\ +IROR & \code{0x1035} & \code{Idst, Isrc} & Rotate right на один bit. \\ +IRCL & \code{0x1036} & \code{Idst, Isrc} & Rotate left through carry CF на один bit. \\ +IRCR & \code{0x1037} & \code{Idst, Isrc} & Rotate right through carry CF на один bit. \\ +ISHLN & \code{0x1040} & \code{Idst, Isrc, r64 n} & Logical shift left на n bits. \\ +ISHRN & \code{0x1041} & \code{Idst, Isrc, r64 n} & Logical shift right на n bits. \\ +ISALN & \code{0x1042} & \code{Idst, Isrc, r64 n} & Arithmetic shift left на n bits. \\ +ISARN & \code{0x1043} & \code{Idst, Isrc, r64 n} & Arithmetic shift right на n bits. \\ +IROLN & \code{0x1044} & \code{Idst, Isrc, r64 n} & Rotate left на n bits. \\ +IRORN & \code{0x1045} & \code{Idst, Isrc, r64 n} & Rotate right на n bits. \\ +IRCLN & \code{0x1046} & \code{Idst, Isrc, r64 n} & Rotate left through carry на n bits. \\ +IRCRN & \code{0x1047} & \code{Idst, Isrc, r64 n} & Rotate right through carry на n bits. \\ +IINC & \code{0x1050} & \code{Idst, Isrc} & Увеличивает integer value на единицу. \\ +IDEC & \code{0x1051} & \code{Idst, Isrc} & Уменьшает integer value на единицу. \\ +IXCHG & \code{0x1052} & \code{Ia, Ib} & Обменивает integer values одинаковой ширины. \\ +ICPY & \code{0x1053} & \code{Idst, Isrc} & Unsigned width-changing copy: zero-extension/truncation по integer object rules. \\ +ICVT & \code{0x1054} & \code{Idst, Isrc} & Signed width-changing conversion с sign extension/truncation; conversion PSW-neutral. \\ +IMUL & \code{0x1060} & \code{Iprod, Ia, Ib} & Полное unsigned integer произведение; destination имеет product width, допустимую ISA. \\ +ISMUL & \code{0x1061} & \code{Iprod, Ia, Ib} & Полное signed integer произведение. \\ +IDIV & \code{0x1062} & \code{Iquot, Irem, Inum, Iden} & Unsigned integer division с отдельными quotient и remainder. \\ +ISDIV & \code{0x1063} & \code{Iquot, Irem, Inum, Iden} & Signed integer division с отдельными quotient и remainder. \\ +IBITSLEN & \code{0x1064} & \code{r64 dst, Isrc} & Возвращает число значащих bits integer source. \\ +RADD & \code{0x2000} & \code{Rdst, Ra, Rb} & Сложение двух Real одинаковой physical width. \\ +RSUB & \code{0x2001} & \code{Rdst, Ra, Rb} & Вычитание Real. \\ +RMUL & \code{0x2002} & \code{Rdst, Ra, Rb} & Умножение Real. \\ +RDIV & \code{0x2003} & \code{Rdst, Ra, Rb} & Деление Real. \\ +RSQRT & \code{0x2010} & \code{Rdst, Rsrc} & Квадратный корень Real. \\ +RSIN & \code{0x2020} & \code{Rdst, Rsrc} & Синус Real. \\ +RCOS & \code{0x2021} & \code{Rdst, Rsrc} & Косинус Real. \\ +RTAN & \code{0x2022} & \code{Rdst, Rsrc} & Тангенс Real. \\ +RASIN & \code{0x2023} & \code{Rdst, Rsrc} & Арксинус Real. \\ +RACOS & \code{0x2024} & \code{Rdst, Rsrc} & Арккосинус Real. \\ +RATAN & \code{0x2025} & \code{Rdst, Rsrc} & Арктангенс Real. \\ +RLOG & \code{0x2030} & \code{Rdst, Rsrc} & Натуральный логарифм Real. \\ +RLOG10 & \code{0x2031} & \code{Rdst, Rsrc} & Десятичный логарифм Real. \\ +RLOG2 & \code{0x2032} & \code{Rdst, Rsrc} & Двоичный логарифм Real. \\ +REXP & \code{0x2033} & \code{Rdst, Rsrc} & Экспонента $e^x$. \\ +RSINH & \code{0x2040} & \code{Rdst, Rsrc} & Гиперболический синус. \\ +RCOSH & \code{0x2041} & \code{Rdst, Rsrc} & Гиперболический косинус. \\ +RTANH & \code{0x2042} & \code{Rdst, Rsrc} & Гиперболический тангенс. \\ +RPOW & \code{0x2050} & \code{Rdst, Ra, Rb} & Возводит Real a в степень Real b. \\ +RHYPOT & \code{0x2051} & \code{Rdst, Ra, Rb} & Вычисляет hypot(a,b) в Real domain. \\ +RATAN2 & \code{0x2052} & \code{Rdst, Ra, Rb} & Вычисляет atan2(y,x) в Real domain. \\ +RNEG & \code{0x2060} & \code{Rdst, Rsrc} & Изменяет знак Real. \\ +RABS & \code{0x2061} & \code{Rdst, Rsrc} & Модуль Real. \\ +RCMP & \code{0x2062} & \code{r64 dst, Ra, Rb} & Сравнивает Real a/b и возвращает classification \{-2,-1,0,+1\} в r64. \\ +RCPY & \code{0x2063} & \code{Rdst, Rsrc} & Копирует Real object совместимой physical width. \\ +RCVT & \code{0x2064} & \code{Rdst, Rsrc} & Преобразует Real между поддерживаемыми precision widths; conversion PSW-neutral. \\ +RFLOOR & \code{0x2070} & \code{Rdst, Rsrc} & Округляет Real вниз. \\ +RCEIL & \code{0x2071} & \code{Rdst, Rsrc} & Округляет Real вверх. \\ +RROUND & \code{0x2072} & \code{Rdst, Rsrc} & Округляет Real по правилам LibMPU. \\ +RFREXP & \code{0x2073} & \code{Rfrac, Iexp, Rsrc} & Разлагает Real на significand и integer exponent. \\ +RLDEXP & \code{0x2074} & \code{Rdst, Rsrc, Iexp} & Формирует Real как source, умноженный на степень двойки с integer exponent. \\ +RLOGB & \code{0x2075} & \code{Idst, Rsrc} & Возвращает integer exponent/classification для Real source. \\ +RMODF & \code{0x2076} & \code{Rfrac, Rint, Rsrc} & Разделяет Real на fractional и integral parts. \\ +RREMAIN & \code{0x2077} & \code{Rdst, Ra, Rb} & IEEE/LibMPU-style remainder для двух Real operands. \\ +RLOG1P & \code{0x2080} & \code{Rdst, Rsrc} & Вычисляет log(1+x) с Real semantics. \\ +REXPM1 & \code{0x2081} & \code{Rdst, Rsrc} & Вычисляет exp(x)-1. \\ +RASINH & \code{0x2082} & \code{Rdst, Rsrc} & Обратный гиперболический синус. \\ +RACOSH & \code{0x2083} & \code{Rdst, Rsrc} & Обратный гиперболический косинус. \\ +RATANH & \code{0x2084} & \code{Rdst, Rsrc} & Обратный гиперболический тангенс. \\ +ITOR & \code{0x2090} & \code{Rdst, Isrc} & Преобразует signed integer в Real; conversion PSW-neutral. \\ +UITOR & \code{0x2091} & \code{Rdst, Isrc} & Преобразует unsigned integer в Real; conversion PSW-neutral. \\ +RTOI & \code{0x2092} & \code{Idst, Rfrac, Rsrc} & Преобразует Real в signed integer destination и отдельно возвращает fractional remainder. \\ +RTOUI & \code{0x2093} & \code{Idst, Rfrac, Rsrc} & Преобразует Real в unsigned integer destination и отдельно возвращает fractional remainder. \\ +RISNEG & \code{0x20a0} & \code{r64 dst, Rsrc} & Возвращает r64 predicate: является ли Real отрицательным. \\ +RSIGN & \code{0x20a1} & \code{r64 dst, Rsrc} & Возвращает signed Real classification code \{-3..+1\} в r64. \\ +RISIND & \code{0x20a2} & \code{r64 dst, Rsrc} & Возвращает predicate для indeterminate Real representation. \\ +RISNAN & \code{0x20a3} & \code{r64 dst, Rsrc} & Возвращает predicate для NaN. \\ +RISNANMAX & \code{0x20a4} & \code{r64 dst, Rsrc} & Возвращает predicate для NaN max-class representation. \\ +RISNANMIN & \code{0x20a5} & \code{r64 dst, Rsrc} & Возвращает predicate для NaN min-class representation. \\ +RISINF & \code{0x20a6} & \code{r64 dst, Rsrc} & Возвращает predicate для infinity. \\ +RISSIGNULL & \code{0x20a7} & \code{r64 dst, Rsrc} & Возвращает predicate для signed null/zero classification. \\ +RCONST & \code{0x2100} & \code{Rdst, CONST8} & Загружает предопределённую математическую Real constant по CONST8 selector. \\ +CADD & \code{0x3000} & \code{Cdst, Ca, Cb} & Сложение Complex. \\ +CSUB & \code{0x3001} & \code{Cdst, Ca, Cb} & Вычитание Complex. \\ +CMUL & \code{0x3002} & \code{Cdst, Ca, Cb} & Умножение Complex. \\ +CDIV & \code{0x3003} & \code{Cdst, Ca, Cb} & Деление Complex. \\ +CEXP & \code{0x3020} & \code{Cdst, Csrc} & Комплексная экспонента. \\ +CSIN & \code{0x3021} & \code{Cdst, Csrc} & Комплексный синус. \\ +CCOS & \code{0x3022} & \code{Cdst, Csrc} & Комплексный косинус. \\ +CSINH & \code{0x3023} & \code{Cdst, Csrc} & Комплексный гиперболический синус. \\ +CCOSH & \code{0x3024} & \code{Cdst, Csrc} & Комплексный гиперболический косинус. \\ +CLOG & \code{0x3025} & \code{Cdst, Csrc} & Комплексный натуральный логарифм. \\ +CSQRT & \code{0x3026} & \code{Cdst, Csrc} & Комплексный квадратный корень. \\ +CPOW & \code{0x3050} & \code{Cdst, Ca, Cb} & Комплексное возведение в степень. \\ +CREAL & \code{0x3060} & \code{Rdst, Csrc} & Извлекает real component Complex object. \\ +CIMAG & \code{0x3061} & \code{Rdst, Csrc} & Извлекает imaginary component. \\ +CRTOC & \code{0x3062} & \code{Cdst, Rsrc} & Преобразует Real в Complex с нулевой imaginary component; conversion PSW-neutral. \\ +CGEN & \code{0x3063} & \code{Cdst, Rre, Rim} & Создаёт Complex из real и imaginary components. \\ +CPOLAR & \code{0x3064} & \code{Cdst, Rrho, Rtheta} & Создаёт Complex по polar representation rho/theta. \\ +CCONJ & \code{0x3065} & \code{Cdst, Csrc} & Комплексное сопряжение. \\ +CABS & \code{0x3066} & \code{Rdst, Csrc} & Возвращает абсолютную величину Complex. \\ +CNORM & \code{0x3067} & \code{Rdst, Csrc} & Возвращает квадрат нормы Complex. \\ +CARG & \code{0x3068} & \code{Rdst, Csrc} & Возвращает аргумент/phase Complex. \\ +CISEQ & \code{0x3070} & \code{r64 dst, Ca, Cb} & Возвращает predicate равенства двух Complex. \\ +CISNE & \code{0x3071} & \code{r64 dst, Ca, Cb} & Возвращает predicate неравенства двух Complex. \\ +CCPY & \code{0x3072} & \code{Cdst, Csrc} & Копирует Complex object совместимой physical width. \\ +CCVT & \code{0x3073} & \code{Cdst, Csrc} & Преобразует Complex между precision widths; conversion PSW-neutral. \\ +JMP & \code{0x4000} & \code{CODE64 target} & Безусловный прямой переход на PROGRAM address. \\ +JSET & \code{0x4001} & \code{PSWBIT8, CODE64} & Переходит, если выбранный branchable PSW bit установлен. \\ +JCLR & \code{0x4002} & \code{PSWBIT8, CODE64} & Переходит, если выбранный PSW bit очищен. \\ +JMPP & \code{0x4003} & \code{r64 ptr} & Косвенный переход через PROGRAM PTR64. \\ +CALL & \code{0x4010} & \code{CODE64 target} & Кладёт address следующей инструкции в STACK и передаёт управление target. \\ +RET & \code{0x4011} & \code{---} & Извлекает return PC из STACK и возвращается из CALL. \\ +CALLP & \code{0x4012} & \code{r64 ptr} & Косвенный CALL через PROGRAM PTR64 с push return PC. \\ +PUSH & \code{0x5000} & \code{R/C src} & Кладёт register object в STACK и изменяет SP согласно stack ABI. \\ +POP & \code{0x5001} & \code{R/C dst} & Извлекает register object из STACK. \\ +LDSP & \code{0x5010} & \code{R/C dst, OFF64} & Читает object по адресу SP + signed byte offset. \\ +STSP & \code{0x5011} & \code{OFF64, R/C src} & Записывает object по адресу SP + signed byte offset. \\ +ADJSP & \code{0x5020} & \code{OFF64} & Изменяет SP на signed byte offset с проверкой STACK bounds/alignment policy. \\ +PUSHFP & \code{0x5030} & \code{---} & Сохраняет текущий 64-bit FP в STACK. \\ +SETFP & \code{0x5031} & \code{---} & Устанавливает FP = SP. \\ +RESTSP & \code{0x5032} & \code{---} & Восстанавливает SP = FP. \\ +POPFP & \code{0x5033} & \code{---} & Извлекает 64-bit FP из STACK. \\ +LDFP & \code{0x5040} & \code{R/C dst, OFF64} & Читает object по адресу FP + signed byte offset. \\ +STFP & \code{0x5041} & \code{OFF64, R/C src} & Записывает object по адресу FP + signed byte offset. \\ +LEAFP & \code{0x5042} & \code{r64 dst, OFF64} & Формирует STACK PTR64 на FP + signed byte offset. \\ +SETSP & \code{0x5050} & \code{r64 ptr} & Устанавливает SP из валидного STACK PTR64. \\ +\bottomrule +\end{longtable} diff --git a/doc/src/libmcpu-psw-table.tex b/doc/src/libmcpu-psw-table.tex new file mode 100644 index 0000000..579e2d2 --- /dev/null +++ b/doc/src/libmcpu-psw-table.tex @@ -0,0 +1,31 @@ +\begin{longtable}{@{}L{27mm}L{18mm}L{114mm}@{}} +\toprule +\textbf{Selector} & \textbf{Bit} & \textbf{Смысл для JSET/JCLR и PSW}\\ +\midrule +\endfirsthead +\toprule +\textbf{Selector} & \textbf{Bit} & \textbf{Смысл для JSET/JCLR и PSW}\\ +\midrule +\endhead +AF & 0 & CPU arithmetic auxiliary/carry state; writable by \code{SETF/CLRF}\\ +CF & 1 & CPU carry/borrow flag; writable by \code{SETF/CLRF}\\ +OF & 2 & CPU integer overflow flag; writable by \code{SETF/CLRF}\\ +SF & 3 & CPU sign flag; writable by \code{SETF/CLRF}\\ +PF & 4 & CPU parity/auxiliary result classification flag; writable by \code{SETF/CLRF}\\ +ZF & 5 & CPU zero flag; writable by \code{SETF/CLRF}\\ +RF & 6 & CPU-visible LibMPU arithmetic status flag; writable by \code{SETF/CLRF}\\ +VF & 7 & CPU-visible LibMPU value/validity status flag; writable by \code{SETF/CLRF}\\ +DOMF & 8 & MPU math domain error state; writable by \code{SETF/CLRF}\\ +SNGF & 9 & MPU singularity error state; writable by \code{SETF/CLRF}\\ +OVFF & 10 & MPU floating/math overflow state; writable by \code{SETF/CLRF}\\ +UDFF & 11 & MPU floating/math underflow state; writable by \code{SETF/CLRF}\\ +TLSF & 12 & MPU total-loss-of-significance state; writable by \code{SETF/CLRF}\\ +PLSF & 13 & MPU partial-loss-of-significance state; writable by \code{SETF/CLRF}\\ +INDF & 14 & MPU invalid/indeterminate state; writable by \code{SETF/CLRF}\\ +INXF & 15 & MPU inexact state; writable by \code{SETF/CLRF}\\ +HF & 16 & HALT-related execution state; readable by \code{JSET/JCLR}, not writable by \code{SETF/CLRF}\\ +TF & 17 & trace/trap control state; readable by \code{JSET/JCLR}, not writable by \code{SETF/CLRF}\\ +IF & 18 & interrupt-enable control state; readable by \code{JSET/JCLR}, not writable by \code{SETF/CLRF}\\ +\bottomrule +\end{longtable} +\noindent Поле MODE является многобитным и намеренно не имеет selector для \code{JSET/JCLR}. Архитектурно PSW[7:0] образует CPU flag byte, PSW[15:8] --- MPU flag byte. \code{SETF/CLRF} разрешают запись только selectors 0..15; \code{CLRCPUF} очищает PSW[7:0], \code{CLRMPUF} --- PSW[15:8]. HF/TF/IF/MODE этими инструкциями не изменяются. Точные правила изменения PSW конкретными арифметическими и conversion instructions описаны в основной части руководства. diff --git a/doc/src/libmcpu-rconst-table.tex b/doc/src/libmcpu-rconst-table.tex new file mode 100644 index 0000000..3448a73 --- /dev/null +++ b/doc/src/libmcpu-rconst-table.tex @@ -0,0 +1,72 @@ +\begin{longtable}{@{}L{38mm}L{25mm}L{90mm}@{}} +\toprule +\textbf{Константа} & \textbf{CONST8} & \textbf{Смысл} \\ +\midrule +\endfirsthead +\toprule +\textbf{Константа} & \textbf{CONST8} & \textbf{Смысл} \\ +\midrule +\endhead +ZERO & \code{0x00} & Точный ноль. \\ +HALF & \code{0x01} & $1/2$. \\ +ONE & \code{0x02} & $1$. \\ +TWO & \code{0x03} & $2$. \\ +TEN & \code{0x04} & $10$. \\ +MTEN & \code{0x05} & $-10$. \\ +32 & \code{0x06} & $32$. \\ +PI & \code{0x10} & Число $\pi$. \\ +E & \code{0x11} & Основание натурального логарифма $e$. \\ +1\_LN2 & \code{0x12} & $1/\ln 2$. \\ +LN2 & \code{0x13} & $\ln 2$. \\ +1\_LN10 & \code{0x14} & $1/\ln 10$. \\ +LN10 & \code{0x15} & $\ln 10$. \\ +1\_LG2 & \code{0x16} & $1/\log_{10}2$. \\ +LG2 & \code{0x17} & $\log_{10}2$. \\ +PI\_2 & \code{0x20} & $\pi/2$. \\ +PI\_3 & \code{0x21} & $\pi/3$. \\ +PI\_4 & \code{0x22} & $\pi/4$. \\ +PI\_5 & \code{0x23} & $\pi/5$. \\ +PI\_6 & \code{0x24} & $\pi/6$. \\ +1\_PI & \code{0x25} & $1/\pi$. \\ +2\_PI & \code{0x26} & $2/\pi$. \\ +3\_PI & \code{0x27} & $3/\pi$. \\ +4\_PI & \code{0x28} & $4/\pi$. \\ +5\_PI & \code{0x29} & $5/\pi$. \\ +2PI & \code{0x2a} & $2\pi$. \\ +3PI & \code{0x2b} & $3\pi$. \\ +1\_2PI & \code{0x2c} & $1/(2\pi)$. \\ +1\_3PI & \code{0x2d} & $1/(3\pi)$. \\ +1\_4PI & \code{0x2e} & $1/(4\pi)$. \\ +1\_5PI & \code{0x2f} & $1/(5\pi)$. \\ +1\_6PI & \code{0x30} & $1/(6\pi)$. \\ +3PI\_4 & \code{0x31} & $3\pi/4$. \\ +SQRTPI & \code{0x40} & $\sqrt{\pi}$. \\ +1\_SQRTPI & \code{0x41} & $1/\sqrt{\pi}$. \\ +2\_SQRTPI & \code{0x42} & $2/\sqrt{\pi}$. \\ +SQRT2 & \code{0x43} & $\sqrt{2}$. \\ +1\_SQRT2 & \code{0x44} & $1/\sqrt{2}$. \\ +SQRT3 & \code{0x45} & $\sqrt{3}$. \\ +1\_SQRT3 & \code{0x46} & $1/\sqrt{3}$. \\ +DEGREE & \code{0x47} & Один градус в радианах, $\pi/180$. \\ +1\_DEGREE & \code{0x48} & Число градусов в одном радиане, $180/\pi$. \\ +GOLDENRATIO & \code{0x49} & Золотое сечение $(1+\sqrt{5})/2$. \\ +EULERGAMMA & \code{0x4a} & Постоянная Эйлера--Маскерони $\gamma$. \\ +CATALAN & \code{0x4b} & Постоянная Каталана $G$. \\ +EPSILON & \code{0x50} & LibMPU Real epsilon для выбранной физической ширины результата. \\ +IND & \code{0x51} & Специальное indeterminate-значение LibMPU. \\ +PNAN & \code{0x52} & Положительное NaN-представление LibMPU. \\ +NNAN & \code{0x53} & Отрицательное NaN-представление LibMPU. \\ +PNANMAX & \code{0x54} & Положительное NaN максимального класса LibMPU. \\ +NNANMAX & \code{0x55} & Отрицательное NaN максимального класса LibMPU. \\ +PNANMIN & \code{0x56} & Положительное NaN минимального класса LibMPU. \\ +NNANMIN & \code{0x57} & Отрицательное NaN минимального класса LibMPU. \\ +PINF & \code{0x58} & Положительная бесконечность. \\ +NINF & \code{0x59} & Отрицательная бесконечность. \\ +PREALMIN & \code{0x5a} & Минимальное положительное конечное Real-значение выбранной ширины. \\ +NREALMIN & \code{0x5b} & Минимальное по модулю отрицательное конечное Real-значение выбранной ширины. \\ +PREALMAX & \code{0x5c} & Максимальное положительное конечное Real-значение выбранной ширины. \\ +NREALMAX & \code{0x5d} & Максимальное по модулю отрицательное конечное Real-значение выбранной ширины. \\ +PZERO & \code{0x5e} & Положительный signed zero LibMPU. \\ +NZERO & \code{0x5f} & Отрицательный signed zero LibMPU. \\ +\bottomrule +\end{longtable} |
