Hacker VBI, Да - интересно почитать про TS в доступном виде = продолжай ))
Вид для печати
Hacker VBI, Да - интересно почитать про TS в доступном виде = продолжай ))
piroxilin, это хорошо.
в общем, есть ещё один разбор.
MindWarp от DDp
Смотреть бум только первую часть балета - эффект, завязанный на палитре
Что имеем сразу в страницах памяти: сформированное изображение для экрана, сотни килобайт звука для ковокса.
Картинка для экрана - чёрнобелая.
Суть эффекта - в смене палитры для изображения на экране.
изображение палитры - во вложении.
берём в b адрес порта, в а - данные, бросаем в порт:Код:org 0x6200
binclude "mw_pal.bin"
ld iyl,3
restart:di
ld sp,0x6000
ld hl,mw_int
ld (0x67ff),hl
ld a,0x67
ld i,a
im 2
; копируем палитру
ld hl,0x6200
ld de,0x6000
ld bc,0x0200
ldir
; начинаем заброс данных в порты:
ld hl,mwset
ld e,(mwset_end-mwset)/2
ld c,0xaf
wrrg1: ld b,(hl)
inc l
ld a,(hl)
inc l
out (c),a
dec e
jr nz,wrrg1
0x20,6 - System Config, %10 -ставим частоту 14.0,normal, кеш включен.
0x00,0xc2 - VConfig, включаем макс разрешение 360x288, 256 цветов.
0x01,MW_PIC_PAGE - Video Page, включаем страницу 16 с изображением
0x02,0 - X-offset for graphics, отступы окна просмотра в 0.
0x03,0
0x04,0 - Y-offset for graphics
0x05,0
0x1a,0x00 - DMA Source Address
0x1b,0x20
0x1c,5 - DMASAddrX, страница
0x1d,0 - DMA Destination Address
0x1e,0
0x1f,0 - страница приёмника
0x26,255 - DMA Burst Length, 512 байт за один бурст
0x28,0 - DMANum, колво бурстов - 0 (это 1) штука.
0x27,0x84 - DMACtrl, здесь RAM (Src) is copied to CRAM (Dst)
насколько я понимаю, здесь перебрасывается палитра в память CRAM
что имеем выполняемого?Код:ld hl,0x2000 ; палитра
ld de,0x0020 ; сдвиг по палитре
ld a,0x84 ; DMACtrl, здесь RAM (Src) is copied to CRAM (Dst)
exx
ex af,af'
ld bc,0x13af ; память со звуком
ld de,1 ; инкремент на 1 при воспроизведении
ei
sloop0:
; здесь происходит вывод звука в ковокс в основном цикле
ld a,MW_SND_PAGE
jp sloop3
snewpg: ld a,(sndpage)
sloop3: out (c),a
inc a
ld (sndpage),a
ld hl,0xc000
sloop1: ld a,(hl)
or a
jr z,sloop0
out (0xfb),a
add hl,de
jp c,snewpg
ld a,MW_SND_DELAY ; задержка при воспроизведении
sdly: dec a
jr nz,sdly
jp sloop1
; непосредственно инт, меняющий палитру
mw_int: ex af,af'
exx
add hl,de ; добавили #20
res 1,h ; больше #2200 адрес не увеличится
ld b,0x1a ;DMA Source Address младший байт
out (c),l
ld b,0x1b; DMA Source Address старший байт
out (c),h
ld b,0x27 ; выполнение DMACtrl
out (c),a
exx
ex af,af'
ei
ret
; всё, палитра сдвинулась, на экране красота)
sndpage:defb 0
mwset: defb 0x20,6
defb 0x00,0xc2
defb 0x01,MW_PIC_PAGE
defb 0x02,0
defb 0x03,0
defb 0x04,0
defb 0x05,0
defb 0x1a,0x00
defb 0x1b,0x20
defb 0x1c,5
defb 0x1d,0
defb 0x1e,0
defb 0x1f,0
defb 0x26,255
defb 0x28,0
defb 0x27,0x84
mwset_end:
для эффекта: три аута в порты по прерыванию,
для звука - простой вывод в ковокс:
Просто?Код:ld a,(hl)
or a
jr z,sloop0
out (0xfb),a
add hl,de
jp c,snewpg
ld a,MW_SND_DELAY ; задержка при воспроизведении
sdly: dec a
jr nz,sdly
Описание работы эффекта от автора - DDp
Код:Все данные уже подготовлены в нужном формате
и загружаются в загрузчиком SPG в заданные страницы памяти.
Программу можно разделить на две части:
подготовка(инициализация) и собственно эффект.
При инициализации устанавливается видео режим,
предустанавливается регистры DMA (делается
первая пересылка - запись в палитру) и др.
Перед запуском эффекта в следующих регистрах установлены значения:
DE = 0001
BC = 13AF
A'= 84
HL'= 2000
DE'= 0020
C'= AF
Основной цикл использует "первый" набор регистров,
а обработчик прерывания "второй".
Основной цикл программно проигрывает звук на covox.
В обработчике прерывания посредством DMA устанавливается новая,
циклически сдвинутая, палитра (пересылка "из RAM в ПАЛИТРУ").
;------------------------------------------------------------------------------
sloop0:
ld a,MW_SND_PAGE ;номер начальной страницы памяти со звуком
jp sloop3
snewpg: ld a,(sndpage)
sloop3: out (c),a ;установка страницы памяти в окне "С000"
inc a
ld (sndpage),a ;номер следующей страницы сохранить
ld hl,0xc000 ;HL - указатель
sloop1: ld a,(hl) ;читаем значение семпла из памяти
or a ;конец звука? (см. примечания)
jr z,sloop0 ; да - играем с начала
out (0xfb),a ;вывод семпла звука в порт covox-а
add hl,de ;HL+1 - инкремент адреса
jp c,snewpg ;конец страницы? да - включить следующую
ld a,MW_SND_DELAY ;задержка между семплами
sdly: dec a ; (подобрано значение для скорости
jr nz,sdly ; примерно 44100 семплов в секунду)
jp sloop1
;------------------------------------------------------------------------------
;кадровое прерывание
mw_int: ex af,af' ;переключаемся на "второй"
exx ;набор регистров
;в HL указатель на значения палитры в памяти
add hl,de ;HL+32 - коррекция указателя
res 1,h ;ограничивает перемещение указателя в пределах 512 байт
ld b,0x1a ;"DMA Source Address" - LOW
out (c),l
ld b,0x1b ;"DMA Source Address" - HIGH
out (c),h
ld b,0x27 ;"DMA Control / Start"
out (c),a ;0x84 - запуск DMA в режиме "из RAM в ПАЛИТРУ"
exx ;переключаемся на "первый"
ex af,af' ;набор регистров
ei
ret
;------------------------------------------------------------------------------
Примечание по звуку. Данные звука - PCM unsigned 8bit.
Отфильтрованы значения 0x00 и заменены на 0x01.
Значение 0x00 используется как флаг "конец звука".
Думаю, вполне можно уместить эффект в 256 байт,
если картинку и палитру сгенерировать программно.
"Гипножаба" работает похожим образом:
основной цикл программно проигрывает звук на covox,
а в обработчике прерывания посредством DMA обновляется
часть экрана размером 112x48 пикселей
(пересылка "из RAM в RAM_с_Выравниванием_512").
http://rghost.ru/55036812/image.png
Пример с фреймовыми\строчными интами не хочешь покурить для тренировки?
line-ints.zip
скрин эффекта - внизу
Итак, что имеем в эффекте:
все строки изображения плавно перемещаются в горизонтальной плоскости по синусу.
за прерывание :v2_dizzy_coder:
изображение - 320х200, 16 цветов
некоторые части кода, связанные с синусом я пока не затрагиваю, интересен именно механизм прерываний.
Buyan обьяснит свой прикольный эффект немного позже и гораздо доступней, чем я сейчас ;)
Начнём. Сначала - уже знакомая по этой теме предварительная фаза: установка разрешения/цветности, скорости/кеша, выбор палитры, инициализация позиций окна вывода экрана, указание на место экрана в памяти.
здесь можно отметить две интересные подпрограммы - очистка экрана с помощью дма, и с его-же помощью перемещение графики на экран.
Скрытый текст
Код:device ZXSPECTRUM128
include dev\ts-ports.asm
org #8000
start di
ld sp,49151
ld a,128
call clear_vpage
call gfx_copy
call init_gfx
call init_zx_pal
call init_im2
ei
stop jp stop
init_gfx ld bc,VConfig
ld a,%10000001
out (c),a
ld bc,SysConfig
ld a,%00000111
out (c),a
ld bc,PalSel
ld a,%00000000
out (c),a
ld hl,0
ld bc,GYOffsL
out (c),l
ld bc,GYOffsH
out (c),h
ld bc,GXOffsL
out (c),l
ld bc,GXOffsH
out (c),h
ld bc,VPage
ld a,128
out (c),a
ret
[свернуть]
итак, инициализация прерывания.
читаем мануал:
"...В TS-Conf можно запрограммировать несколько источников маскируемого прерывания. Среди них:
- кадровый (frame, индекс 0),
- строчный (line, индекс 1),
- окончание DMA транзакции (dma, индекс 2).
Источник frame срабатывает, когда значение счетчиков растра совпадает с регистрами HSINT и VSINT. Источник line срабатывает в каждой строке, когда горизонтальный счетчик растра равен 0. Источник dma срабатывает после окончания любой транзакции DMA.
Каждый источник прерывания формирует сигнал ~INT и выставляет собственный байт D[7:0] на ШД в цикле ~IORQ || ~M1.
- $FF - кадровый,
- $FD - строчный,
- $FB - DMA."
здесь можно отметить установку горизонтального HSINT и вертикального VSINT прерывания (INT) в ноль - начало отрисовки экрана. замечаем, что адрес обработчика прерывания записывается в адрес #beff, что говорит о фреймовом вызове. ну типа каждый кадр. как обычно, в общем :)
после разрешения, и как начинаем отрисовывать экран с абсолютного 0,0 - происходит прерывание im_blank.
Скрытый текст
Код:init_im2 ld a,#be
ld i,a
ld hl,im_blank
ld (#beff),hl
ld bc,HSINT
ld a,0
out (c),a
ld hl,0
ld bc,VSINTL
out (c),l
ld bc,VSINTH
out (c),h
im 2
ret
init_zx_pal ld a,%00010000 ; маппинг на #0000 ; 0 - ZX palette
ld bc,FMAddr
out (c),a
ld hl,zx_palette
ld de,0
ld bc,32
ldir
xor a
ld bc,FMAddr
out (c),a
ret
zx_palette include "dev\zx_palette.asm"
im_blank di
push af
ex af,af
push af
push hl
push de
push bc
push ix
push iy
exx
push hl
push bc
push de
ld hl,30+24
ld bc,VSINTL
out (c),l
ld bc,VSINTH
out (c),h
ld hl,im_blank_off
ld (#beff),hl
ld de,(roll_beg)
ld (roll),de
inc de
ld a,d
and %00000001
ld d,a
ld (roll_beg),de
pop de
pop bc
pop hl
exx
pop iy
pop ix
pop bc
pop de
pop hl
pop af
ex af,af
pop af
ei
ret
frame_counter defw 0
flag defb 0
roll_beg defw 0
[свернуть]
по приходу im_blank в строчный регистр интов VSINT устанавливаются значения нового обработчика фреймовых прерываний,
которые будут вызваны по началу отрисовки строки 30+24 (54).
другими словами, пропуск отрисовки линий, ибо пока малюется бордюр.
следующий инт приходит на 54 строке экрана, и попадает в im_blank_off
Скрытый текст
Код:im_blank_off di
push af
push hl
push de
push bc
ld hl,31+24+240
ld bc,VSINTL
out (c),l
ld bc,VSINTH
out (c),h
ld hl,im_blank_on
ld (#beff),hl
ld bc,INTMask
ld a,%00000011
out (c),a
ld hl,line_proc
ld (#befd),hl
pop bc
pop de
pop hl
pop af
ei
ret
[свернуть]
указываем, что следующее прерывание должно возникнуть на строке 31+24+240 - а это у нас конец экрана и начало бордюра, и вызывать im_blank_on для фреймового int.
Разрешаем строчный инт - по строкам будет приходить прерывание на line_proc. Отмечаем, что строчный инт у нас пишется по #befd
RTFM: "Регистр конфигурации INTMask содержит биты разрешения индивидуального источника маскируемого прерывания, 0 - запрещен / 1 - разрешен.
бит 0, FRAME - разрешение источника frame,
бит 1, LINE - разрешение источника line,
бит 2, DMA - разрешение источника dma,
биты 3-7 - не используются, записывать 0."
Скрытый текст
Код:
im_blank_on di
push af
push hl
push de
push bc
ld hl,0
ld bc,VSINTL
out (c),l
ld bc,VSINTH
out (c),h
ld hl,im_blank
ld (#beff),hl
ld bc,INTMask
ld a,%00000001
out (c),a
pop bc
pop de
pop hl
pop af
ei
ret
[свернуть]
следующее прерывание пришло на im_blank_on. указываем приход нового фреймового с позиции 0 (новый кадр), вырубаем строчные инты - пропуск бордюра. и опять по кругу.
что же делают здесь строчные инты? КАЧАЮТ девочек :)
line_proc отрабатывает с позиции VSINT от 54 до 295 (область экрана) и бросает в порт GXOffs ("X-offset for graphics") сдвиг по х для текущей строки, взятой из текущего положения переменной roll, + sines_tab (которая указывают на таблицу синусов):
Скрытый текст
Код:line_proc di
push af
push hl
push de
push bc
ld de,(roll)
sin_tb ld hl,sines_tab
add hl,de
inc de
ld a,d
and %00000001
ld d,a
ld (roll),de
ld a,(hl)
ld bc,GXOffsL
out (c),a
pop bc
pop de
pop hl
pop af
ei
ret
roll defw 0
sines_tab include "\dev\sineline.asm"
[свернуть]
дма очистка и ldir на экран:
Скрытый текст
Код:clear_vpage push af
ld bc,Page0
ld a,33
out (c),a
ld hl,0
ld (0),hl
ld bc,DMASAddrX
ld a,33
out (c),a
ld hl,0
ld bc,DMASAddrH
out (c),h
ld bc,DMASAddrL
out (c),l
ld bc,DMADAddrX
pop af
out (c),a
ld hl,0
ld bc,DMADAddrH
out (c),h
ld bc,DMADAddrL
out (c),l
ld bc,DMALen
ld a,255
out (c),a
ld bc,DMANum
ld a,255
out (c),a
ld bc,DMACtrl
ld a,%00000100
out (c),a
ld bc,DMAStatus
c1rl1 in a,(c)
or a
jr nz,c1rl1
ret
Код:gfx_copy ld bc,DMASAddrX
ld a,100
out (c),a
ld hl,0
ld bc,DMASAddrH
out (c),h
ld bc,DMASAddrL
out (c),l
ld bc,DMADAddrX
ld a,128
out (c),a
ld hl,0
ld bc,DMADAddrH
out (c),h
ld bc,DMADAddrL
out (c),l
ld bc,DMALen
ld a,160/2-1
out (c),a
ld bc,DMANum
ld a,240-1
out (c),a
ld bc,DMACtrl
ld a,%00010001
out (c),a
ld bc,DMAStatus
s1cp1rl in a,(c)
or a
jr nz,s1cp1rl
ret
endcode nop
SAVEBIN "1-spg\line-ints.bin",start, endcode-start
[свернуть]
Другими словами, за один отрисованный экран было вызвано 3 фреймовых и -надцать строчных прерывания.
аминь :v2_dizzy_priest:
А вот слова автора эффекта, господина Buyan, который любезно предоставил исходники для разбора, ознакомления и изучения принципа работы системы прерываний:
"Такс.. Для начала по растру - у нас в кадре 320 строк. Это размеры видеосигнала с учетом всех бланков, синхр и тд, а не видимой части изображения. Видимых из них соответственно 288 (при максимальном разрешении). Т.е. строки 0-31 на экране мы не видим никогда. Остальные отображаются. Но как они отображаются (т.е. что там отображается - бордер или графика уже зависит от включенного разрешения. Т.е. при 360х288 все строки отображают графику, при 320х240 соответственно 240 строк графику, а остаточные строки сверху и снизу уйдут на бордер.
Теперь по интам: тут у нас есть фреймовый и строчный. Фреймовый инт приходит 1 раз в кадре (при условии что мы по ходу кадра его не перепрограммируем на другую позицию по ходу луча. Строчные же инты после включения будут срабатывать в начале каждой строки, т.е. до 320 раз за фрейм. Отсюда и пляшем:
В данном случае т.к. разрешение выбрано 320х240 нам нужно обработать соответственно 240 строк, ибо качать строки которые на экране не отображаются смысла нет. Для этого и используется несколько обработчиков инта последовательно:
Изначально у нас фреймовый инт настроен на 0 строку. Поехали:
im_blank - пришло прерывание в начале кадра. Тут проинитили синусоиду для качения, ну и как обычно на спеке музычку можно проиграть и т.д. Далее чтобы проц не дергать и невидимые строки не дрюкать переставляем фреймовый инт на im_blank_off - на 30 (неотображаемых) + 24 (бордер) т.е. попадем за 2 строки до начала отображаемых.
im_blank_off - вот мы уже на 30+24 строке и нам пора начать обрабатывать видимые 240 строк строчным интом. Но как нам оганичиться 240 строками если строчные инты долбят по всему диапазону строк? Просто: переставляем фреймовый инт на конец отображения наших 240 строк, т.е. на im_blank_on, который придет в 32(невидимые)+24(бордер)+240 наших качаемых строк и вырубит строчные инты. Переставили. Включаем строчные инты (line_proc)
line_proc вызывается в каждой следующей строке и изменяет ее смещение. Проходит 240 строк и тут срабатывает опять фреймовый инт, который мы перенастроили перед этим:
im_blank_on отрубаем строчный инт и перенастраиваем фреймовый на первый обработчик и начало следующего кадра. Зе енд."
:v2_dizzy_rastoman:
Все экземпляры Евы (вопреки тому, что трындит рупор), при условии прошивания сабжа в оные.
Медленно но верно портируется на Реверс U8, медленно потому что не в лоб, а допиливается, а процесс этот небыстрый. Потом портируем на U16, возможно на другие клоны. Например, она могла бы работать с некоторыми ограничениями v6z80p, если найдется смельчак, чтоб перетащить ее на Xilinx.
в пост MindWarp от DDp добавил описание работы эффекта от автора.
Спасибо ему :)
Есть такой прием, который называется "дрочка инта".
А как будет рендериться экран, если меняется вертикальное или горизонтальное положение тайлов?
denpopov, ты на сеге игры видел? :)
так же и будет
там каждую линию данные берутся
denpopov, как будет рендериться экран, если меняется вертикальное или горизонтальное положение тайлов ты можешь увидеть в инвитре, там такого море.
в моей части с синими шарами меняется положение тайлов на экране по синусу, всех сразу - и норм
насчёт "дрочка инта" :) в сонике за фрейм вызывается два инта, соответственно два хальта стоит) один инт - начало экрана, красный бордюр, второй инт - средина, белый.
всё