TSconf: DMA
Учитывая такой большой размер памяти, необходимо средство быстрой передачи данных.
TSconf предлагает нам такое средство, позволяющее переносить данные в памяти без участия процессора.
Что мы можем использовать?
Прямое копирование, режим копирования для изображений с прозрачностью (прозрачность не копируется — наложение данных поверх), копирование из SPI устройств (например — sd-card), копирование из винчестера, заполнение памяти заданными 16 битами (очистка экрана — он же fill цветом), копирование во внутреннюю память системы для палитры и для спрайтов.
Копирование выполняется заполнением портов DMA системы:
Максимальная длина для одной передачи — 512 байт (256 раз по 2 байта), максимальное количество блоков передачи — 256
Максимально возможная ОДНА передача данных: 256*512 байт = 131072 байт за одно копирование.
Естественно, что длина может быть установлена другая.
Учитывая то, что передача происходит по 2 байта (16 бит), минимально мы можем скопировать 2 байта данных, что есть 4 точки в режиме 16ц (один байт — 2 точки), либо 2 точки в режиме 256 цветов. Все адреса операций четные.
Режимы копирования:
Данные биты используются для установки действий системы после копирования одного блока данных (burst) заданной длины:
Более подробно о #27af (порт запуска DMACtrl):
Здесь бит 7 — R/W, 6й бит не юзается, 5 — выравнивание источника, 4 — выравнивание приёмника, 3 — тип выравнивания (512/256), далее 3 бита устройства.
Итак, как всем этим добром управлять?
Необходимо программировать порты DMA (#xxAF):
Старший байт порта источника:
#1Aaf, #1Baf — адрес (младший DMASAddrL, старший DMASAddrH байты)
#1Caf — начальная страница DMASAddrX
Старший байт порта приёмника
#1Daf, #1Eaf — адрес (младший DMADAddrL, старший DMADAddrH байты)
#1Faf — начальная страница DMADAddrX
Порт длины одного burst передачи: #26af, DMALen
Порт количества burst передачи: #28af, DMANum
Порт управление передачей / состояния передачи: #27af, DMACtrl
Отправка данных в этот порт #27af (DMACtrl) запускает передачу DMA
Примеры:
Давайте подойдём к делу более умным образом, чем простое программирование каждого порта:
Итак, копируем графику с выравниванием (переходом на следующую строку на экране) после каждого бурста.
Отметим себе, что A_SZ у нас выключен, что и нужно для 16 цветов:
Для этого используем подпрограмму выдачи данных в порт (set_ports):
После установки значения для порта 27 передача стартует. Нам нужно контролировать занятость DMA, для этого используется чтение этого-же порта на предмет сигнала busy (бит DMA_ACT). Установка этого бита в 0 обозначает, что передача завершена.
В данном случае мы включаем страницу видео с адреса #c000 и заполняем её нужным нам цветом (в данном случае — цвет №00), после чего стартуем заливку. Копирование происходит с адреса 0000 (помним, что системе по барабану состояние старших двух битов и одного младшего)
происходит заполнение длинной 256*2, 200 бурстов.
В данном случае копируем 16 цветов (одну палитру), со второй страницы в начало палитровой памяти.
Вопросы:
? Зачем тут DMA_DALGN?
! Так как изображение у нас по ширине 256 точек, после последней 256й точки мы должны размещать новую порцию данных с новой строки. В этом нам этот бит и поможет.
? Почему для порта DMANum (#28af) такое странное значение: 256-1?
! Учитывая то, что максимальное количество burst у нас 256, а минимальное — 1, принято, что отправленное в порт значение 0 — это количество burst 1 штука, а отправленное значение 255 — это соответственно 256 бурстов.
? Почему для порта DMALen (#26af) задано такое странное значение: 256/4-1 ?
! Так как у нас размер изображения 256 точек в режиме 16цветов, в одном байте мы получаем 2 точки, а в двух — 4 точки.
Опять-же, значение 0 для этого порта — это минимальная длина в 2 байта.
? Стоит ли ждать конца пересылки в цикле чтения порта DMASTATUS?
! Если Вы уверены, что пересылка успеет отработать до начала новой — совершенно не обязательно. Мало того, рекомендуется цикл ожидания ставить ПЕРЕД новой DMA транзакцией, дабы z80 продолжал свою работу по вычислениям, пока DMA отрабатывает задачу.
? Я переслал палитру, а она вообше не такого цвета!
! Проверьте расположение палитры — она должна лежать в памяти по чётному адресу. ALIGN 2 вам в помощь. Или, возможно, не туда скопировали?
? Картинку переслал на экран, а он съехала по строчкам!
! Размер картинки должен быть кратен 2м байтам — 2 точки (256ц), 4 точки (16ц)
? а DMA при копировании сама страницы переключает?
! Конечно! И источник и приёмник.
Литература: F.A.Q., справочник
TSconf предлагает нам такое средство, позволяющее переносить данные в памяти без участия процессора.
Дао говорит: Скорость пересылки составляет 7 Мгц, копирование происходит по два байта (16 бит) при условии что в этот такт к памяти нет обращения от ЦПУ, видео или ТСУ.DMA может копировать данные из следующих источников:
В среднем: 4 байта — 2 такта, дма обращается к озу за 1 такт 7 мгц, 16 бит, для пересылки надо 2 обращения
Получаем: скорость DMA 7 МБ/с
Src Destination
RAM RAM RAM (Src) is copied to RAM (Dst)
BLT RAM Pixels from RAM (Src) are copied to RAM (Dst) if they non zero
SPI RAM SPI data is copied to RAM (Dst)
RAM SPI RAM (Src) is copied to SPI
IDE RAM IDE data is copied to RAM (Dst)
RAM IDE RAM (Src) is copied to IDE
FILL RAM RAM (Dst) is filled with word from RAM (Src)
RAM CRAM RAM (Src) is copied to CRAM (Dst)
RAM SFILE RAM (Src) is copied to SFILE (Dst)
Что мы можем использовать?
Прямое копирование, режим копирования для изображений с прозрачностью (прозрачность не копируется — наложение данных поверх), копирование из SPI устройств (например — sd-card), копирование из винчестера, заполнение памяти заданными 16 битами (очистка экрана — он же fill цветом), копирование во внутреннюю память системы для палитры и для спрайтов.
Копирование выполняется заполнением портов DMA системы:
- адрес начала исходных данных, страница исходных данных;
- адрес начала приёмника, страница для приёма данных;
- количество передаваемых данных за один раз (длина burst), количество таких блоков передачи (burst);
- установка режима копирования, которая запускает передачу
Максимальная длина для одной передачи — 512 байт (256 раз по 2 байта), максимальное количество блоков передачи — 256
Максимально возможная ОДНА передача данных: 256*512 байт = 131072 байт за одно копирование.
Естественно, что длина может быть установлена другая.
Учитывая то, что передача происходит по 2 байта (16 бит), минимально мы можем скопировать 2 байта данных, что есть 4 точки в режиме 16ц (один байт — 2 точки), либо 2 точки в режиме 256 цветов. Все адреса операций четные.
Режимы копирования:
S_ALGN Source Address Alignment
D_ALGN Destination Address Alignment
0 After each burst address keeped as is
1 After each burst lower bits of address restored to their initial values before burst, upper bits increased by 1
A_SZ Address Alignment Size
0 256 bytes (8 lower address bits) alignment
1 512 bytes (9 lower address bits) alignment
A_SZ Blitting Bitness
0 4 bits per pixel, transparent color is 0 from 16 (4'b0)
1 8 bits per pixel, transparent color is 0 from 256 (8'b0)
Данные биты используются для установки действий системы после копирования одного блока данных (burst) заданной длины:
- S_ALGN,D_ALGN: данные биты отвечают за «выравнивание» адреса источника / приёмника. В состоянии 0 адрес не изменяется, в состоянии 1- адрес будет восстановлен до начального с увеличением старшего адреса в зависимости от бита A_SZ. Такой режим нам пригодится при копировании графики.
- A_SZ — способ выравнивания данных: по 256 / 512 байт после каждого burst, что полезно для копирования 4х битной (16 цветной) или 8 битной графики
Более подробно о #27af (порт запуска DMACtrl):
DMACtrl ~R/W - S_ALGN D_ALGN A_SZ DDEV[2:0]
Здесь бит 7 — R/W, 6й бит не юзается, 5 — выравнивание источника, 4 — выравнивание приёмника, 3 — тип выравнивания (512/256), далее 3 бита устройства.
Дао говорит: Адрес для DMA не учитывает состояние двух старших бит 16-битного адреса.
Соответственно, #c000 = #0000. Можно использовать как #c000, так и #0000 для адреса — они равнозначны.
При копировании данных расположение в памяти (адрес) для источника / приёмника должно быть кратно 2.
Итак, как всем этим добром управлять?
Необходимо программировать порты DMA (#xxAF):
Старший байт порта источника:
#1Aaf, #1Baf — адрес (младший DMASAddrL, старший DMASAddrH байты)
#1Caf — начальная страница DMASAddrX
Старший байт порта приёмника
#1Daf, #1Eaf — адрес (младший DMADAddrL, старший DMADAddrH байты)
#1Faf — начальная страница DMADAddrX
Порт длины одного burst передачи: #26af, DMALen
Порт количества burst передачи: #28af, DMANum
Порт управление передачей / состояния передачи: #27af, DMACtrl
Отправка данных в этот порт #27af (DMACtrl) запускает передачу DMA
Примеры:
Копируем изображение 256х256 точек в режиме 16ц в экран.Исходное изображение находится по адресу #c000 страницы glasspat_page, копируется в адрес #c000 страницы экрана.
Давайте подойдём к делу более умным образом, чем простое программирование каждого порта:
ld bc, #1aaf ; DMASAddrL
xor a
out (c),a
inc b
out (c),a
Итак, копируем графику с выравниванием (переходом на следующую строку на экране) после каждого бурста.
Отметим себе, что A_SZ у нас выключен, что и нужно для 16 цветов:
ld hl,glasspat_copy
call set_ports
ret
glasspat_page equ #22
Vid_page equ #80
glasspat_copy db #1a,0
db #1b,0
db #1c,glasspat_page
db #1d,0
db #1e,0
db #1f,Vid_page
db #26,256/4-1
db #28,256-1
db #27,DMA_RAM + DMA_DALGN
db #ff
Для этого используем подпрограмму выдачи данных в порт (set_ports):
set_ports ld c,#AF
.m1 ld b,(hl)
inc hl
inc b
jr z,dma_stats
outi
jr .m1
dma_stats ld b,high DMASTATUS
in a,(c)
AND #80
jr nz,$-4
ret
После установки значения для порта 27 передача стартует. Нам нужно контролировать занятость DMA, для этого используется чтение этого-же порта на предмет сигнала busy (бит DMA_ACT). Установка этого бита в 0 обозначает, что передача завершена.
Очистка (заливка) экрана:
ld bc,PAGE3
ld a,Vid_page
out (c),a
ld hl,0 ;00 - цвет, заданный в палитре
ld (#c000),hl
ld hl,fill_screen
jp set_ports
fill_screen defb #1a,0 ;
defb #1b,0 ;
defb #1c,Vid_page ;
defb #1d,0 ;
defb #1e,0 ;
defb #1f,Vid_page ;
defb #28,200 ;
defb #26,#ff ;
defb #27,%00000100 ; DMA_FILL
db #ff
В данном случае мы включаем страницу видео с адреса #c000 и заполняем её нужным нам цветом (в данном случае — цвет №00), после чего стартуем заливку. Копирование происходит с адреса 0000 (помним, что системе по барабану состояние старших двух битов и одного младшего)
происходит заполнение длинной 256*2, 200 бурстов.
Очистка тайлового слоя:
clear_tileset ld bc,PAGE3
ld a,Tile_page
out (c),a
ld hl,0
ld (#c000),hl
ld hl,tileset_clr
jp set_ports
tileset_clr
defb #1a,0 ;
defb #1b,0 ;
defb #1c,Tile_page ;
defb #1d,0 ;
defb #1e,0 ;
defb #1f,Tile_page ;
defb #28,#ff ;
defb #26,#3f ;
defb #27,%00000100
db #ff
Копирование палитры в палитровую память:
ld hl,pals
jp set_ports
pals db #1a,low pal
db #1b,high pal
db #1c,2
db #1d,0
db #1e,0
db #1f,0
db #26,#10
db #28,0
db #27,DMA_RAM_CRAM ; #84 - копирование из RAM в CRAM
db #ff
align 2
pal incbin "palette.tga.pal"
В данном случае копируем 16 цветов (одну палитру), со второй страницы в начало палитровой памяти.
Вопросы:
? Зачем тут DMA_DALGN?
! Так как изображение у нас по ширине 256 точек, после последней 256й точки мы должны размещать новую порцию данных с новой строки. В этом нам этот бит и поможет.
? Почему для порта DMANum (#28af) такое странное значение: 256-1?
! Учитывая то, что максимальное количество burst у нас 256, а минимальное — 1, принято, что отправленное в порт значение 0 — это количество burst 1 штука, а отправленное значение 255 — это соответственно 256 бурстов.
? Почему для порта DMALen (#26af) задано такое странное значение: 256/4-1 ?
! Так как у нас размер изображения 256 точек в режиме 16цветов, в одном байте мы получаем 2 точки, а в двух — 4 точки.
Опять-же, значение 0 для этого порта — это минимальная длина в 2 байта.
? Стоит ли ждать конца пересылки в цикле чтения порта DMASTATUS?
! Если Вы уверены, что пересылка успеет отработать до начала новой — совершенно не обязательно. Мало того, рекомендуется цикл ожидания ставить ПЕРЕД новой DMA транзакцией, дабы z80 продолжал свою работу по вычислениям, пока DMA отрабатывает задачу.
? Я переслал палитру, а она вообше не такого цвета!
! Проверьте расположение палитры — она должна лежать в памяти по чётному адресу. ALIGN 2 вам в помощь. Или, возможно, не туда скопировали?
? Картинку переслал на экран, а он съехала по строчкам!
! Размер картинки должен быть кратен 2м байтам — 2 точки (256ц), 4 точки (16ц)
? а DMA при копировании сама страницы переключает?
! Конечно! И источник и приёмник.
Литература: F.A.Q., справочник
5 комментариев
10:47 единственная проблема, но не сильно критичная выдерживать гранцу блоков кода в 2 байта