vault backup: 2025-04-18 23:10:56
This commit is contained in:
34
.obsidian/workspace.json
vendored
34
.obsidian/workspace.json
vendored
@@ -41,12 +41,12 @@
|
|||||||
"state": {
|
"state": {
|
||||||
"type": "markdown",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "PERSONAL PROJECTS/PSX code - modules load and exec.md",
|
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||||
"mode": "source",
|
"mode": "source",
|
||||||
"source": false
|
"source": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
"title": "PSX code - modules load and exec"
|
"title": "PS1 Geometry Transformation Engine"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -207,17 +207,21 @@
|
|||||||
},
|
},
|
||||||
"active": "dd912cc876184c4f",
|
"active": "dd912cc876184c4f",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"PERSONAL PROJECTS/PSX code texture load unpack show and fade.md",
|
"PERSONAL PROJECTS/PS1 DOCS/LZSS C++ Lib.md",
|
||||||
"PERSONAL PROJECTS/PSX code - modules load and exec.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||||
"PERSONAL PROJECTS/PS1 Gamepad.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
|
||||||
"PERSONAL PROJECTS/PSX code - Load texture from SECTOR!.md",
|
"PERSONAL PROJECTS/PS1 DOCS",
|
||||||
"PERSONAL PROJECTS/PSX code - Texture show from file.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PSX code texture load unpack show and fade.md",
|
||||||
"PERSONAL PROJECTS/PS1 Vblank.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md",
|
||||||
"PERSONAL PROJECTS/PS1 MDEC.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Texture show from file.md",
|
||||||
"PERSONAL PROJECTS/PS1 DMA.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PSX code - modules load and exec.md",
|
||||||
"PERSONAL PROJECTS/PS1 Gpu-DMA.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
||||||
"PERSONAL PROJECTS/PS1 DMA CD-ROM.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PSX code - Load texture from SECTOR!.md",
|
||||||
"PERSONAL PROJECTS/LZSS C++ Lib.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Vblank.md",
|
||||||
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 MDEC.md",
|
||||||
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md",
|
||||||
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 Gpu-DMA.md",
|
||||||
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 DMA CD-ROM.md",
|
||||||
"WORK & PROJECTS/Mol/Ideas/Все идеи для Моли.md",
|
"WORK & PROJECTS/Mol/Ideas/Все идеи для Моли.md",
|
||||||
"WORK & PROJECTS/Mol/Серверы/mail.mol-soft.ru.md",
|
"WORK & PROJECTS/Mol/Серверы/mail.mol-soft.ru.md",
|
||||||
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/СМК/КУ_Чек_лист_10_ошибок_УД_скачивание.pdf",
|
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/СМК/КУ_Чек_лист_10_ошибок_УД_скачивание.pdf",
|
||||||
@@ -239,18 +243,14 @@
|
|||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
||||||
"WORK & PROJECTS/Mol/Серверы/git.moldev.ru.md",
|
"WORK & PROJECTS/Mol/Серверы/git.moldev.ru.md",
|
||||||
"WORK & PROJECTS/Ulab/передача сформированных заявки и протокола как ссылку или файл.md",
|
"WORK & PROJECTS/Ulab/передача сформированных заявки и протокола как ссылку или файл.md",
|
||||||
"WORK & PROJECTS/Ulab/Доступы к точкам.md",
|
|
||||||
"Структура объектов испытаний.png",
|
"Структура объектов испытаний.png",
|
||||||
"Схема связей юрлиц и адресов.png",
|
"Схема связей юрлиц и адресов.png",
|
||||||
"Структура объектов испытаний.png.0.pdnSave",
|
"Структура объектов испытаний.png.0.pdnSave",
|
||||||
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/АФ-01 Альбом форм.pdf",
|
"WORK & PROJECTS/Mol/Документы для ТЗ ЛИМС/АФ-01 Альбом форм.pdf",
|
||||||
"WORK & PROJECTS/Mol/Серверы/Схема инфраструктуры.canvas",
|
"WORK & PROJECTS/Mol/Серверы/Схема инфраструктуры.canvas",
|
||||||
"WORK & PROJECTS/Ulab/Московский проект/ACCESS TABLE.md",
|
|
||||||
"WORK & PROJECTS/Ulab/Автобан/щебень 5-20.xlsx",
|
"WORK & PROJECTS/Ulab/Автобан/щебень 5-20.xlsx",
|
||||||
"WORK & PROJECTS/Ulab/Автобан/щебень 20-40.xlsx",
|
"WORK & PROJECTS/Ulab/Автобан/щебень 20-40.xlsx",
|
||||||
"WORK & PROJECTS/Ulab/Автобан/песок природный.xls",
|
"WORK & PROJECTS/Ulab/Автобан/песок природный.xls",
|
||||||
"WORK & PROJECTS/Ulab/Автобан/грунт песчаный.xlsx",
|
|
||||||
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod_canvas2doc-data/newdoc-node_f3d0e9a6d4d8e6a7_fromCanvas.md",
|
|
||||||
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod.canvas",
|
"WORK & PROJECTS/Mol/Серверы/Alfa cloud prod.canvas",
|
||||||
"PERSONAL PROJECTS/P2EP/cdRead.canvas",
|
"PERSONAL PROJECTS/P2EP/cdRead.canvas",
|
||||||
"P2EP/cdRead.canvas",
|
"P2EP/cdRead.canvas",
|
||||||
|
|||||||
144
PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md
Normal file
144
PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
### **Математический процессор (GTE) в PlayStation 1**
|
||||||
|
|
||||||
|
**Geometry Transformation Engine (GTE)** — это сопроцессор в PS1, отвечающий за ускорение математических операций, критичных для 3D-графики. Он работает параллельно с основным CPU (R3000A) и оптимизирован для:
|
||||||
|
|
||||||
|
1. **Перемножения матриц**
|
||||||
|
2. **Вращения и трансформации вершин**
|
||||||
|
3. **Расчёта перспективы и освещения**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. Основные функции GTE**
|
||||||
|
### **1.1. Быстрые матричные операции**
|
||||||
|
GTE умеет:
|
||||||
|
- Умножать **матрицу 3×3** на вектор (для поворота объектов).
|
||||||
|
- Вычислять **матрицу модели-вида** (Model-View).
|
||||||
|
- Обновлять **нормали объектов** для освещения.
|
||||||
|
|
||||||
|
**Пример**: Поворот вершины:
|
||||||
|
```mips
|
||||||
|
# Вход: матрица вращения в $a0, вершина (x,y,z) в $a1
|
||||||
|
lw $t0, 0($a0) # Загружаем элемент матрицы
|
||||||
|
lw $t1, 0($a1) # Загружаем X вершины
|
||||||
|
mult $t0, $t1 # Умножаем (GTE делает это за 1 такт)
|
||||||
|
mflo $t2 # Результат
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.2. Перспективное преобразование**
|
||||||
|
GTE вычисляет **экранные координаты (X,Y)** из 3D-пространства:
|
||||||
|
1. Учитывает **камеру** (матрица вида).
|
||||||
|
2. Применяет **перспективу** (деление на Z).
|
||||||
|
3. Оптимизирует расчёт **FOV** (поля зрения).
|
||||||
|
|
||||||
|
**Формула**:
|
||||||
|
\[
|
||||||
|
X_{screen} = \frac{X_{3D} \cdot scale}{Z_{3D}} + center\_x
|
||||||
|
\]
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.3. Освещение и цвет**
|
||||||
|
- GTE рассчитывает **интенсивность света** для вершин.
|
||||||
|
- Поддерживает **до 3 источников света** (накладывает цвета).
|
||||||
|
- Работает с **нормалями** (через скалярное произведение).
|
||||||
|
|
||||||
|
**Пример**:
|
||||||
|
```mips
|
||||||
|
# Нормаль в $a0, свет в $a1
|
||||||
|
dp $t0, $a0, $a1 # Скалярное произведение (GTE)
|
||||||
|
sll $t0, 8 # Яркость = 0..255
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. Зачем нужно перемножение матриц?**
|
||||||
|
Матрицы используются для:
|
||||||
|
1. **Поворота объектов**
|
||||||
|
```math
|
||||||
|
\begin{bmatrix}
|
||||||
|
\cosθ & -\sinθ & 0 \\
|
||||||
|
\sinθ & \cosθ & 0 \\
|
||||||
|
0 & 0 & 1 \\
|
||||||
|
\end{bmatrix} \cdot
|
||||||
|
\begin{bmatrix} X \\ Y \\ Z \end{bmatrix}
|
||||||
|
```
|
||||||
|
2. **Масштабирования**
|
||||||
|
```math
|
||||||
|
\begin{bmatrix}
|
||||||
|
S_x & 0 & 0 \\
|
||||||
|
0 & S_y & 0 \\
|
||||||
|
0 & 0 & S_z \\
|
||||||
|
\end{bmatrix}
|
||||||
|
```
|
||||||
|
3. **Смещения (трансляции)**
|
||||||
|
```math
|
||||||
|
\begin{bmatrix} 1 & 0 & T_x \\ 0 & 1 & T_y \\ 0 & 0 & 1 \end{bmatrix}
|
||||||
|
```
|
||||||
|
|
||||||
|
**GTE делает это за 1-2 такта** (вместо 10+ тактов на R3000A).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. Пример: поворот куба на PS1**
|
||||||
|
### **Код на C с ассемблерными вставками**
|
||||||
|
```c
|
||||||
|
#include <libgte.h>
|
||||||
|
|
||||||
|
typedef struct { short x, y, z; } Vertex;
|
||||||
|
|
||||||
|
void rotate_vertex(Vertex *v, int angle) {
|
||||||
|
MATRIX rot_matrix;
|
||||||
|
int sin, cos;
|
||||||
|
|
||||||
|
// Получаем синус/косинус угла (через GTE)
|
||||||
|
gte_ldsin(angle, &sin);
|
||||||
|
gte_ldcos(angle, &cos);
|
||||||
|
|
||||||
|
// Заполняем матрицу поворота вокруг Z
|
||||||
|
rot_matrix.m[0][0] = cos; rot_matrix.m[0][1] = -sin;
|
||||||
|
rot_matrix.m[1][0] = sin; rot_matrix.m[1][1] = cos;
|
||||||
|
|
||||||
|
// Умножаем матрицу на вершину (через GTE)
|
||||||
|
gte_rtps(v->x, v->y, v->z, &rot_matrix, &v->x, &v->y, &v->z);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. Оптимизации через GTE**
|
||||||
|
### **4.1. Пакетная обработка**
|
||||||
|
- GTE может обрабатывать **до 3 вершин за инструкцию** (`rtpt`).
|
||||||
|
- Пример для треугольника:
|
||||||
|
```mips
|
||||||
|
rtpt # Поворот 3 вершин сразу
|
||||||
|
nop
|
||||||
|
```
|
||||||
|
|
||||||
|
### **4.2. Отложенные вычисления**
|
||||||
|
- Команды `nclip` и `avsz3` считают **площадь полигона** и **Z-буфер** без CPU.
|
||||||
|
|
||||||
|
### **4.3. Интеграция с GPU**
|
||||||
|
- Результаты GTE (экранные X,Y,Z) передаются в **GPU** через DMA.
|
||||||
|
- Это ускоряет рендеринг в 5-10 раз.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. Сравнение с современными GPU**
|
||||||
|
| Функция | PS1 (GTE) | Современный GPU |
|
||||||
|
|-----------------------|----------------|----------------|
|
||||||
|
| Матричные операции | 1-2 такта | 1 такт |
|
||||||
|
| Макс. источников света| 3 | 100+ |
|
||||||
|
| Поддержка шейдеров | Нет | Да |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **6. Итог**
|
||||||
|
- **GTE** — это «сердце» 3D-графики PS1, отвечающее за:
|
||||||
|
- Поворот, масштабирование, перспективу.
|
||||||
|
- Освещение и цвет.
|
||||||
|
- **Без GTE** игры вроде *Tekken 3* или *Metal Gear Solid* работали бы на **1-2 FPS**.
|
||||||
|
- Оптимизация под GTE — ключ к плавному рендерингу на PS1.
|
||||||
|
|
||||||
|
Для глубокого изучения смотрите [GTE Technical Reference](http://problemkaputt.de/psx-spx.htm#gtegeometrytransformationengine).
|
||||||
137
PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md
Normal file
137
PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
|
||||||
|
### **Сортировка полигонов на PlayStation 1 (PS1)**
|
||||||
|
|
||||||
|
PS1 не имеет аппаратной поддержки **Z-буфера** (depth buffer), поэтому правильный порядок отрисовки полигонов (сортировка) критически важен для корректного отображения 3D-сцен. Вот как это реализовано:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **1. Основные методы сортировки**
|
||||||
|
### **1.1. Ordering Table (OT)**
|
||||||
|
**Ordering Table** — это главный механизм сортировки на PS1.
|
||||||
|
Работает по принципу **связного списка** в VRAM, где полигоны группируются по расстоянию.
|
||||||
|
|
||||||
|
#### **Как это работает?**
|
||||||
|
1. **Инициализация OT**:
|
||||||
|
- Создаётся массив указателей (например, на 256 или 1024 элемента).
|
||||||
|
- Каждый элемент соответствует диапазону глубин (Z-значений).
|
||||||
|
|
||||||
|
2. **Добавление примитивов**:
|
||||||
|
- Для каждого полигона вычисляется **Z-координата** (например, средняя точка).
|
||||||
|
- По Z-значению выбирается **ячейка OT** (чем дальше объект, тем меньше индекс).
|
||||||
|
- Полигон добавляется в список для этой ячейки.
|
||||||
|
|
||||||
|
3. **Рендеринг**:
|
||||||
|
- OT обрабатывается **от дальних к ближним** ячейкам (от 0 до N).
|
||||||
|
- Все примитивы в одной ячейке рисуются в порядке добавления.
|
||||||
|
|
||||||
|
#### **Пример кода (PsyQ SDK)**
|
||||||
|
```c
|
||||||
|
#include <libgpu.h>
|
||||||
|
|
||||||
|
#define OT_LEN 256 // Размер Ordering Table
|
||||||
|
uint32_t ot[OT_LEN]; // Сама таблица
|
||||||
|
|
||||||
|
void init_ot() {
|
||||||
|
ClearOTagR(ot, OT_LEN); // Очистка OT
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_polygon(POLY_F4 *poly, int z) {
|
||||||
|
// Вычисляем индекс в OT (0 = дальний, OT_LEN-1 = ближний)
|
||||||
|
int ot_entry = (z >> 8) & (OT_LEN - 1); // Простейшее масштабирование Z
|
||||||
|
|
||||||
|
// Добавляем полигон в OT
|
||||||
|
addPrim(ot + ot_entry, poly);
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_frame() {
|
||||||
|
DrawOTag(ot + (OT_LEN - 1)); // Рендеринг OT (от ближних к дальним)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.2. Сортировка по Bounding Box**
|
||||||
|
Для сложных объектов (например, моделей) используется **сортировка по ограничивающему объёму**:
|
||||||
|
1. Вычисляется **сфера или AABB** (коробка), охватывающая объект.
|
||||||
|
2. Сортируются **центры сфер** по Z-координате.
|
||||||
|
|
||||||
|
#### **Псевдокод**
|
||||||
|
```c
|
||||||
|
struct Object {
|
||||||
|
int center_z;
|
||||||
|
POLY_F4 *polys;
|
||||||
|
};
|
||||||
|
|
||||||
|
void sort_objects(Object *objs, int count) {
|
||||||
|
qsort(objs, count, sizeof(Object), compare_by_z);
|
||||||
|
}
|
||||||
|
|
||||||
|
int compare_by_z(const void *a, const void *b) {
|
||||||
|
return ((Object*)a)->center_z - ((Object*)b)->center_z;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1.3. Priority Groups**
|
||||||
|
Некоторые игры (например, *Crash Bandicoot*) используют **приоритетные группы**:
|
||||||
|
- Полигоны делятся на **статические** (уровень) и **динамические** (персонажи).
|
||||||
|
- Статические рисуются через OT, динамические — поверх них.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **2. Оптимизации**
|
||||||
|
### **2.1. Z-Сортировка только для прозрачных объектов**
|
||||||
|
- Непрозрачные полигоны рисуются **без сортировки** (через алгоритм художника).
|
||||||
|
- Прозрачные (с полупрозрачностью) сортируются **строго от дальних к ближним**.
|
||||||
|
|
||||||
|
### **2.2. Двойная OT**
|
||||||
|
- **Одна OT для непрозрачных**, вторая — **для прозрачных** полигонов.
|
||||||
|
- Позволяет уменьшить накладные расходы.
|
||||||
|
|
||||||
|
### **2.3. Субпиксельная корректировка**
|
||||||
|
- Для борьбы с **Z-файтингом** (мерцание полигонов) используется:
|
||||||
|
- Случайное смещение Z (`z += rand() % 4`).
|
||||||
|
- Принудительный порядок для мелких объектов.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **3. Пример для игры**
|
||||||
|
Допустим, у нас есть:
|
||||||
|
- **10 коробок** на разных расстояниях.
|
||||||
|
- **1 полупрозрачный полигон** (вода).
|
||||||
|
|
||||||
|
#### **Код рендеринга**
|
||||||
|
```c
|
||||||
|
// 1. Инициализация
|
||||||
|
init_ot();
|
||||||
|
|
||||||
|
// 2. Добавление непрозрачных полигонов (коробки)
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
add_polygon(&boxes[i], boxes[i].z);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Добавление прозрачного полигона (вода)
|
||||||
|
add_polygon(&water_poly, water_z);
|
||||||
|
|
||||||
|
// 4. Рендеринг
|
||||||
|
render_frame();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **4. Проблемы и решения**
|
||||||
|
| Проблема | Решение |
|
||||||
|
|------------------------|----------------------------------|
|
||||||
|
| **Мерцание полигонов** | Субпиксельная корректировка Z. |
|
||||||
|
| **Низкая производительность** | Уменьшение размера OT. |
|
||||||
|
| **Неправильный порядок** | Ручная настройка приоритетов. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## **5. Итог**
|
||||||
|
- **Ordering Table** — основа сортировки на PS1.
|
||||||
|
- **Для сложных сцен** комбинируют OT, Bounding Box и приоритетные группы.
|
||||||
|
- **Оптимизации** нужны для борьбы с артефактами.
|
||||||
|
|
||||||
|
Этот подход использовался в играх типа *Tekken 3* и *Resident Evil*. Для глубокого понимания изучите [документацию PsyQ](http://psx.arthus.net/sdk/PsyQ/DOCS/).
|
||||||
123
PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md
Normal file
123
PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
Вот готовая программа для **PlayStation 1**, которая использует **MIPS-ассемблерные вставки** для сложения двух чисел через указатели. Результат возвращается в переменную основной программы.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **1. Полный код (MAIN.C)**
|
||||||
|
```c
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <libetc.h>
|
||||||
|
|
||||||
|
// Объявляем ассемблерную функцию
|
||||||
|
int add_numbers_asm(int *a, int *b, int *result);
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
int num1 = 5;
|
||||||
|
int num2 = 7;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
// Вызываем ассемблерную функцию с указателями
|
||||||
|
add_numbers_asm(&num1, &num2, &result);
|
||||||
|
|
||||||
|
// Выводим результат
|
||||||
|
FntPrint("Result: %d + %d = %d\n", num1, num2, result);
|
||||||
|
FntFlush(-1);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
VSync(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Реализация на MIPS-ассемблере
|
||||||
|
int add_numbers_asm(int *a, int *b, int *result) {
|
||||||
|
int ret;
|
||||||
|
asm volatile (
|
||||||
|
"lw $t0, 0(%1) \n" // Загружаем *a в $t0
|
||||||
|
"lw $t1, 0(%2) \n" // Загружаем *b в $t1
|
||||||
|
"add $t2, $t0, $t1 \n" // Складываем: $t2 = $t0 + $t1
|
||||||
|
"sw $t2, 0(%3) \n" // Сохраняем результат по адресу *result
|
||||||
|
"move %0, $t2 \n" // Возвращаем результат через регистр
|
||||||
|
: "=r" (ret) // Выходные операнды
|
||||||
|
: "r" (a), "r" (b), "r" (result) // Входные операнды
|
||||||
|
: "$t0", "$t1", "$t2" // Разрушаемые регистры
|
||||||
|
);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **2. Как это работает?**
|
||||||
|
1. **Передача указателей в ассемблер**
|
||||||
|
Функция `add_numbers_asm` принимает три указателя:
|
||||||
|
- `a` — адрес первого числа,
|
||||||
|
- `b` — адрес второго числа,
|
||||||
|
- `result` — адрес для сохранения результата.
|
||||||
|
|
||||||
|
2. **Ассемблерная вставка** (`asm volatile`):
|
||||||
|
- `lw` — загружает значения из памяти по указателям.
|
||||||
|
- `add` — складывает числа.
|
||||||
|
- `sw` — сохраняет результат по адресу `result`.
|
||||||
|
- `move` — возвращает значение через регистр.
|
||||||
|
|
||||||
|
3. **Доступ к результату**
|
||||||
|
Результат будет:
|
||||||
|
- В переменной `result` (через указатель).
|
||||||
|
- В возвращаемом значении функции (если нужно).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **3. Компиляция и запуск**
|
||||||
|
1. Скомпилируйте через **PsyQ SDK**:
|
||||||
|
```bash
|
||||||
|
ccpsx MAIN.C -o ADD_DEMO.EXE
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Запишите на диск и запустите на эмуляторе или консоли.
|
||||||
|
На экране появится:
|
||||||
|
```
|
||||||
|
Result: 5 + 7 = 12
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **4. Важные нюансы**
|
||||||
|
- **Регистры MIPS**:
|
||||||
|
- `$t0`–`$t9` — временные регистры (можно использовать без сохранения).
|
||||||
|
- `$s0`–`$s7` — должны сохраняться (если используются).
|
||||||
|
|
||||||
|
- **Разрушаемые регистры**:
|
||||||
|
Указаны в конце `asm volatile` (чтобы компилятор не использовал их для оптимизации).
|
||||||
|
|
||||||
|
- **Опасность**:
|
||||||
|
Если передать **неверные указатели**, PS1 уйдёт в **краш** (нет защиты памяти).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **5. Пример с глобальными переменными**
|
||||||
|
Если нужно работать с глобальными переменными напрямую:
|
||||||
|
```c
|
||||||
|
int global_num1 = 10;
|
||||||
|
int global_num2 = 20;
|
||||||
|
|
||||||
|
void add_globals_asm() {
|
||||||
|
asm volatile (
|
||||||
|
"la $t0, global_num1 \n" // Загружаем адрес global_num1
|
||||||
|
"lw $t1, 0($t0) \n" // Читаем значение
|
||||||
|
"la $t0, global_num2 \n"
|
||||||
|
"lw $t2, 0($t0) \n"
|
||||||
|
"add $t1, $t1, $t2 \n"
|
||||||
|
"sw $t1, 0($t0) \n" // Сохраняем сумму в global_num2
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### **6. Итог**
|
||||||
|
- **Ассемблерные вставки** дают полный контроль над железом PS1.
|
||||||
|
- **Указатели** передаются через регистры (`$a0`–`$a3` в MIPS).
|
||||||
|
- **Результат** можно получить через память или возвращаемое значение.
|
||||||
|
|
||||||
|
Этот подход используется в оптимизированных частях игр (например, в рендеринге или физике).
|
||||||
Reference in New Issue
Block a user