vault backup: 2025-04-20 00:25:47
This commit is contained in:
8
.obsidian/workspace.json
vendored
8
.obsidian/workspace.json
vendored
@@ -41,12 +41,12 @@
|
|||||||
"state": {
|
"state": {
|
||||||
"type": "markdown",
|
"type": "markdown",
|
||||||
"state": {
|
"state": {
|
||||||
"file": "PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md",
|
"file": "PERSONAL PROJECTS/PS1 DOCS/PS1 Gamepad.md",
|
||||||
"mode": "source",
|
"mode": "source",
|
||||||
"source": false
|
"source": false
|
||||||
},
|
},
|
||||||
"icon": "lucide-file",
|
"icon": "lucide-file",
|
||||||
"title": "FUN_80015674 Update Entity Stats"
|
"title": "PS1 Gamepad"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -207,8 +207,9 @@
|
|||||||
},
|
},
|
||||||
"active": "dd912cc876184c4f",
|
"active": "dd912cc876184c4f",
|
||||||
"lastOpenFiles": [
|
"lastOpenFiles": [
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_800453e0 SystemEventManager.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80015674 Update Entity Stats.md",
|
||||||
|
"PERSONAL PROJECTS/P2EP/pseudoCode/MakeSmallChar.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80012df4 RenderInterface.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80012df4 RenderInterface.md",
|
||||||
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80011f2c InitInterfaceManager.md",
|
"PERSONAL PROJECTS/P2EP/pseudoCode/FUN_80011f2c InitInterfaceManager.md",
|
||||||
"PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md",
|
"PERSONAL PROJECTS/PS1 DOCS/PS1 IRQ.md",
|
||||||
@@ -242,7 +243,6 @@
|
|||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Архитектура редактора и генератора (Alfa + Mol).canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Редактор_форм/Архитектура редактора и генератора (Alfa + Mol).canvas",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud prod.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud/Alfa cloud prod.canvas",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Быстрый старт/Быстрый старт.canvas",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/00001_Быстрый старт/Быстрый старт.canvas",
|
||||||
"My/Diet 1.md",
|
|
||||||
"My",
|
"My",
|
||||||
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
"WORK & PROJECTS/Mol/Планы и диаграммы/Alfa Cloud",
|
||||||
"Структура объектов испытаний.png",
|
"Структура объектов испытаний.png",
|
||||||
|
|||||||
@@ -0,0 +1,193 @@
|
|||||||
|
Эта функция является **критически важным системным обработчиком ввода/вывода или управления состоянием** в игре для PS1. Вот детальный разбор:
|
||||||
|
|
||||||
|
### 🔍 Основное назначение
|
||||||
|
Функция управляет:
|
||||||
|
1. **Очередью аппаратных событий** (контроллеры, таймеры, DMA)
|
||||||
|
2. **Синхронизацией игрового состояния** между различными подсистемами
|
||||||
|
3. **Обработкой ошибок** и аварийных сценариев
|
||||||
|
|
||||||
|
### 📌 Полная реконструкция на C
|
||||||
|
```c
|
||||||
|
#define HW_REG_BASE 0x1F801000 // Базовый адрес аппаратных регистров PS1
|
||||||
|
|
||||||
|
int SystemEventManager(int system_state)
|
||||||
|
{
|
||||||
|
// 1. Проверка условий для обработки основного события
|
||||||
|
if (gSystemActive &&
|
||||||
|
!system_state[0x37] &&
|
||||||
|
!system_state[0x38] &&
|
||||||
|
(system_state == *(int*)(system_state + 0x10) || !system_state[0x39]) &&
|
||||||
|
!**(char**)(system_state + 0x30))
|
||||||
|
{
|
||||||
|
gEventCallback(system_state); // Обработка события
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Главный цикл обработки событий
|
||||||
|
int retry_count = -1;
|
||||||
|
if (gSystemActive)
|
||||||
|
{
|
||||||
|
int offset = -0xF0;
|
||||||
|
do {
|
||||||
|
gEventCounter--;
|
||||||
|
if (gEventCounter < 1) break;
|
||||||
|
|
||||||
|
// Проверка вторичных условий
|
||||||
|
if (retry_count >= 0)
|
||||||
|
{
|
||||||
|
int secondary_state = *(int*)(system_state + 0xC) + offset;
|
||||||
|
if (!secondary_state[0x37] &&
|
||||||
|
!secondary_state[0x38] &&
|
||||||
|
(secondary_state == *(int*)(secondary_state + 0x10) || !secondary_state[0x39]) &&
|
||||||
|
!**(char**)(secondary_state + 0x30))
|
||||||
|
{
|
||||||
|
gEventCallback(secondary_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Обработка аппаратного события
|
||||||
|
byte event_type = GetHardwareEvent(system_state, 1);
|
||||||
|
int status = ProcessHardwareEvent(system_state, event_type);
|
||||||
|
if (status < 0) return status;
|
||||||
|
|
||||||
|
// Ожидание готовности аппаратуры
|
||||||
|
uint16_t* hw_status = (uint16_t*)(gHardwareRegs + 4);
|
||||||
|
TIMER_CLOCK = GetSystemClock();
|
||||||
|
*gControlReg = 0xFFFFFF7F;
|
||||||
|
HW_TIMEOUT = 60;
|
||||||
|
|
||||||
|
while (*hw_status & 0x80) {
|
||||||
|
status = CheckHardwareReady();
|
||||||
|
if (status != 0) goto next_event;
|
||||||
|
hw_status = (uint16_t*)(gHardwareRegs + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
*hw_status |= 0x10; // Установка флага готовности
|
||||||
|
retry_count++;
|
||||||
|
offset += 0xF0;
|
||||||
|
} while (retry_count < 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Управление состоянием системы
|
||||||
|
int state_index = 0;
|
||||||
|
if (gEventCounter > 1)
|
||||||
|
{
|
||||||
|
dword* state_ptr = &gSystemStates[gActiveSubsystem == 0];
|
||||||
|
int subsystem_offset = (gActiveSubsystem == 0) ? 0xF0 : 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
dword current_state = *state_ptr;
|
||||||
|
if ((int)current_state < 0) break;
|
||||||
|
|
||||||
|
if (current_state > 0) {
|
||||||
|
int target_state = *(int*)(gStateBuffer + subsystem_offset + 0xC) + (current_state - 1) * 0xF0;
|
||||||
|
gStateCallback(target_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конечный автомат состояний
|
||||||
|
switch(current_state) {
|
||||||
|
case 3:
|
||||||
|
gStateCallback(target_state - 0xF0);
|
||||||
|
*state_ptr = 1;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
int base_state = gStateBuffer + subsystem_offset;
|
||||||
|
gStateCallback(base_state);
|
||||||
|
gSecondaryCallback(base_state);
|
||||||
|
*state_ptr = -1;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
*state_ptr = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Дополнительная обработка
|
||||||
|
event_type = GetHardwareEvent(system_state, gSystemActive);
|
||||||
|
status = ProcessSecondaryEvent(system_state, event_type);
|
||||||
|
if (status < 0) return status;
|
||||||
|
|
||||||
|
// Повторная проверка аппаратуры
|
||||||
|
hw_status = (uint16_t*)(gHardwareRegs + 4);
|
||||||
|
TIMER_CLOCK = GetSystemClock();
|
||||||
|
*gControlReg = 0xFFFFFF7F;
|
||||||
|
HW_TIMEOUT = 60;
|
||||||
|
|
||||||
|
while (*hw_status & 0x80) {
|
||||||
|
status = CheckHardwareReady();
|
||||||
|
if (status != 0) goto event_processed;
|
||||||
|
hw_status = (uint16_t*)(gHardwareRegs + 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
*hw_status |= 0x10;
|
||||||
|
gEventCounter--;
|
||||||
|
} while (gEventCounter > 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Финальная стадия обработки
|
||||||
|
do {
|
||||||
|
gEventCounter--;
|
||||||
|
if (gEventCounter < 1) {
|
||||||
|
while (!(*(uint16_t*)(gHardwareRegs + 4) & 2)); // Ожидание завершения
|
||||||
|
byte* data_ptr = *(byte**)(system_state + 0x3C);
|
||||||
|
data_ptr[*(byte*)(system_state + 0x44)++] = *(byte*)gHardwareRegs;
|
||||||
|
gCompletionCallback(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
event_type = GetHardwareEvent(system_state, gSystemActive);
|
||||||
|
status = ProcessSecondaryEvent(system_state, event_type);
|
||||||
|
if (status < 0) return status;
|
||||||
|
} while (*(short*)(gHardwareRegs + 0xE) != 0x22);
|
||||||
|
|
||||||
|
// ... (аналогичная обработка аппаратного статуса)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 🔧 Ключевые особенности
|
||||||
|
1. **Управление состоянием**:
|
||||||
|
- Использует конечный автомат с состояниями 0-4
|
||||||
|
- Обрабатывает как основные, так и вторичные события
|
||||||
|
|
||||||
|
2. **Аппаратная синхронизация**:
|
||||||
|
- Работает с регистрами PS1 (0x1F801xxx)
|
||||||
|
- Ожидает готовности аппаратуры через флаги
|
||||||
|
- Управляет таймерами (TMR_SYSCLOCK_VAL)
|
||||||
|
|
||||||
|
3. **Обработка ошибок**:
|
||||||
|
- Возвращает коды ошибок (-3 и другие)
|
||||||
|
- Проверяет статус после каждой операции
|
||||||
|
|
||||||
|
4. **Оптимизации**:
|
||||||
|
- Фиксированные смещения (0xF0 для блоков состояний)
|
||||||
|
- Пакетная обработка событий
|
||||||
|
|
||||||
|
### 🌟 Практическое применение
|
||||||
|
Эта функция может быть:
|
||||||
|
1. **Драйвером контроллера**:
|
||||||
|
- Обрабатывает ввод с геймпада
|
||||||
|
- Управляет вибрацией и другими эффектами
|
||||||
|
|
||||||
|
2. **Менеджером DMA**:
|
||||||
|
- Контролирует передачу данных
|
||||||
|
- Обрабатывает прерывания
|
||||||
|
|
||||||
|
3. **Ядром аудиосистемы**:
|
||||||
|
- Управляет SPU (звуковым процессором)
|
||||||
|
- Синхронизирует аудиопотоки
|
||||||
|
|
||||||
|
### 📊 Структура данных
|
||||||
|
```c
|
||||||
|
// Пример системного состояния (0xF0 байт)
|
||||||
|
struct SystemState {
|
||||||
|
dword main_state; // 0x00: Основное состояние
|
||||||
|
byte sub_state[0x34]; // 0x04: Внутренние флаги
|
||||||
|
byte* data_buffer; // 0x38: Буфер данных
|
||||||
|
byte data_index; // 0x3C: Индекс в буфере
|
||||||
|
// ... другие поля ...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Эта функция - критически важный системный компонент, обеспечивающий:
|
||||||
|
- Стабильную работу с аппаратурой PS1
|
||||||
|
- Своевременную обработку событий
|
||||||
|
- Корректную синхронизацию подсистем игры
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
### **1.2. Регистры управления**
|
### **1.2. Регистры управления**
|
||||||
Основные регистры для работы с контроллерами:
|
Основные регистры для работы с контроллерами:
|
||||||
|
|
||||||
| Адрес | Назначение |
|
| Адрес | Назначение |
|
||||||
|----------------|---------------------------------------------------------------------------|
|
|----------------|---------------------------------------------------------------------------|
|
||||||
| **0x1F801040** | **SIO_DATA** — Данные для отправки/приёма. |
|
| **0x1F801040** | **SIO_DATA** — Данные для отправки/приёма. |
|
||||||
@@ -260,4 +261,90 @@ int main() {
|
|||||||
3. Рекомендуется вызывать эту функцию один раз за кадр
|
3. Рекомендуется вызывать эту функцию один раз за кадр
|
||||||
4. В отличие от `PadRead()`, `PadChkVsync` не очищает буфер ввода
|
4. В отличие от `PadRead()`, `PadChkVsync` не очищает буфер ввода
|
||||||
|
|
||||||
Функция `PadChkVsync` особенно полезна в играх, где важно точно определять момент подключения/отключения контроллеров во время gameplay, например, в multiplayer-играх с возможностью "hot-plug" контроллеров.
|
Функция `PadChkVsync` особенно полезна в играх, где важно точно определять момент подключения/отключения контроллеров во время gameplay, например, в multiplayer-играх с возможностью "hot-plug" контроллеров.
|
||||||
|
|
||||||
|
-------
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Да, функция **`PadInitDirect`** действительно существует в библиотеке PsyQ и является важной частью системы обработки ввода для PlayStation 1. Вот подробное объяснение:
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔍 **Назначение PadInitDirect**
|
||||||
|
Функция **инициализирует систему обработки геймпадов** в режиме прямого доступа (Direct Access). Она:
|
||||||
|
|
||||||
|
1. **Настраивает аппаратные порты контроллеров** (до 2-х геймпадов)
|
||||||
|
2. **Подготавливает буферы** для чтения состояния кнопок
|
||||||
|
3. **Активирует низкоуровневый доступ** к данным геймпадов
|
||||||
|
4. **Возвращает статус** инициализации (`1` = успех, `0` = ошибка)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📜 **Синтаксис в PsyQ**
|
||||||
|
```c
|
||||||
|
#include <libpad.h>
|
||||||
|
|
||||||
|
int PadInitDirect(unsigned char *padBuf1, unsigned char *padBuf2);
|
||||||
|
```
|
||||||
|
- **`padBuf1`** - буфер для геймпада на порту 1 (размер ≥ 34 байт)
|
||||||
|
- **`padBuf2`** - буфер для геймпада на порту 2 (может быть `NULL`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 💻 **Пример использования**
|
||||||
|
```c
|
||||||
|
#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()
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔧 **Особенности работы**
|
||||||
|
1. **Требования к буферам**:
|
||||||
|
- Минимальный размер: **34 байта**
|
||||||
|
- Должны быть **64-байтно выровнены** (для DMA)
|
||||||
|
- Пример объявления:
|
||||||
|
```c
|
||||||
|
unsigned char padBuf[34] __attribute__((aligned(64)));
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Режимы работы**:
|
||||||
|
- Прямой доступ (`PadInitDirect`) - ручное управление
|
||||||
|
- Стандартный режим (`PadInit`) - автоматическое управление
|
||||||
|
|
||||||
|
3. **Совместимость**:
|
||||||
|
- Поддерживает все типы контроллеров PS1:
|
||||||
|
- Обычные геймпады (Digital)
|
||||||
|
- Аналоговые джойстики (DualShock)
|
||||||
|
- Мышь PlayStation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ⚠️ **Важные нюансы**
|
||||||
|
1. **Перед использованием** необходимо вызвать `PadStartCom()` для начала обмена данными
|
||||||
|
2. **Для чтения** используется `PadRead()` после инициализации
|
||||||
|
3. **В мультиплеерных играх** нужно инициализировать оба порта:
|
||||||
|
```c
|
||||||
|
PadInitDirect(pad1Buf, pad2Buf);
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 📚 **Документация PsyQ**
|
||||||
|
В официальном **PsyQ SDK** функция описана в файлах:
|
||||||
|
- `libpad.h` - заголовочный файл
|
||||||
|
- `libpad.doc` - документация
|
||||||
|
- Примеры в `Samples/PAD` демонстрируют использование
|
||||||
|
|||||||
Reference in New Issue
Block a user