В PlayStation 1 (PS1) взаимодействие с контроллерами (геймпадами, мышками, световыми пистолетами и т.д.) осуществляется через **порты ввода-вывода (I/O)** и специализированные **контроллеры SIO (Serial Input/Output)**. Вот детальное объяснение процесса: --- ## **1. Аппаратная основа** ### **1.1. Порты контроллеров** - PS1 имеет **два порта** для подключения устройств (Multitap позволяет расширить до 4–8 игроков). - Каждый порт использует **протокол 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. Пример запроса состояния кнопок** ```asm ; 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. **Инициализация порта**: ```c InitPad(1, 0, NULL, 0); // Порт 1, без буфера ``` 2. **Чтение состояния**: ```c struct PadButtonStatus pad; ReadPadStatus(&pad, 0); // Чтение порта 1 ``` 3. **Проверка кнопок**: ```c if (pad.buttons & PAD_CROSS) { // Кнопка CROSS нажата } ``` --- ## **5. Прерывания и синхронизация** - **Прерывание IRQ7** используется для обработки ввода. - Игры часто опрашивают контроллеры **во время VBlank**, чтобы избежать задержек. --- ## **6. Псевдокод полного цикла** ```c 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. **Ручное управление буфером** - позволяет программисту самому решать, когда очищать буфер ввода ## Синтаксис ```c void ChangeClearPad(int mode); ``` где `mode` может принимать значения: - `0` - ручной режим (очистка буфера только при вызове `ClearPad()`) - `1` - автоматический режим (очистка при каждом VSync) ## Практическое использование ```c #include int main() { // Инициализация контроллера PadInit(0); // Переключение в ручной режим очистки буфера ChangeClearPad(0); while(1) { // Чтение состояния контроллера PadRead(0); // В ручном режиме нужно самостоятельно очищать буфер if(need_to_clear) { ClearPad(0); } // Автоматическая очистка происходить не будет } } ``` ## Типичные сценарии использования 1. **Фиксация коротких нажатий**: ```c 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.