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

263 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

В 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. Пример запроса состояния кнопок**
```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)
-----
# Функция `PadChkVsync` в библиотеке PsyQ для PlayStation 1
Функция `PadChkVsync` используется для проверки состояния геймпада (контроллера) с синхронизацией по вертикальному гашению (VSync). Это важная функция для обработки ввода в играх на PS1.
## Основное назначение
`PadChkVsync` выполняет две ключевые задачи:
1. Проверяет состояние подключенных контроллеров
2. Синхронизирует чтение состояния с вертикальной синхронизацией (VSync)
## Синтаксис
```c
int PadChkVsync(void);
```
## Возвращаемое значение
Функция возвращает битовую маску, указывающую на состояние подключения контроллеров:
- Бит 0: Состояние порта 1 (0 - контроллер подключен, 1 - не подключен)
- Бит 1: Состояние порта 2
- Бит 2: Состояние мемори-карты в порту 1
- Бит 3: Состояние мемори-карты в порту 2
## Особенности работы
1. **Синхронизация с VSync** - чтение состояния происходит во время вертикального гашения, что предотвращает "разрывы" изображения
2. **Определение подключенных устройств** - позволяет определить, какие контроллеры/мемори-карты подключены
3. **Работа в паре с другими функциями Pad** - обычно используется вместе с `PadRead()`
## Пример использования
```c
#include <libpad.h>
int main() {
PadInit(0); // Инициализация системы контроллеров
while(1) {
// Проверка состояния подключения
int connected = PadChkVsync();
if (!(connected & 1)) { // Если контроллер в порту 1 подключен
u_long pad = PadRead(0); // Чтение состояния
if (pad & PAD_UP) {
// Обработка нажатия UP
}
// Другие проверки кнопок...
}
VSync(0); // Ожидание следующего VBlank
}
return 0;
}
```
## Типичный сценарий использования
1. В начале кадра вызывается `PadChkVsync()` для проверки подключенных устройств
2. Если контроллер подключен, вызывается `PadRead()` для получения состояния кнопок
3. Состояние кнопок обрабатывается в игровой логике
4. Цикл повторяется после `VSync(0)`
## Важные нюансы
1. Функция не возвращает состояние кнопок - только информацию о подключении
2. Для фактического чтения кнопок нужно использовать `PadRead()`
3. Рекомендуется вызывать эту функцию один раз за кадр
4. В отличие от `PadRead()`, `PadChkVsync` не очищает буфер ввода
Функция `PadChkVsync` особенно полезна в играх, где важно точно определять момент подключения/отключения контроллеров во время gameplay, например, в multiplayer-играх с возможностью "hot-plug" контроллеров.