vault backup: 2025-04-18 23:50:59
This commit is contained in:
10
.obsidian/workspace.json
vendored
10
.obsidian/workspace.json
vendored
@@ -41,12 +41,12 @@
|
||||
"state": {
|
||||
"type": "markdown",
|
||||
"state": {
|
||||
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||
"file": "PERSONAL PROJECTS/PS1 DOCS/Untitled.md",
|
||||
"mode": "source",
|
||||
"source": false
|
||||
},
|
||||
"icon": "lucide-file",
|
||||
"title": "PS1 Geometry Transformation Engine"
|
||||
"title": "Untitled"
|
||||
}
|
||||
}
|
||||
],
|
||||
@@ -207,8 +207,10 @@
|
||||
},
|
||||
"active": "dd912cc876184c4f",
|
||||
"lastOpenFiles": [
|
||||
"PERSONAL PROJECTS/PS1 DOCS/LZSS C++ Lib.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/Untitled.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Geometry Transformation Engine.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/LZSS C++ Lib.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 Ordering table.md",
|
||||
"PERSONAL PROJECTS/PS1 DOCS",
|
||||
"PERSONAL PROJECTS/PS1 DOCS/PSX code texture load unpack show and fade.md",
|
||||
@@ -241,8 +243,6 @@
|
||||
"WORK & PROJECTS/Mol/Планы и диаграммы/СМК.md",
|
||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud readme.md",
|
||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
||||
"WORK & PROJECTS/Mol/Серверы/git.moldev.ru.md",
|
||||
"WORK & PROJECTS/Ulab/передача сформированных заявки и протокола как ссылку или файл.md",
|
||||
"Структура объектов испытаний.png",
|
||||
"Схема связей юрлиц и адресов.png",
|
||||
"Структура объектов испытаний.png.0.pdnSave",
|
||||
|
||||
221
PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md
Normal file
221
PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md
Normal file
@@ -0,0 +1,221 @@
|
||||
### **Прерывания (Interrupts) на PlayStation 1: Зачем они нужны и как работают?**
|
||||
Прерывания в PS1 — это механизм, позволяющий процессору **мгновенно реагировать** на критичные события (например, завершение рендеринга кадра или чтение с диска), не требуя постоянного опроса (polling). Они играют ключевую роль в синхронизации и эффективности системы.
|
||||
|
||||
---
|
||||
|
||||
## **1. Основные типы прерываний**
|
||||
В PS1 есть несколько аппаратных прерываний, каждое обслуживает свою задачу:
|
||||
|
||||
| Прерывание | Источник | Задача |
|
||||
|------------|---------------------------|-----------------------------------------------------------------------|
|
||||
| **IRQ0** | VBlank (вертикальная синхронизация) | Оповещает о завершении рендеринга кадра. Используется для обновления графики. |
|
||||
| **IRQ1** | GPU | Генерируется при ошибках GPU (например, переполнение буфера команд). |
|
||||
| **IRQ2** | CD-ROM | Сигнализирует о завершении чтения данных с диска. |
|
||||
| **IRQ3** | DMA | Уведомляет о завершении передачи данных (например, в VRAM). |
|
||||
| **IRQ4** | Timer (таймер) | Используется для точного измерения времени. |
|
||||
| **IRQ5** | Контроллеры (геймпады) | Обработка ввода игрока. |
|
||||
| **IRQ6** | SPU (звук) | Прерывание от звукового процессора (например, окончание воспроизведения сэмпла). |
|
||||
|
||||
---
|
||||
|
||||
## **2. Зачем они нужны?**
|
||||
### **(1) Синхронизация графики (VBlank)**
|
||||
Без прерывания **IRQ0** (VBlank) игра не могла бы:
|
||||
- Плавно обновлять кадры (без разрывов изображения).
|
||||
- Безопасно изменять VRAM (иначе артефакты).
|
||||
|
||||
**Пример кода:**
|
||||
```mips
|
||||
wait_vblank:
|
||||
li $t0, 0x1F801070 # I_STAT (регистр статуса прерываний)
|
||||
lw $t1, 0($t0)
|
||||
andi $t1, 0x1 # Проверяем бит IRQ0 (VBlank)
|
||||
beqz $t1, wait_vblank
|
||||
nop
|
||||
jr $ra
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **(2) Асинхронная работа с CD-ROM**
|
||||
Прерывание **IRQ2** позволяет:
|
||||
- Читать данные с диска **без блокировки основного цикла игры**.
|
||||
- Загружать уровни/аудио **в фоне**.
|
||||
|
||||
**Пример:**
|
||||
```mips
|
||||
cd_read_done:
|
||||
# IRQ2 вызвано — данные готовы
|
||||
la $t0, cd_buffer
|
||||
sw $t0, 0x1F8010A0 # DMA CD-ROM
|
||||
jr $ra
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### **(3) Обработка ввода (геймпады)**
|
||||
Прерывание **IRQ5** сообщает:
|
||||
- Когда игрок нажал кнопку (без задержек).
|
||||
- Поддерживает **вибрацию** (если есть DualShock).
|
||||
|
||||
**Пример:**
|
||||
```mips
|
||||
read_pad:
|
||||
li $t0, 0x1F801040 # SIO_DATA
|
||||
lw $t1, 0($t0) # Чтение кнопок
|
||||
andi $t1, 0xFF // Фильтруем биты
|
||||
jr $ra
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **3. Как работают прерывания?**
|
||||
1. **Аппаратное событие** (например, завершение VBlank) устанавливает флаг в **I_STAT (0x1F801070)**.
|
||||
2. Процессор **приостанавливает текущий код** и переходит к **обработчику прерывания** (адрес задаётся в **$k0**).
|
||||
3. Обработчик:
|
||||
- Сохраняет регистры в стек.
|
||||
- Выполняет нужные действия (например, обновляет графику).
|
||||
- Очищает флаг прерывания.
|
||||
- Восстанавливает регистры и возвращает управление.
|
||||
|
||||
**Пример обработчика на ассемблере:**
|
||||
```mips
|
||||
irq_handler:
|
||||
addiu $sp, -32 # Резервируем стек
|
||||
sw $ra, 0($sp) # Сохраняем $ra
|
||||
sw $a0, 4($sp) # Сохраняем аргументы
|
||||
|
||||
# Проверяем источник прерывания
|
||||
li $t0, 0x1F801070
|
||||
lw $t1, 0($t0)
|
||||
andi $t2, $t1, 0x1 # IRQ0 (VBlank)?
|
||||
bnez $t2, handle_vblank
|
||||
nop
|
||||
|
||||
# Выход
|
||||
lw $a0, 4($sp)
|
||||
lw $ra, 0($sp)
|
||||
addiu $sp, 32
|
||||
eret # Возврат из прерывания
|
||||
|
||||
handle_vblank:
|
||||
# Обновляем кадр
|
||||
jal update_graphics
|
||||
nop
|
||||
j irq_handler # Возврат
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **4. Почему без прерываний — плохо?**
|
||||
- **Графика**: Без VBlank появится **tearing** (разрывы кадров).
|
||||
- **Звук**: SPU будет работать с задержками.
|
||||
- **Ввод**: Кнопки станут «лагающими».
|
||||
- **CD-ROM**: Игра зависнет на время загрузки.
|
||||
|
||||
---
|
||||
|
||||
## **5. Итог**
|
||||
Прерывания в PS1 — это **«нервная система» консоли**, которая:
|
||||
1. **Синхронизирует** графику, звук, ввод и загрузку данных.
|
||||
2. **Избегает busy-waiting** (постоянного опроса), экономя ресурсы CPU.
|
||||
3. **Гарантирует точность** (например, 60 FPS через VBlank).
|
||||
|
||||
Если ты **пишешь на ассемблере**, прерывания придётся обрабатывать вручную. В **C** этим частично занимается PsyQ SDK.
|
||||
|
||||
P.S. В твоём переводе Persona 2 прерывания **уже работают** — иначе игра бы просто не запустилась! 😉 Но если хочешь **добавить свои обработчики** (например, для кастомной загрузки), дай знать — помогу с кодом.
|
||||
|
||||
------------------
|
||||
|
||||
### **Как работают прерывания на PlayStation 1: детальный разбор**
|
||||
|
||||
Прерывания (IRQ) в PS1 — это механизм, позволяющий процессору R3000A мгновенно реагировать на аппаратные события. Вот их полный цикл работы:
|
||||
|
||||
#### **1. Инициализация прерываний**
|
||||
Перед использованием нужно:
|
||||
- Задать адрес обработчика в **$k0** (регистр ядра)
|
||||
- Разрешить нужные IRQ в регистре **I_MASK (0x1F801074)**
|
||||
|
||||
```mips
|
||||
setup_irq:
|
||||
la $k0, irq_handler # Устанавливаем обработчик
|
||||
li $t0, 0x1F801074
|
||||
li $t1, 0x0001 # Разрешаем только IRQ0 (VBlank)
|
||||
sw $t1, 0($t0)
|
||||
jr $ra
|
||||
```
|
||||
|
||||
#### **2. Аппаратный триггер**
|
||||
Когда происходит событие (например, VBlank):
|
||||
1. CD-ROM контроллер/GPU устанавливает бит в **I_STAT (0x1F801070)**
|
||||
2. Процессор проверяет:
|
||||
- Разрешено ли это прерывание в **I_MASK**
|
||||
- Не находится ли он уже в обработчике (бит **IEc** в регистре **SR**)
|
||||
|
||||
#### **3. Переход в обработчик**
|
||||
Если условия выполнены:
|
||||
1. Процессор:
|
||||
- Сохраняет **PC** и **SR** в специальных регистрах (**EPC**, **ErrorEPC**)
|
||||
- Переходит в режим ядра (бит **KUc** = 0)
|
||||
- Прыгает по адресу в **$k0**
|
||||
|
||||
#### **4. Обработка прерывания**
|
||||
Типичный обработчик:
|
||||
```mips
|
||||
irq_handler:
|
||||
# 1. Сохраняем контекст
|
||||
addiu $sp, -120 # Резервируем место для 30 регистров
|
||||
sw $at, 0($sp)
|
||||
sw $v0, 4($sp)
|
||||
# ... сохраняем все используемые регистры
|
||||
|
||||
# 2. Определяем источник
|
||||
li $t0, 0x1F801070
|
||||
lw $t1, 0($t0) # Читаем I_STAT
|
||||
|
||||
# 3. Обработка VBlank
|
||||
andi $t2, $t1, 0x1
|
||||
beqz $t2, not_vblank
|
||||
nop
|
||||
jal handle_vblank
|
||||
nop
|
||||
|
||||
not_vblank:
|
||||
# 4. Сбрасываем флаг прерывания
|
||||
li $t3, 0xFFFF00FF # Маска для очистки
|
||||
and $t1, $t1, $t3
|
||||
sw $t1, 0($t0) # Пишем обратно в I_STAT
|
||||
|
||||
# 5. Восстанавливаем контекст
|
||||
lw $at, 0($sp)
|
||||
lw $v0, 4($sp)
|
||||
# ...
|
||||
addiu $sp, 120
|
||||
|
||||
# 6. Возврат
|
||||
eret # Возврат с восстановлением SR и PC
|
||||
```
|
||||
|
||||
#### **5. Возврат из прерывания**
|
||||
Инструкция **eret**:
|
||||
- Восстанавливает **PC** из **EPC**
|
||||
- Восстанавливает **SR** (включая бит **IEc**)
|
||||
- Возвращает процессор в пользовательский режим
|
||||
|
||||
#### **6. Особенности PS1**
|
||||
1. **Приоритеты**: Нет аппаратного приоритета - порядок обработки определяется программно
|
||||
2. **Вложенность**: Новые прерывания блокируются, пока **IEc = 0**
|
||||
3. **Задержки**: Минимальная задержка между прерываниями - 5 тактов
|
||||
|
||||
#### **7. Реальный пример из PsyQ**
|
||||
Обработчик VBlank в библиотеке **libgs**:
|
||||
1. Сохраняет матрицу преобразования
|
||||
2. Обновляет буферы GPU
|
||||
3. Вызывает пользовательский callback
|
||||
|
||||
#### **8. Оптимизации**
|
||||
- **Короткие обработчики**: Не более 100 тактов
|
||||
- **Минимальное сохранение**: Только используемые регистры
|
||||
- **Аппаратное ускорение**: Для DMA используйте **D_ICR (0x1F8010F4)**
|
||||
|
||||
Для отладки в no$psx используйте точки останова на записи в **I_STAT**!
|
||||
0
PERSONAL PROJECTS/PS1 DOCS/Untitled.md
Normal file
0
PERSONAL PROJECTS/PS1 DOCS/Untitled.md
Normal file
Reference in New Issue
Block a user