Files
SergObsidian/PERSONAL PROJECTS/PS1 DOCS/PS1 DMA.md
2025-04-19 00:21:02 +05:00

12 KiB
Raw Blame History

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)

; Настройка 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)

#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):

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 критична для производительности (например, загрузка уровней без лагов).

Для глубокого понимания изучите:


Команда DMACallback в PS1 (PlayStation 1)

DMACallback — это функция в библиотеках PsyQ для PlayStation 1, которая позволяет установить пользовательский обработчик прерываний DMA (Direct Memory Access). DMA используется для высокоскоростной передачи данных между компонентами системы без участия основного процессора.

Основное назначение

Функция DMACallback регистрирует callback-функцию, которая будет вызываться при завершении DMA-передачи. Это позволяет:

  • Уведомлять программу о завершении передачи данных
  • Обрабатывать ошибки DMA
  • Запускать следующие операции передачи данных по цепочке

Синтаксис

void DMACallback(void (*callback)(void));

Пример использования

#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. Сброс обработчика: По завершении можно сбросить обработчик, если он больше не нужен:

    DMACallback(NULL);
    
  5. Сочетание с другими функциями: Часто используется вместе с DmaReady() для проверки состояния DMA.

Пример с GPU DMA

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.