TSconf: DMA

Учитывая такой большой размер памяти, необходимо средство быстрой передачи данных.
TSconf предлагает нам такое средство, позволяющее переносить данные в памяти без участия процессора.

Дао говорит: Скорость пересылки составляет 7 Мгц, копирование происходит по два байта (16 бит) при условии что в этот такт к памяти нет обращения от ЦПУ, видео или ТСУ.
В среднем: 4 байта — 2 такта, дма обращается к озу за 1 такт 7 мгц, 16 бит, для пересылки надо 2 обращения
Получаем: скорость DMA 7 МБ/с
DMA может копировать данные из следующих источников:


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 комментариев

avatar
А ещё можно код исполняемый генерировать с помощью DMA. Отлично обгоняет PC процессора. Получается аппаратный мультиколор только для процессора.
avatar
Robus, ты псих, в очень хорошем смысле!!! это как поезд идёт, рельсоукладчик перед паровозом, а за последним вагоном можно сразу и рельсоуборщик пустить :)
avatar
обоснуй, КАК?
avatar
короче, идея мне нравится, но вот применения пока не вижу))
avatar
10:46 идея Робуса о выкладывании кода дмой -круто, кеш кстати отключать не надо, достаточно выдерживать границу. Очень хорошо в разворачивании циклов
10:47 единственная проблема, но не сильно критичная выдерживать гранцу блоков кода в 2 байта
  • VBI
  • +2
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.