vault backup: 2025-04-18 23:10:56

This commit is contained in:
sShemet
2025-04-18 23:10:56 +05:00
parent 8f4ceebaf3
commit 491d7fc92a
15 changed files with 421 additions and 17 deletions

View 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).
- **Результат** можно получить через память или возвращаемое значение.
Этот подход используется в оптимизированных частях игр (например, в рендеринге или физике).