250 lines
12 KiB
Markdown
250 lines
12 KiB
Markdown
### **DMA (Direct Memory Access) в PlayStation 1**
|
||
DMA в PS1 — это механизм, позволяющий устройствам (GPU, CD-ROM, SPU и др.) **передавать данные напрямую в RAM без участия CPU**. Это ускоряет работу системы, освобождая процессор для других задач.
|
||
|
||
---
|
||
|
||
## **1. Для чего нужен DMA в PS1?**
|
||
- **Ускорение передачи данных**: CPU (R3000A) слишком медленный для копирования больших объёмов данных.
|
||
- **Разгрузка CPU**: Позволяет играм одновременно:
|
||
- Рендерить графику (GPU).
|
||
- Загружать уровни с CD-ROM.
|
||
- Проигрывать музыку (SPU).
|
||
- **Параллельная работа устройств**: Например, CD-ROM может грузить данные, пока GPU рисует кадр.
|
||
|
||
---
|
||
|
||
## **2. Как работает DMA?**
|
||
### **2.1. Общий принцип**
|
||
1. **CPU настраивает DMA**: Указывает источник, приёмник и размер данных.
|
||
2. **DMA-контроллер берёт управление шиной**: CPU временно "засыпает".
|
||
3. **Данные копируются напрямую** из устройства в RAM (или наоборот).
|
||
4. **DMA завершает работу** и сообщает CPU через прерывание.
|
||
|
||
### **2.2. Регистры DMA**
|
||
Главный контроллер DMA находится по адресу **`0x1F8010F0`**, но каждый канал имеет свои регистры:
|
||
|
||
| Адрес | Назначение |
|
||
|----------------|--------------------------------|
|
||
| `0x1F8010F0` | **DPCR** (Управление каналами) |
|
||
| `0x1F8010F4` | **DICR** (Статус/прерывания) |
|
||
| `0x1F8010__` | Регистры конкретных каналов |
|
||
|
||
---
|
||
|
||
## **3. Каналы DMA и их назначение**
|
||
В PS1 есть **6 каналов DMA**, каждый закреплён за конкретным устройством:
|
||
|
||
| Канал | Устройство | Назначение |
|
||
|-------|------------|----------------------------------------------------------------------------|
|
||
| **0** | MDEC (IN) | Декодирование видео (например, FMV из MPEG). |
|
||
| **1** | MDEC (OUT) | Вывод декодированных данных. |
|
||
| **2** | GPU | Передача команд и данных в видеопроцессор (например, списки отображения). |
|
||
| **3** | CD-ROM | Чтение данных с диска. |
|
||
| **4** | SPU | Загрузка семплов и команд в звуковой процессор. |
|
||
| **5** | PIO (EXT) | Расширенный порт (редко используется). |
|
||
| **6** | OTC | Очистка RAM (используется для Ordering Table в GPU). |
|
||
|
||
---
|
||
|
||
## **4. Как настроить и запустить DMA?**
|
||
### **4.1. Общий алгоритм**
|
||
Для любого канала DMA нужно:
|
||
1. **Установить источник и приёмник**:
|
||
- Если передача **из RAM в устройство** (например, GPU):
|
||
- Источник: Адрес в RAM.
|
||
- Приёмник: Регистр устройства (например, `0x1F801810` для GPU).
|
||
- Если передача **из устройства в RAM** (например, CD-ROM):
|
||
- Источник: Данные устройства (буфер CD-ROM).
|
||
- Приёмник: Адрес в RAM.
|
||
|
||
2. **Задать размер блока** и режим DMA:
|
||
- Размер: Сколько слов (4 байта) передать.
|
||
- Режим:
|
||
- `0x01000000` — одношаговый (по одному слову).
|
||
- `0x01000200` — пакетный (пачками, быстрее).
|
||
|
||
3. **Включить канал** через **DPCR** и **DICR**.
|
||
|
||
---
|
||
|
||
### **4.2. Примеры кода**
|
||
#### **Пример 1: Передача данных в GPU (канал 2)**
|
||
```asm
|
||
; Настройка DMA для GPU
|
||
li a0, 0x1F8010A0 ; Адрес регистра DMA2 (GPU)
|
||
la a1, command_list ; Адрес данных в RAM
|
||
sw a1, 0(a0) ; Источник = command_list
|
||
|
||
li a0, 0x1F8010A4
|
||
li a1, 0x01000200 ; Размер + режим (пакетный)
|
||
sw a1, 0(a0)
|
||
|
||
li a0, 0x1F8010A8
|
||
li a1, 0x01000001 ; Включить DMA
|
||
sw a1, 0(a0)
|
||
```
|
||
|
||
#### **Пример 2: Чтение CD-ROM (канал 3)**
|
||
```c
|
||
#include <libcd.h>
|
||
|
||
void cd_read_sectors(int lba, int num_sectors, void *buffer) {
|
||
CdRead(num_sectors, (CdlLOC*)&lba, CD_READ_SPEED, buffer);
|
||
CdReadSync(0); // Ожидать завершения DMA
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## **5. Важные нюансы**
|
||
### **5.1. Синхронизация**
|
||
- DMA работает **асинхронно**. Нужно ждать завершения:
|
||
- Через **прерывание** (если настроено в DICR).
|
||
- Через **опрос флага** (например, `CdReadSync` для CD-ROM).
|
||
|
||
### **5.2. Ограничения**
|
||
- **Размер блока**: Не более 64 КБ за одну передачу.
|
||
- **Выравнивание**: Адреса в RAM должны быть кратны 4.
|
||
|
||
### **5.3. Конфликты**
|
||
- Если два устройства пытаются использовать DMA одновременно, возможны **задержки**.
|
||
- Решение: планировать передачу данных между кадрами (например, в VBlank).
|
||
|
||
---
|
||
|
||
## **6. DMA и Ordering Table (GPU)**
|
||
Для 3D-рендеринга DMA используется для передачи **Ordering Table** (OT):
|
||
1. CPU формирует список примитивов в RAM.
|
||
2. DMA (канал 2) копирует OT в GPU.
|
||
3. GPU рендерит кадр, соблюдая порядок из OT.
|
||
|
||
**Пример очистки OT через DMA (канал 6)**:
|
||
```asm
|
||
li a0, 0x1F8010E0 ; DMA6 (OTC)
|
||
la a1, ot_buffer ; Адрес OT
|
||
sw a1, 0(a0)
|
||
|
||
li a0, 0x1F8010E4
|
||
li a1, 0x00010000 ; Размер (например, 256 слов)
|
||
sw a1, 0(a0)
|
||
|
||
li a0, 0x1F8010E8
|
||
li a1, 0x11000002 ; Режим: очистка OT
|
||
sw a1, 0(a0)
|
||
```
|
||
|
||
---
|
||
|
||
## **7. Итог**
|
||
- **DMA в PS1** — это ключевой механизм для быстрой передачи данных между устройствами и RAM.
|
||
- **6 каналов**, каждый закреплён за конкретным устройством (GPU, CD-ROM, SPU и др.).
|
||
- **Настройка** требует указания источника, приёмника и режима работы.
|
||
- **Оптимизация DMA** критична для производительности (например, загрузка уровней без лагов).
|
||
|
||
Для глубокого понимания изучите:
|
||
- [PSX DMA Hardware Specs](http://problemkaputt.de/psx-spx.htm#dmacontroller)
|
||
- [PsyQ SDK Docs](http://psx.arthus.net/sdk/PsyQ/DOCS/)
|
||
|
||
-------------------
|
||
|
||
|
||
|
||
# Команда `DMACallback` в PS1 (PlayStation 1)
|
||
|
||
`DMACallback` — это функция в библиотеках PsyQ для PlayStation 1, которая позволяет установить пользовательский обработчик прерываний DMA (Direct Memory Access). DMA используется для высокоскоростной передачи данных между компонентами системы без участия основного процессора.
|
||
|
||
## Основное назначение
|
||
|
||
Функция `DMACallback` регистрирует callback-функцию, которая будет вызываться при завершении DMA-передачи. Это позволяет:
|
||
- Уведомлять программу о завершении передачи данных
|
||
- Обрабатывать ошибки DMA
|
||
- Запускать следующие операции передачи данных по цепочке
|
||
|
||
## Синтаксис
|
||
|
||
```c
|
||
void DMACallback(void (*callback)(void));
|
||
```
|
||
|
||
## Пример использования
|
||
|
||
```c
|
||
#include <sys/types.h>
|
||
#include <libetc.h>
|
||
#include <libgte.h>
|
||
#include <libgpu.h>
|
||
#include <libdma.h>
|
||
|
||
void my_dma_callback(void)
|
||
{
|
||
printf("DMA transfer completed!\n");
|
||
}
|
||
|
||
int main()
|
||
{
|
||
// Установка callback-функции для DMA
|
||
DMACallback(my_dma_callback);
|
||
|
||
// Пример DMA-передачи (условный)
|
||
DmaCopy(0, dest_addr, src_addr, size);
|
||
|
||
while(1)
|
||
{
|
||
// Главный цикл программы
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
```
|
||
|
||
## Типы DMA в PS1
|
||
|
||
В PS1 существует несколько DMA-каналов, для которых можно устанавливать обработчики:
|
||
|
||
1. **GPU DMA** - для передачи данных в графический процессор
|
||
2. **CD-ROM DMA** - для чтения данных с CD
|
||
3. **SPU DMA** - для передачи звуковых данных
|
||
4. **OTC DMA** - для очистки ordering tables
|
||
|
||
## Важные особенности
|
||
|
||
1. **Асинхронность**: DMA работает независимо от CPU, callback вызывается по завершении передачи.
|
||
|
||
2. **Критические секции**: Обработчик DMA должен быть коротким и быстрым, без сложных операций.
|
||
|
||
3. **Регистрация**: Обработчик нужно регистрировать перед началом DMA-передачи.
|
||
|
||
4. **Сброс обработчика**: По завершении можно сбросить обработчик, если он больше не нужен:
|
||
```c
|
||
DMACallback(NULL);
|
||
```
|
||
|
||
5. **Сочетание с другими функциями**: Часто используется вместе с `DmaReady()` для проверки состояния DMA.
|
||
|
||
## Пример с GPU DMA
|
||
|
||
```c
|
||
void gpu_dma_complete(void)
|
||
{
|
||
// Разблокировать ресурсы или начать следующую передачу
|
||
printf("GPU DMA completed\n");
|
||
}
|
||
|
||
void send_data_to_gpu(void *data, u_long size)
|
||
{
|
||
// Установка обработчика
|
||
DMACallback(gpu_dma_complete);
|
||
|
||
// Начало DMA-передачи в GPU
|
||
LoadImage((RECT*)data, (u_long*)(data + sizeof(RECT)));
|
||
}
|
||
```
|
||
|
||
## Альтернативные функции
|
||
|
||
В разных версиях PsyQ могут быть аналогичные функции с другими именами:
|
||
- `DMACallBack()` (с заглавной B)
|
||
- `SetDMACallback()`
|
||
- Для конкретных каналов: `SetGPUCompleteCallback()`, `SetCDROMCallback()` и т.д.
|
||
|
||
`DMACallback` предоставляет удобный механизм для асинхронной обработки завершения DMA-операций, что особенно важно для эффективного использования аппаратных возможностей PS1. |