Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md
2025-04-19 00:31:03 +05:00

8.4 KiB
Raw Blame History

В PlayStation 1 (PS1) взаимодействие с контроллерами (геймпадами, мышками, световыми пистолетами и т.д.) осуществляется через порты ввода-вывода (I/O) и специализированные контроллеры SIO (Serial Input/Output). Вот детальное объяснение процесса:


1. Аппаратная основа

1.1. Порты контроллеров

  • PS1 имеет два порта для подключения устройств (Multitap позволяет расширить до 48 игроков).
  • Каждый порт использует протокол SPI (Serial Peripheral Interface) для обмена данными.

1.2. Регистры управления

Основные регистры для работы с контроллерами:

Адрес Назначение
0x1F801040 SIO_DATA — Данные для отправки/приёма.
0x1F801044 SIO_STAT — Статус операции (готовность, ошибки).
0x1F801048 SIO_MODE — Настройка режима (скорость, прерывания).
0x1F801050 SIO_CTRL — Управление передачей (старт/стоп).

2. Протокол обмена данными

2.1. Формат команд

Контроллеры PS1 понимают 5-байтовые команды:

  1. Стартовый байт (0x01) — начало передачи.
  2. Команда (например, 0x42 — запрос состояния кнопок).
  3. Данные (зависит от типа устройства).

2.2. Пример запроса состояния кнопок

; 1. Запись команды в SIO_DATA
li t0, 0x1F801040
li t1, 0x01000042  // Старт (0x01) + команда (0x42)
sw t1, 0(t0)

; 2. Ожидание готовности
wait_ready:
  lw t2, 0x1F801044(SIO_STAT)
  andi t2, t2, 0x0002  // Проверка бита "Готов к передаче"
  beqz t2, wait_ready

; 3. Чтение ответа (5 байт)
lw t3, 0x1F801040(SIO_DATA)  // Первые 4 байта
lw t4, 0x1F801040(SIO_DATA)  // Последний байт

3. Типы контроллеров и их ответы

3.1. Стандартный геймпад (Digital Pad)

  • Команда: 0x42.
  • Ответ: 5 байт:
    [0x41][0x5A][Кнопки 1][Кнопки 2][Аналоговые данные (если есть)]
    
  • Распаковка кнопок:
    • Байт 3: SELECT, L3, R3, START, UP, RIGHT, DOWN, LEFT.
    • Байт 4: L2, R2, L1, R1, TRIANGLE, CIRCLE, CROSS, SQUARE.

3.2. Аналоговый джойстик (DualShock)

  • Поддерживает вибрацию и аналоговые стики.
  • Команды:
    • 0x43 — запрос аналоговых данных.
    • 0x4D — управление моторчиками.

4. Как игры обрабатывают ввод?

  1. Инициализация порта:
    InitPad(1, 0, NULL, 0);  // Порт 1, без буфера
    
  2. Чтение состояния:
    struct PadButtonStatus pad;
    ReadPadStatus(&pad, 0);  // Чтение порта 1
    
  3. Проверка кнопок:
    if (pad.buttons & PAD_CROSS) {
        // Кнопка CROSS нажата
    }
    

5. Прерывания и синхронизация

  • Прерывание IRQ7 используется для обработки ввода.
  • Игры часто опрашивают контроллеры во время VBlank, чтобы избежать задержек.

6. Псевдокод полного цикла

while (1) {
    VSync(0);  // Синхронизация с кадром
    PollPad(); // Опрос контроллера
    
    if (PAD_PRESSED(PAD_UP)) {
        player_y--;
    }
}

7. Интересные нюансы

  • Light Gun (GunCon) требует строгой синхронизации с лучом ЭЛТ.
  • Multitap усложняет протокол (нужно переключать устройства).

Функция ChangeClearPad в библиотеке PsyQ для PlayStation 1

Функция ChangeClearPad относится к работе с контроллерами (геймпадами) PlayStation и используется для управления поведением буфера ввода.

Назначение функции

ChangeClearPad изменяет режим очистки буфера данных контроллера. Она определяет, как система будет обрабатывать ввод с геймпада между кадрами:

  1. Автоматическая очистка буфера (по умолчанию) - система автоматически очищает данные о предыдущем состоянии кнопок
  2. Ручное управление буфером - позволяет программисту самому решать, когда очищать буфер ввода

Синтаксис

void ChangeClearPad(int mode);

где mode может принимать значения:

  • 0 - ручной режим (очистка буфера только при вызове ClearPad())
  • 1 - автоматический режим (очистка при каждом VSync)

Практическое использование

#include <libpad.h>

int main() {
    // Инициализация контроллера
    PadInit(0);
    
    // Переключение в ручной режим очистки буфера
    ChangeClearPad(0);
    
    while(1) {
        // Чтение состояния контроллера
        PadRead(0);
        
        // В ручном режиме нужно самостоятельно очищать буфер
        if(need_to_clear) {
            ClearPad(0);
        }
        
        // Автоматическая очистка происходить не будет
    }
}

Типичные сценарии использования

  1. Фиксация коротких нажатий:

    ChangeClearPad(0); // Ручной режим
    if(PadRead(0) {
        if((pad_status & PAD_CROSS) && !(old_pad_status & PAD_CROSS)) {
            // Обнаружено нажатие Cross
        }
        old_pad_status = pad_status;
        ClearPad(0); // Очищаем буфер вручную
    }
    
  2. Комбинации кнопок - когда нужно отслеживать состояние нескольких кнопок одновременно

  3. Специальные игровые механики - где важно точное время нажатия/отпускания кнопок

Важные нюансы

  1. По умолчанию в PsyQ используется автоматический режим (ChangeClearPad(1))

  2. В ручном режиме вы должны самостоятельно вызывать ClearPad() для очистки буфера

  3. Функция влияет на работу PadRead() - в автоматическом режиме она сама очищает предыдущее состояние

  4. Для большинства игр достаточно стандартного автоматического режима

  5. Функция работает с обоими портами контроллера (0 и 1)

Совместимость

ChangeClearPad является частью библиотеки libpad.h в PsyQ SDK и доступна во всех версиях. Аналогичная функциональность присутствует и в официальном Sony SDK для PS1.