Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md
2025-04-19 00:11:01 +05:00

14 KiB
Raw Blame History

Прерывания (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 (иначе артефакты).

Пример кода:

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 позволяет:

  • Читать данные с диска без блокировки основного цикла игры.
  • Загружать уровни/аудио в фоне.

Пример:

cd_read_done:
    # IRQ2 вызвано — данные готовы
    la $t0, cd_buffer
    sw $t0, 0x1F8010A0  # DMA CD-ROM
    jr $ra

(3) Обработка ввода (геймпады)

Прерывание IRQ5 сообщает:

  • Когда игрок нажал кнопку (без задержек).
  • Поддерживает вибрацию (если есть DualShock).

Пример:

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. Обработчик:
    • Сохраняет регистры в стек.
    • Выполняет нужные действия (например, обновляет графику).
    • Очищает флаг прерывания.
    • Восстанавливает регистры и возвращает управление.

Пример обработчика на ассемблере:

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)
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. Обработка прерывания

Типичный обработчик:

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!


Команда SetIntrMask в PS1 (PlayStation 1)

SetIntrMask — это низкоуровневая функция в SDK PlayStation 1 (как в официальном Sony SDK, так и в PsyQ), которая управляет маской прерываний процессора R3000.

Основное назначение

Функция SetIntrMask устанавливает битовую маску, определяющую, какие прерывания будут обрабатываться процессором. Она позволяет включать/выключать определенные типы прерываний.

Синтаксис (в PsyQ)

void SetIntrMask(unsigned int mask);

Битовая маска прерываний

Маска прерываний обычно определяется следующими флагами (конкретные значения могут отличаться в разных версиях SDK):

0x0001 - VBLANK (вертикальное гашение)
0x0002 - GPU
0x0004 - CD-ROM
0x0008 - DMA
0x0010 - TIMER0 (таймер 0)
0x0020 - TIMER1 (таймер 1)
0x0040 - TIMER2 (таймер 2)
0x0080 - Периферийные устройства (контроллеры, память карт)
0x0400 - SPU (звуковой процессор)

Примеры использования

  1. Разрешить все прерывания:

    SetIntrMask(0xFFFF);
    
  2. Разрешить только VBLANK и CD-ROM:

    SetIntrMask(0x0005); // 0x0001 (VBLANK) | 0x0004 (CD-ROM)
    
  3. Запретить все прерывания:

    SetIntrMask(0x0000);
    

Типичное использование в сочетании с другими функциями

// Сохраняем текущую маску
unsigned int old_mask = GetIntrMask();

// Запрещаем все прерывания
SetIntrMask(0x0000);

// Выполняем критический код, который не должен прерываться

// Восстанавливаем предыдущую маску
SetIntrMask(old_mask);

Важные замечания

  1. Альтернативы: В PsyQ часто используют EnterCriticalSection() и ExitCriticalSection(), которые internally работают с SetIntrMask.

  2. Влияние на производительность: Неправильное управление маской прерываний может привести к пропуску важных событий (например, VBLANK).

  3. GPU синхронизация: При работе с GPU часто требуется временно отключать прерывания для атомарных операций.

  4. Сочетание с обработчиками: Даже если прерывание разрешено маской, для него должен быть установлен обработчик через соответствующие функции PsyQ.

Эта функция предоставляет низкоуровневый контроль над прерываниями и обычно используется в сочетании с более высокоуровневыми API PsyQ для управления конкретными типами прерываний.