Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PSX code inline asm.md
2025-04-18 23:10:56 +05:00

123 lines
4.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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