summaryrefslogtreecommitdiff
path: root/doc/src/libmcpu-architecture-runtime-ru.tex
blob: 2ecf4cb50dc32d6d3fe224f9e044396a022ff9a9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
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.