191 lines
8.4 KiB
Markdown
191 lines
8.4 KiB
Markdown
В 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 <libpad.h>
|
||
|
||
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. |