15 KiB
В 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-байтовые команды:
- Стартовый байт (
0x01) — начало передачи. - Команда (например,
0x42— запрос состояния кнопок). - Данные (зависит от типа устройства).
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:
3.2. Аналоговый джойстик (DualShock)
- Поддерживает вибрацию и аналоговые стики.
- Команды:
0x43— запрос аналоговых данных.0x4D— управление моторчиками.
4. Как игры обрабатывают ввод?
- Инициализация порта:
InitPad(1, 0, NULL, 0); // Порт 1, без буфера - Чтение состояния:
struct PadButtonStatus pad; ReadPadStatus(&pad, 0); // Чтение порта 1 - Проверка кнопок:
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 изменяет режим очистки буфера данных контроллера. Она определяет, как система будет обрабатывать ввод с геймпада между кадрами:
- Автоматическая очистка буфера (по умолчанию) - система автоматически очищает данные о предыдущем состоянии кнопок
- Ручное управление буфером - позволяет программисту самому решать, когда очищать буфер ввода
Синтаксис
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);
}
// Автоматическая очистка происходить не будет
}
}
Типичные сценарии использования
-
Фиксация коротких нажатий:
ChangeClearPad(0); // Ручной режим if(PadRead(0) { if((pad_status & PAD_CROSS) && !(old_pad_status & PAD_CROSS)) { // Обнаружено нажатие Cross } old_pad_status = pad_status; ClearPad(0); // Очищаем буфер вручную } -
Комбинации кнопок - когда нужно отслеживать состояние нескольких кнопок одновременно
-
Специальные игровые механики - где важно точное время нажатия/отпускания кнопок
Важные нюансы
-
По умолчанию в PsyQ используется автоматический режим (
ChangeClearPad(1)) -
В ручном режиме вы должны самостоятельно вызывать
ClearPad()для очистки буфера -
Функция влияет на работу
PadRead()- в автоматическом режиме она сама очищает предыдущее состояние -
Для большинства игр достаточно стандартного автоматического режима
-
Функция работает с обоими портами контроллера (0 и 1)
Функция PadChkVsync в библиотеке PsyQ для PlayStation 1
Функция PadChkVsync используется для проверки состояния геймпада (контроллера) с синхронизацией по вертикальному гашению (VSync). Это важная функция для обработки ввода в играх на PS1.
Основное назначение
PadChkVsync выполняет две ключевые задачи:
- Проверяет состояние подключенных контроллеров
- Синхронизирует чтение состояния с вертикальной синхронизацией (VSync)
Синтаксис
int PadChkVsync(void);
Возвращаемое значение
Функция возвращает битовую маску, указывающую на состояние подключения контроллеров:
- Бит 0: Состояние порта 1 (0 - контроллер подключен, 1 - не подключен)
- Бит 1: Состояние порта 2
- Бит 2: Состояние мемори-карты в порту 1
- Бит 3: Состояние мемори-карты в порту 2
Особенности работы
- Синхронизация с VSync - чтение состояния происходит во время вертикального гашения, что предотвращает "разрывы" изображения
- Определение подключенных устройств - позволяет определить, какие контроллеры/мемори-карты подключены
- Работа в паре с другими функциями Pad - обычно используется вместе с
PadRead()
Пример использования
#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;
}
Типичный сценарий использования
- В начале кадра вызывается
PadChkVsync()для проверки подключенных устройств - Если контроллер подключен, вызывается
PadRead()для получения состояния кнопок - Состояние кнопок обрабатывается в игровой логике
- Цикл повторяется после
VSync(0)
Важные нюансы
- Функция не возвращает состояние кнопок - только информацию о подключении
- Для фактического чтения кнопок нужно использовать
PadRead() - Рекомендуется вызывать эту функцию один раз за кадр
- В отличие от
PadRead(),PadChkVsyncне очищает буфер ввода
Функция PadChkVsync особенно полезна в играх, где важно точно определять момент подключения/отключения контроллеров во время gameplay, например, в multiplayer-играх с возможностью "hot-plug" контроллеров.
Да, функция PadInitDirect действительно существует в библиотеке PsyQ и является важной частью системы обработки ввода для PlayStation 1. Вот подробное объяснение:
🔍 Назначение PadInitDirect
Функция инициализирует систему обработки геймпадов в режиме прямого доступа (Direct Access). Она:
- Настраивает аппаратные порты контроллеров (до 2-х геймпадов)
- Подготавливает буферы для чтения состояния кнопок
- Активирует низкоуровневый доступ к данным геймпадов
- Возвращает статус инициализации (
1= успех,0= ошибка)
📜 Синтаксис в PsyQ
#include <libpad.h>
int PadInitDirect(unsigned char *padBuf1, unsigned char *padBuf2);
padBuf1- буфер для геймпада на порту 1 (размер ≥ 34 байт)padBuf2- буфер для геймпада на порту 2 (может бытьNULL)
💻 Пример использования
#define BUF_SIZE 34
int main() {
unsigned char pad1Buf[BUF_SIZE] __attribute__((aligned(64))); // Выравнивание для DMA
if(PadInitDirect(pad1Buf, NULL)) {
printf("Геймпад 1 инициализирован!\n");
} else {
printf("Ошибка инициализации!\n");
return 1;
}
// Далее можно использовать PadRead()
}
🔧 Особенности работы
-
Требования к буферам:
- Минимальный размер: 34 байта
- Должны быть 64-байтно выровнены (для DMA)
- Пример объявления:
unsigned char padBuf[34] __attribute__((aligned(64)));
-
Режимы работы:
- Прямой доступ (
PadInitDirect) - ручное управление - Стандартный режим (
PadInit) - автоматическое управление
- Прямой доступ (
-
Совместимость:
- Поддерживает все типы контроллеров PS1:
- Обычные геймпады (Digital)
- Аналоговые джойстики (DualShock)
- Мышь PlayStation
- Поддерживает все типы контроллеров PS1:
⚠️ Важные нюансы
- Перед использованием необходимо вызвать
PadStartCom()для начала обмена данными - Для чтения используется
PadRead()после инициализации - В мультиплеерных играх нужно инициализировать оба порта:
PadInitDirect(pad1Buf, pad2Buf);
📚 Документация PsyQ
В официальном PsyQ SDK функция описана в файлах:
libpad.h- заголовочный файлlibpad.doc- документация- Примеры в
Samples/PADдемонстрируют использование