### **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 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 #include #include #include #include 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.