pop de
ld a,(hl)
or e
xor d
ld (hl),a
inc l/dec l/inc h/downhl
=36t/b = 108 t/line = 216 t/doubleline
можно средний байт выводить без маски (высоту спрайта мы знаем и лишнее не затрём), тогда 36+16+36 = 88 t/line = 176 t/doubleline (6+2.5+6)/3 < 5 b/b < 240 b одна выводилка, а надо 4 (фазы по Y)
итого 1408 t + обвязка

...

pop de
ld (hl),e
inc l
ld (hl),e
inc l
ld (hl),e
inc h
;------------
ld (hl),d
dec l
ld (hl),d
dec l
ld (hl),d
inc h/downhlattr
=76 t/2 doublelines = 38 t/doubleline (существенный выигрыш из-за линейности атрибутов хотя бы по одной оси)
(чтобы не считать адрес, можно начать с того адреса, где кончилась отрисовка пикселей, и пересчитать H)
итого 304 t + обвязка


вывод подготовленного прямоугольника 24x16:
pop de
ld (hl),e
inc l
ld (hl),d
inc l
pop de
ld (hl),e
inc h
ld (hl),d
dec l
pop de
ld (hl),e
dec l
ld (hl),d
inc h/downhl
(или по столбцам)
=16t/b (вдвое быстрее честного вывода спрайтов, но атрибуты как раньше) линейность по X тут не важна

подготовка прямоугольника 24x16:
;sp=gfx
;hl=scr
;de=out
pop bc
ld a,(hl)
or c
xor b
ld (de),a
inc l ;или inc h/downhl
inc e
...
=40t/b (медленнее, чем вывод на экран!) сделать в верхнем бордере? линейность по X тут не важна


или всё-таки можно упихать во фрейм больше?
как-то сэкономить на стирании некоторых спрайтов? тележек?
даже если нелинейные атрибуты (т.е. не теряем 32 строки):
8 строк - музыка и звуки
56 строк - отрисовка 6 спрайтов (nowait)
128 строк - мультиколор
56 строк - стирание 6 спрайтов (проблема, что пока ещё вайты)
32 строки - логика
16 строк - стирание 19 точек (nowait)
16 строк - движение + отрисовка 19 точек (nowait)

Примерный вывод спрайта с атрибутами, когда атрибуты нелинейны по X:
1. выводим спрайт (down micro dub)
	dup 8*(maxsprchrhgt+1)
	pop de
	ld a,(hl)
	or e
	xor d
	ld (hl),a
	 dec b
	 jr z... ;или патч выхода
	inc h
	edup
	down hl
;47t/b ;или 36t/b с патчем выхода (при линейном с безмасковым центром было 88 t/line = 29.3t/b)
(или 8 разных фаз down micro dub)
2. выводим атрибуты по столбцам
	pop de
	ld (hl),e
	add hl,bc
	ld (hl),d
	add hl,bc
;23t/b
(при отрисовке это невыгодно, т.к. один байт атрибута на всю строку спрайта - при линейном было 38 t/doubleline < 13t/b)


стирание спрайта должно восстанавливать цвет фона откуда-то (каждый байт отдельно)! допустим, что это так же быстро, как вывод атрибутов.
а стирание пикселей должно восстанавливать сам фон откуда-то! допустим, что это так же быстро, как вывод пикселей.

в Rick Dangerous бывает больше 4 больших спрайтов (например: персонаж, два врага, две тележки, мина)
сделать за 3 фрейма? в первых 2 фреймах готовим прямоугольники на вывод, в 3-ем выводим?


что делать при спрайтах разной высоты? (например, ползание и платформы - там нельзя выводить центр без маски)
сделать вместо 6 спрайтов 18x16 - 12 спрайтов 18x8?
надо посчитать обвязки входа в спрайт, атрибуты, стиралку спрайта и стиралку атрибутов

/*если бы вывод атрибутов был сгенерированной процедурой (но тогда ей нужен честный downhl): главные 2 атрибута держать в bc (+10t)? они в сумме должны составлять ровно половину спрайта (это можно использовать и для быстрой перекраски врагов)?*/
/*если адрес атрибутов вычислять (+19-18), а потом делать inc l (на нужной фазе) - для этого надо выход на вывод атрибутов через inc l:jp (+14), проигрыш*/

Если атрибуты линейны, то примерно такое использование времени:
16 строк - музыка, звуковые эффекты
32 строки - патч атрибутов
16 строк - рисование 19 точек для взрыва и выстрелов
128 строк - мультиколор
16 строк - стирание 19 точек для взрыва и выстрелов
36 строк - стирание 4 спрайтов 18x16
32 строк - логика
36 строк - рисование 4 спрайтов 18x16


если найдётся линейный мультиколор, использующий 16 (а не 32) строк предзаливки:
отрисовка = 176+38 t/doubleline (10272 t = 46 строк на 6 спрайтов)
стирание = 16+16 t/b (9216 t = 42 строки на 6 спрайтов)
совсем нелинейно - неудобно искать адреса атрибутов при отрисовке точек, стирании точек, отрисовке спрайтов и стирании спрайтов

16 строк - предзаливка атрибутов
48 строк - отрисовка 6 спрайтов (nowait)
128 строк - мультиколор
8 строк - музыка и звуки (128K only)
16 строк - стирание 19 точек (надо до стирания спрайтов, т.е. восстановления тайлов. проблема, что пока ещё вайты)
48 строк - стирание 6 спрайтов (проблема, что пока ещё вайты)
32 строки - логика
16 строк - движение + отрисовка 19 точек (nowait)


При нелинейности по X можно убрать карту атрибутов, но желательно добавить буфер выводимых прямоугольников


мультиколор - это явно не pop hl:ld (),hl, т.к. будет излом. Надо использовать ld sp,:pop...:push...
Это значит, что по-любому надо переставлять стек. То есть атрибуты можно зациклить, если у нас в верхнем бордере будет фиксированная процедура патчинга стека и jp, а между строками будет jp и ld sp. Но тогда вообще нельзя использовать ld (),hl (или его тоже надо патчить в верхнем бордере).
при ширине 32 знакоместа у нас только 5 тактов между строками (4 шт. ld (),hl, предзаливка верхнего ряда), нельзя вставить jp, так что надо 30 знакомест (3 шт. ld (),hl, без предзаливки)


графический движок не думает о луче, просто стирает все спрайты, логика (там же опрос клавиатуры, т.к. бывают с вайтами?), рисует все спрайты

/*        macro DOWNHL8ATTR
        inc h
	ld a,l ;нужно только в первом downhl8attr
	add a,32
	ld l,a
        jp nc,$+ ;not fixed!!! нельзя использовать в верхнем бордере!
        ld h,b
        endm ;по идее 29+4/8, но только для первого downhl8attr
*/

[можно вычислять параметры спрайтов в обработчике прерываний, но 25 фпс - но зачем тогда выводить спрайты каждый фрейм? мерцать-то так нельзя, и памяти не хватит на 48К]


        ld l,(ix+) ;
        ld h,(ix+) ;hl=gfxdescraddr+3 ;все дескрипторы спрайтов чётные
;x=0:        
        dec l
        dec hl
        ld d,(hl)
        dec l
        ld e,(hl)
;x=2:
        ld d,(hl)
        dec l
        ld e,(hl)
;x=4:
        inc hl
        ld e,(hl)
        inc l
        ld d,(hl)
;x=6:
        inc hl
        inc l
        inc hl
        ld e,(hl)
        inc l
        ld d,(hl)

/*
;CY=0
        ld hl,() ;l=gfxdescraddrLSB, h=x/2 ;на каждую фазу X 3 байта: gfx16, pg, хотя по идее pg должны быть общие
        ld a,h ;x/2
        rra
        rl l
        rra ;CY=x&4
        rl l
        ld h,gfxdescr/256
;51
        ld e,(hl)
        inc h
        ld d,(hl)
        push de ;gfx
        inc h
        ld d,(hl) ;pg
;40
;a=x/8
        ld hl,() ;y
        ld h,tytoscr/256
        add a,(hl)
        inc h
        ld h,(hl)
        ld l,a ;hl=scr
        push hl ;scr
;56
        ld a,h ;scrH
        and 6 ;scrH&6
        add a,prspr/256 ;ветвление по x&4 будет уже в самом prspr
        ld e,a ;f(yphase)
        push de ;f(yphase),pg
;33
;180t/спрайт (можно две константы в bc, тогда 174t/спрайт = 1392t = >6 строк)
;можно or 0b11111001:add a,prspr/256+7=tytoscr/256 (общая константа), тогда 171t/спрайт, но CY=1!!! это надо учесть в tytoscr
*/

/*
        exx
        add hl,de
        ld sp,hl
        exx
         pop iy ;restorer_tile2 ;только первый раз? ;реально повторяется 3 раза для пикселей и 2 раза для атрибутов
         pop ix ;restorer_tile1 ;только первый раз? ;реально повторяется 3 раза для пикселей и 2 раза для атрибутов
        pop bc ;scr
        pop hl ;tilegfx_tile1
        pop de ;tilegfx_tile2
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix)
;8 входов в одно и то же (не от начала знакоместа/тайла)
        dup 1..8
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8
        edup
        ex de,hl
        ld sp,hl ;tilegfx
        ex de,hl
        jp (iy)
        ...
;8 разных веток (не до конца знакоместа/тайла)
        dup 1..8
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8/-
        edup
;опять читаем из стека...
;и так 3 раза
;но на входе в восстановитель атрибутов нужен уже новый ix!
;а на выходе новый iy!
;если ради этого выигрыша 14*2*2=56t сделать отдельный псевдопроход, то проиграем
;8 разных веток специально для выхода из графики в атрибуты - жирно
*/
/*         pop de
         out (c),d ;pg
         ld a,e ;f(yphase)
        exx
        pop de ;scr
        pop hl ;gfx
        ld sp,hl
        pop hl ;l = f(hgt, x&4)
        ld h,a
        jp (hl)
        ...
        jp[x<4]/inc hl...inc l[x>=4]
        ...
        ex de,hl
*/ ;но нельзя портить de'!!!!!!!!!!!!!!!!

TODO сгенерить патчи:
... ;a=f1(spry)
ld (),a ;вход для верхнего неполного столбца (используется 3 раза)
... ;a=f2(spry) - можно одинаковые f1,f2 (ровное число байт на ветку, не более 42, иначе надо jp, будет 0x600 байт на стиралки)
ld (),a ;вход для нижнего неполного столбца (используется 3 раза)
или пропатчить каждый в 3 местах, чтобы не делать условные выходы из стирания столбца тайла

стираем снизу вверх

нижний неполный столбец:
;sp=адрес тайла (как посчитать? тайл = 32+16 байт)
jr/jp ... ;вход в разные места одной ветки (или 4 разных ветки с пустыми pop, чтобы начать всегда с начала тайла - как выгоднее?)
dup 4
pop bc
ld (hl),c
dec h
ld (hl),b
dec h/uphl8/-
edup
 or a ;т.к. после uphl8 CY не определён
ld a,h
rra ;CY=0
add a,attrs/256 - 0x40
ld h,a
pop bc*0..3
dup 1..4
pop bc
ld (hl),c
inc h
ld (hl),b
inc h/downhl8attr/-
edup

jp ;теперь hl=низ спрайта в атрибутах (не ровно знакоместо)
...
;надо восстановить hl для следующего куска столбца и сделать uphl8

средний полный столбец:
???

верхний неполный столбец:
;sp=адрес тайла (как посчитать? тайл = 32+16 байт)
jr/jp ... ;4 разных ветки
dup 1..4
pop bc
ld (hl),c
dec h
ld (hl),b
dec h/uphl8/-
edup
 or a ;т.к. после uphl8 CY не определён
ld a,h
rra ;CY=0
add a,attrs/256 - 0x40
ld h,a
pop bc*0..3
dup 1..4
pop bc
ld (hl),c
inc h
ld (hl),b
inc h/downhl8attr/-
edup
jp ;теперь hl=верх знакоместа в атрибутах


/*
для каждого из 3 столбцов:
- адрес тайла
- scr
- адрес входа в стиратель (с атрибутами?)
- адрес тайла
- scr
- адрес входа в стиратель (с атрибутами?)
[- адрес тайла
- scr
- адрес входа в стиратель (с атрибутами?)] если требуется по высоте и положению спрайта
для этого надо перестановку стека после каждого знакоместа
        exx
        add hl,de
        ld sp,hl
        exx ;25
*/

/*
;если сколько угодно тайлов:
        ld e,(iy)
        ld d,(iy+32)
        push de ;tilegfx_tile2
        ld e,(iy+64)
        ld d,(iy+64+32)
        push de ;tilegfx_tile1 ;98t
        push bc ;scr
        push ix ;restorer_tile1
        inc c ;scr
;если 64 тайла:
        ld e,(hl)
        push de
        ld a,l
        add a,32
        ld l,a
        ld e,(hl)
        push de ;51t + (2*2*11t) = 95t
        push bc ;scr
        push ix ;restorer_tile1
        inc c ;scr
*/
;если tilemap = 512 bytes (строка = 64)
        and 0b11011111 ;tilehgt=16
        ld l,a
        ld a,b
        cp 0x48
        sbc a,a ;-1=верхняя треть, 0=нижняя треть
        add a,tilemap/256+1
        ld h,a ;37t
;но так нельзя шагать через add a,32:ld l,a - только через add hl,bc (нет свободного регистра) или (ix) (+8t уже здесь - сразу проигрыш)

/*
        ld e,(hl)
        add a,32
        ld l,a
        ld d,(hl)
        push de
;36t + (2*2*11t) = 80t
        ld b,???
        push bc ;scr
        push ix ;restorer_tile1
;33 = +3t
;0t + (2*11t) = 22t
        ld b,???
        push bc ;attr
        inc c ;scr
        push iy ;restorer_tile1attr
        inc l
;41 = +8t
;невыгодно и непонятно, как присваивать b
*/

;можно ли выиграть без exx???
;если при этом не сохранять restorer_tile1attr, то:
        ld e,(hl)
        add a,32
        ld l,a
        ld d,(hl)
        push de
;36t + (2*2*11t) = 80t
        push bc ;scr
        push ix ;restorer_tile1
;26 = -4t
;0t + (2*11t) = 22t
        ld ly,c
        push iy ;attr
        inc c ;scr
        inc l
;31 = -3t
;но мы можем и так не класть, так что тут тоже проигрыш
        
;если чередовать attr/gfx (именно в этом порядке), то можно добавить 0..4 pop hl, чтобы не читать адрес графики??? столбец будет такой: attr1,gfx1,attr2,gfx2 - но откуда брать адрес экрана?



genprsprscript0
;CY=0
        ld a,(ix+) ;x/2
        rra
        jr c, ;среднее = 32.5t
        rra ;/srl a
        jr c, ;среднее = 15.5t
;мы в конкретном x&6 (можно перенести перед вычислением scr)
        ld h,(ix+) ;h=gfxdescraddrHSB ;все дескрипторы спрайтов делятся на 16 (на каждую фазу X 4 байта: gfx16, pg, hgt, хотя по идее hgt и pg должны быть общие)
;этот блок в среднем 67t
        
;у нас всего примерно 44 спрайта (16192 байта при высоте 18, считая с prattraddr), их дескрипторы займут 704 b
;на 128K больше, но не на порядок.
;x=0:
        ld l,(ix+)
;x=2:
        ld l,(ix+)
        set 2,l
;x=4:
        ld l,(ix+)
        set 3,l
;x=6:
        ld l,(ix+)
        set 2,l
        set 3,l
;среднее = 24t

        ld e,(hl)
        inc l
        ld d,(hl)
        push de ;gfx
        inc l
        ld d,(hl)
        inc l
        ld e,(hl) ;f(sprhgt)=g(gfxdescaddr) ;можно =sprhgt/2*3 (а там jp prsprpause)
;62
;a=x/8
        ld l,(ix+) ;y
        ld h,tytoscr/256
        add a,(hl)
        inc h
        ld h,(hl)
        ld l,a ;hl=scr
        push hl ;scr
        push de ;pg
;59
        ld a,h ;scrH
        and 6 ;scrH&6
        add a,prspr/256[+1] ;для (x&4)!=0
        ld d,a ;f1(y&3,x&4)
        push de ;prsprproc ;записывается в стек последняя, считывается из стека первая
;33
        add ix,bc
        dec ly
        jp nz,genprsprscript0
;33
;итого 278t/спрайт = 2224t (10 строк)
;надо как-то оптимизировать случаи, когда меньше 8 спрайтов?

;если хранить дескрипторы вертикально (читать только gfxdescrLSB), то -17t/спрайт
;если без ветвлений, то (rra:rl l:rra:rl l), то ещё -5t/спрайт (итого -22t/спрайт)
;если tytoscr лежит после дескрипторов, то ещё -3t/спрайт (итого -25t/спрайт)
;если раскрыть цикл (не трогая ix+), то ещё -19t/спрайт (итого -44t/спрайт)
;если после этого раскрытия убрать ix, то ещё -32t/спрайт (tytoscr после дескрипторов не получается использовать) (итого -76t/спрайт = 202t/спрайт)
;без ветвлений ПРОБЛЕМА с расчётом prspr/256[+1]


;пусть тайлы высотой 16, тогда восстановитель столбца состоит из 2 частей
;ширина тайла 8 или 16? как удобнее генератору?
;в стеке будут лежать готовые патчи, адреса и входы:
;атрибуты (2 раза):
        pop ix ;restorer_tile1attr
         pop iy ;restorer_tile2attr
        pop bc ;attr
        pop hl ;tileattr_tile1
        pop de ;tileattr_tile2
        ...
;пиксели (3 раза):
        pop ix ;restorer_tile1
         pop iy ;restorer_tile2
        pop bc ;scr
        pop hl ;tilegfx_tile1
        pop de ;tilegfx_tile2
;и так 8 спрайтов
;выход:
        resprq
        0
        0
        0
        0

        
;sprhgt достать сложно, он в sprgfx - всё делаем высотой 18? тогда не нужно iy

;d'=b'=tilegfx/256
;h'=tilemap/256
;d=restorer/256

        ld hl,() ;l=y ;h=gfxdescraddrLSB ;на каждую фазу X 3 байта: gfx16, pg, хотя по идее pg должны быть общие
;restorer = f(yphase) = f1(scryphase) (8 веток, в сумме порядка 400 байт) - читать из какой-то таблицы? или ветвление тут (больше 70t)? или красивая адресация + [jp] (<3*10t в восстановителе)?
        ld a,l
        and 7 ;yphase
        add a,a
        add a,a
        ld e,a ;restorer
;36
        ld a,() ;x/2
        rra
        rra
         jr c,genrestore_left ;33
genrestore_right ;эта ветка -5(nojr)+10(jp) = +5
        ...
        jp ...
genrestore_left ;эта ветка +8(dec:dec) = +8 (среднее по веткам = +6.5)
;a=x/8 + 0x80
;l=y
        ld h,tytoscr/256
        add a,(hl)
        inc h
        ld b,(hl)
        ld c,a ;bc=scr
;29
;если tilemap = 256 bytes (строка = 32)
        add a,a
        rla
        rla ;0bxxxxx0yy
        rrca
        rrca ;0byyxxxxx0
        bit 3,b
        jr z,$+3
        inc a
        rrca ;43.5t
        exx
        ld l,a
;51.5

   ;;;;;;;; этот блок
;d=b=tilegfx/256/4
;h=tilemap/256
;tile1,tile2 = f(tilemapaddr)
;один тайл 8x16 занимает 16 байт линейно (пиксели) + 8 байт линейно (атрибуты)
;сколько разных тайлов? явно больше 16 (если 64, то можно сделать пересчёт через 2*add hl,hl в самом восстановителе (+2*2*11t))
;сколько байт в ячейке tilemap и как они разложены в памяти?
;если 64 тайла (1.5K графики тайлов, почти как 128 тайлов на NES):
;(64 левых + 64 правых добавит 7+7t: pushde..pushde ..... pushbc..pushbc ..... pushde..pushde, но надо ветвиться по x&8!!!)
;(если ветвиться по x&8, то можно сделать 64 левых + 64 правых через inc d:pushde..pushde:dec d в среднем ряду)
        ld e,(hl)
        add a,32
        ld l,a
        ld c,(hl)
        push de
        push bc
;47t + (2*2*11t) = 91t
        exx
        push bc ;scr
        push de ;restorer_tile1
        inc c ;scr
        exx
        inc l
;38
        ld c,(hl)
        sub 32
        ld l,a
        ld e,(hl)
        push de
        push bc
;47t + (2*2*11t) = 91t
        exx
        push bc ;scr
        push de ;restorer_tile1
        inc c ;scr
        exx
        inc l
;38
        ld e,(hl)
        add a,32
        ld l,a
        ld c,(hl)
        push de
        push bc
;47t + (2*2*11t) = 91t
        exx
        push bc ;scr
        push de ;restorer_tile1
;26
;теперь атрибуты:
;пусть ветка (x&4)!=0, т.е. восстанавливаем правые атрибуты (для левой ветки надо dec c:dec l' = +8t)
;для атрибутов придётся делать столько же add hl,hl, как и для пикселей! ибо вход у них общий
        ld a,b
        rra
        add a,attr/256 - 0x40
        ld b,a
        inc d ;restorer_tile1attr
        exx
         ld b,tileattr/256/4
         ld d,b
;38
        ld c,(hl)
        sub 32
        ld l,a
        ld e,(hl)
        push de
        push bc
;47t + (2*2*11t) = 91t
        exx
        push bc ;attr
        push de ;restorer_tile1attr
        dec c ;attr
        exx
        dec l
;38
        ld e,(hl)
        add a,32
        ld l,a
        ld c,(hl)
        push de
        push bc
;47t + (2*2*11t) = 91t
        exx
        push bc ;attr
        push de ;restorer_tile1attr
        dec d ;restorer_tile1
;30        
     ;;;;; этот блок = 443t
;=566t/спрайт (не считая add hl,hl)
;реально +11, чтобы вернуть tilegfx/256/4



        pop ix ;restorer_tile1attr
         ;pop iy ;restorer_tile2attr
        pop bc ;attr
        pop hl ;tileattr_tile1
        pop de ;tileattr_tile2
         add hl,hl
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix)
        ...
;8 входов в одно и то же (не от начала знакоместа/тайла) (реально надо копии, т.к. вход в середину слова)
        dup 1..4
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8attr
        edup ;5..20 bytes
        ex de,hl
         add hl,hl
         add hl,hl
        ld sp,hl ;tileattr
        ex de,hl
         ;jp (iy) ;можно убрать (приклеить), если всё восстанавливать высотой 18 - будет всего порядка 200 байт на все ветки)
        ...
;8 разных веток (не до конца знакоместа/тайла)
        dup 1..4
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8attr/-
        edup ;5..20 bytes
;
        exx
        add hl,de
        ld sp,hl
        exx
        pop ix ;restorer_tile1attr / restorer_tile1
         ;pop iy ;restorer_tile2attr / restorer_tile2
        pop bc ;attr / scr
        pop hl ;tileattr_tile1 / tilegfx_tile1
        pop de ;tileattr_tile2 / tilegfx_tile2
         add hl,hl
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix) ;этот фрагмент = 105t (91 без iy)
        ...
;8 входов в одно и то же (не от начала знакоместа/тайла)
        dup 1..8
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8
        edup ;10..40 bytes
        ex de,hl
         add hl,hl
         add hl,hl
        ld sp,hl ;tilegfx
        ex de,hl
         ;jp (iy) ;можно убрать (приклеить), если всё восстанавливать высотой 18 - будет всего порядка 400 байт на все ветки)
        ...
;8 разных веток (не до конца знакоместа/тайла)
        dup 1..8
        pop bc
        ld (hl),c
        dec h
        ld (hl),b
        dec h/uphl8/-
        edup ;10..40 bytes
        exx
        add hl,de
        ld sp,hl
        exx
        pop ix ;restorer_tile1 / restorer_tile1attr / resprq
         ;pop iy ;restorer_tile2 / restorer_tile2attr
        pop bc ;scr / attr
        pop hl ;tilegfx_tile1 / tileattr_tile1
        pop de ;tilegfx_tile2 / tileattr_tile2
         add hl,hl
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix)

        
        
        
        pop ix ;restorer_tile1
        pop bc ;scr
        pop hl ;tilegfx_tile1
        pop de ;tilegfx_tile2
         add hl,hl
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix)
        ...
        <draw>
        ex de,hl
         add hl,hl
         add hl,hl
        ld sp,hl ;tilegfx_tile2
        ex de,hl
        <draw>
         ;;; с этого момента надо уметь скипать атрибуты
        pop ix ;restorer_tile1attr / resprq
        pop bc ;attr
        pop hl ;tileattr_tile1
        pop de ;tileattr_tile2
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=attr
        jp (ix)
        ...
        <draw>
        ex de,hl
         add hl,hl
        ld sp,hl ;tileattr_tile2
        ex de,hl
        <draw>
         ;;; выход из скипа атрибутов
        pop ix ;restorer_tile1
        pop bc ;scr
        pop hl ;tilegfx_tile1
        pop de ;tilegfx_tile2
         add hl,hl
         add hl,hl
        ld sp,hl
        ld h,b
        ld l,c ;hl=scr
        jp (ix)
;A используется только в uphl8, uphl8attr
;в D можно хранить tilegfx/256/4??? экономия 22 такта на генераторе каждого входа, но сколько проиграем тут?



/*
;то же с атрибутами:
        pop ix ;restorer_tile1attr / resprq ;ПРОБЛЕМА!!! в конце спрайта надо переходить не к атрибутам, а к пикселям!!!
        pop de ;attr
        ;pop bc ;tileattr_tile1,tile2 (LSB) ;можно не читать???
       ld l,c
       ld h,tileattr/256/4
         add hl,hl
        ld sp,hl
        ex de,hl ;hl=attr
        jp (ix)
*/
        
если бы restorer_tile1attr всегда зависел от restorer_tile1, то можно было бы не писать его в стек и не читать (выигрыш 11(+3)+14+8 = 36t), решилась бы проблема
но для этого надо отдельные ветки (все 8!) для restorer_tile1 без атрибутов и переприсваивание в генераторе
или как-то можно сделать проверку в самом восстановителе?
например, первый вход спрайта - без атрибутов
как мы это узнаем? у нас только scr(не содержит этой информации), restorer(const), tilegfx(не содержит этой информации)
иметь собственный счётчик троек?
        ex af,af' ;a=85
        add a,85 ;170,255,84(skip),169,254,8(skip)...
        jr c,skip ;+22 skip (там тоже ex af,af')
        ex af,af' ;+22 noskip

        
итого выводилка спрайта должна быть такая:
        ld sp,gfx ;10
        ld hl,scr ;10
        POPAND_AND_POPAND_RIGHT ;86
        AOR_AOR_AOR_LEFT ;108
        AOR_AOR_AOR_RIGHT ;108
        AOR_AOR_AOR_LEFT ;108
        AOR_AOR_AOR_RIGHT ;108
        AOR_AOR_AOR_LEFT ;108
        AOR_AOR_AOR_RIGHT ;108
        AOR_LD_AOR_LEFT ;

        AOR_LD_AOR_RIGHT
        AOR_LD_AOR_LEFT
        AOR_LD_AOR_RIGHT
        AOR_LD_AOR_LEFT
        AOR_LD_AOR_RIGHT
        AOR_LD_AOR_LEFT
        AOR_LD_AOR_RIGHT
        AOR_LD_AOR_LEFT
        ld hl,attr
        ...
        jp nextspr
если после вывода спрайтов идёт синхронизатор на 8 строк, то есть ещё некоторое количество тактов (синхронизатор работает на правой границе экрана)
главное, чтобы в синхронизаторе уместился плейер AY (запись в регистры - contended!?)

каждый лишний центральный байт с маской (вместо ld (hl)) добавляет 20 t, а для платформы/ползания надо добавить как минимум 7 лишних (если у платформы будет высота с маской 9, а не 8)
но в верхней строке всегда маски без xor, там выигрываем 9*3 t, то есть всего 140-27 = 113 лишних тактов на спрайт
- inch в конце + 2*downhl + ld:ld + ret(как он будет выглядеть? jp по цепочке?)


в конце каждой выводилки ld sp,ix:pop ix (24t)...
или:
         exx       ;
         add hl,de ;кроме первого входа
        ld sp,hl
        exx ;25t, зато не надо класть в стек лишнее слово
        pop de ;scr
         pop bc ;attr
        pop hl ;gfx/attrgfx
        pop ix ;prsprproc ;H=yphase, L=f(sprhgt)
        pop iy ;prattrproc
        ld sp,hl
        ex de,hl
        jp (ix) ;в середину процедуры prspr ;а там нельзя сделать ld sp,hl
        ...
         ld h,b
         ld l,c
        ;ld a,h
        ;rra
        ;add a,attr/256 - 0x40
        ;ld h,a
        ;nop/inc l - так не получается одна выводилка для всех фаз X!!!
        jp (iy) ;в середину процедуры prattr
;[91+4+27 = 122t на каждый спрайт = 976 на 8 спрайтов + 91 в конце]
;101+16 = 117t на каждый спрайт = 936 на 8 спрайтов +101 в конце -15(exx:add hl,bc) в начале
;сам вывод спрайта (симметричный) = 176*8 + 34(downhl8)*2 - 4(последний inch) = 1482
;сам вывод атрибутов (POPLDr_LDld) = 36*8 + 34(downhl8)*2 - 4(последний inch) = 352
;итого на 8 спрайтов: 8*(1482+352) + 936+101-15 = 15694 (>70 lines!!!)
надо не более 14300 (даже с заходом в contention 64-й строки, что надо очень осторожно, иначе синхронизатор не сработает)!!!
1394t лишних = 174.25t на каждый спрайт
заменяем верхнюю строку спрайта с POPAORr_POPLDr_APOPORd на POPAr_LDr_APOPd - выигрыш 18t на спрайт (итого 144) - мало!

высота спрайта известна по адресу спрайта
/*
высота и фаза атрибутов известна по адресу спрайта, т.е. можно читать выход в отрисовщик атрибутов прямо из графики спрайта:
         exx       ;
         add hl,de ;кроме первого входа
        ld sp,hl
        exx
        pop de ;scr
         pop bc ;attr
        pop hl ;gfx
        pop ix ;prsprproc ;H=yphase, L=f(sprhgt)
        ld sp,hl
        ex de,hl
        jp (ix) ;в середину процедуры prspr
        ...
         ld h,b
         ld l,c
        ret ;в середину процедуры prattr ;А ОТКУДА ГРАФИКЕ СПРАЙТА ИЗВЕСТНА ФАЗА Y???
;87+18 = 105t на каждый спрайт = 840 на 8 спрайтов +87 в конце -15(exx:add hl,bc) в начале = 912
;итого на 8 спрайтов: 8*(1482+352) + 912 = 15584 (>69 lines!!!)
232 b/фаза
-1 (последний inch)
+2*9 (downhl8)
+4 (ld:jp)
=253 b/фаза при высоте 16
*/

1284t лишних
заменяем верхнюю строку спрайта с POPAORr_POPLDr_APOPORd на POPAr_LDr_APOPd - выигрыш 18t на спрайт (итого 144) - мало!
заменяем прямой вывод атрибутов на зигзаг (т.е. два набора процедур) - выигрыш 32t на спрайт (итого 256) - мало!
884t лишних (110.5 t/спрайт)
строки атрибутов залиты одним атрибутом - выигрыш 40t на спрайт (итого 320) - мало!
564t лишних
пусть вывод спрайтов несимметричный (2(X)*4(Y) процедур = 0x800 в slowmem, так можно и вычислять адрес атрибутов с проигрышем +5t, можно без проигрыша, если фазы с прозрачной левой границей рисовать справа налево + иметь версию отрисовки атрибутов справа налево + условный inc:inc в генераторе скрипта спрайтов):
	POPAORr_POPLDr_LDd ;36+21+11=68
	POPLDl_LDl_POPAORd ;68
;1088+34*2-4 = 1152
;итого на 8 спрайтов: 8*(1152+352) + 912 = 12944 (1356 свободно) при полноценных атрибутах, даже без зигзага

для этого надо врехнее знакоместо использовать для синхронизации мультиколора (а на пентагоне сделать мультиколор нечувствительный к ошибке 0..+23)
это 4 пиксельных строки, которые добавляют задержку +6, если мы не в правом бордере
реально 8 пиксельных строк, потому что можем случайно попасть в nowait
эти 8 строк было бы интересно совместить с выводом в AY


prsprpause
        exx
        dec sp
        dec sp
        pop hl ;l=sprhgt/2*3
        ld a,l
        ld l,prsprhgt18&0xff
        ld e,0*7+4
        cp 3*9
        jp z,prsprpauseq
        nop
        ld l,prsprhgt16&0xff
        ld e,1*7+4
        cp 3*8
        jp z,prsprpauseq ;extra pause 168-35=133=7*19t
        ...
prsprpauseq
        ld (prsprpause_jp),hl
;pause 168-22(decpop)-35(cpjp)-16(ld)-10(jp) = 85
        ret c
        dec e
        jp nz,$-2 ;19t loop
        inc l
        ret c
;
        pop de
        pop hl
        ld sp,hl
        ex de,hl
prsprpause_jp=$+1
        jp 0

        
вывод атрибутов зигзагом: (POPLDr_LDd:POPLDl_LDd) = 32t*9 +...; 5b*9-1(последний inch)+2*9(downhl8)+13(pop:jp) = 75b, таких надо 2(X)*4(Y) = 8 процедур
в нечётные процедуры надо входить с предварительным inc l:pop de:jp (в счёт паузы), но если снизу вверх, то не надо

;вход в низкие спрайты через процедуру паузы (должны быть паузы на все высоты и фазы, чтобы не было лишних данных в стеке)
;задержки надо с учётом рисования атрибутов, т.е. по 68*2+32 = 168 (атрибуты зигзагом)
;нельзя call! можно ld hl:jp pauseN...jp(hl)
hgt18
        exx
        pop de
        pop hl
        ld sp,hl
        ex de,hl
        ... ;дальше сам вывод спрайта
;4 b
hgt16
        ld de,...:jp pause2 ;pause 168*1-48 +ld hx,d:ld lx,e:exx:pop de:pop hl:ld sp,hl:ex de,hl:jp (ix)
        ;pop de
        ;pop hl
        ;ld sp,hl
        ;ex de,hl
        ;jp ...
;[13]6 b
hgt14
        ld de,...:jp pause4 ;pause 168*2-48 +
;6 b
hgt12
        ld de,...:jp pause6 ;pause 168*3-48 +
;6 b
hgt10
        ld de,...:jp pause8 ;pause 168*4-48 +
;6 b
hgt8
        ld de,...:jp pause10 ;pause 168*5-48 +
;6 b
hgt6
        ld de,...:jp pause12 ;pause 168*6-48 +
;6 b
hgt4
        ld de,...:jp pause14 ;pause 168*7-48 +
;6 b
hgt2
        ld de,...:jp pause16 ;pause 168*8-48 +
;6 b
;итого дополнительно 52 b, а у нас только 34 b - придётся убрать 3 наименьших высоты
или убрать 2 наименьших высоты, будет ld e вместо ld de (5 b/высоту), тогда пауза будет начинаться так: dec sp:dec sp:pop hl:ld d,h
или все высоты по 2 b, если jp (iy) вместо ld de,...:jp ..., а там проверка
или все высоты по 3 b, если везде jp prsprpause (нельзя её класть прямо в стек, т.к. в стеке адрес с учётом фазы x,y и высоты!)
можно даже высоту 0 для мигающих спрайтов, только надо гарантировать CY=0 для последующего вычисления адреса атрибутов! (или не важно, атрибуты тоже высотой 0)










;с зигзагом с графике спрайта
        macro POPAORr_POPLDr_LDu ;68t
        pop de
        ld a,(hl)
        and e
        or d
        ld (hl),a
        inc l
        pop de
        ld (hl),e
        inc l
        ld (hl),d
        dec h
        endm

        macro POPLDl_LDl_POPAORu ;68t
        pop de
        ld (hl),e
        dec l
        ld (hl),d
        dec l
        pop de
        ld a,(hl)
        and e
        or d
        ld (hl),a
        dec h
        endm

;без зигзага в графике атрибутов спрайта
        macro POPLDr_LDd
        pop de
        ld (hl),e
        inc l
        ld (hl),d
        inc h
        endm
        
        macro POPLDl_LDd
        pop de
        ld (hl),d
        dec l
        ld (hl),e
        inc h
        endm
        
	macro UPHL8
        org $-1
	ld a,l
	sub c ;32
	ld l,a ;CY=previous third
	sbc a,a ;0 = this third, ff = previous third
	or b ;7 ;+7 = this third, -1 = previous third
	add a,h
	ld h,a ;+7/-1
	endm ;28t (+24 по сравнению с inc h) ;CY не определён!!! но при выводе в следующей строчке будет and:or (CY=0), проблема только в стирании

        macro DOWNHL8ATTR
        org $-1
;hl = 0b?????4yy YYYxxxxx
;hl = 0b?????411 YYYxxxxx
;out: 0b?????500 ZZZxxxxx
        ld a,l
        add a,c ;32
        ld l,a ;CY=next third
        sbc a,a ;0 = this third, ff = next third
        and b ;7
        or h
        and 0xfc
         ;sbc a,a ;0 = this third, ff = next third
         ;and 4
         ;sub 3
         ;add a,h
	ld h,a ;-3/+1 ;если бы экран был с 0-й строки, то реально всего 2 результата h: верхняя половина экрана или нижняя половина экрана (адреса отличаются на 4), а с синхронизатором надо ещё и атрибуты длиной 0xc00 вместо 0x800!!!
        endm ;35t (+31 по сравнению с inc h) ;CY=0

        ;inc h
        ;ld a,l
        ;sub -32
        ;ld l,a ;NC=next third
        ;sbc a,a ;0 = this third, ff = next third
        ;and -4
        ;add a,h
	;ld h,a ;-3/+1
;38t
        
        if 1==0
        
        align 256
prspr_y7_x0
        ;exx
        ;pop de ;scr
        ;pop hl ;gfx
        ;ld sp,hl
        ex de,hl ;34
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
        UPHL8 ;24
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
        UPHL8 ;24
	POPAORr_POPLDr_LDu ;68
	POPLDl_LDl_POPAORu ;68
        org $-1 ;-4
         ;ld a,h ;CY=0 после and:or
         ;rra
         ;add a,attr_/256 - (0x40/2)
         ;ld h,a
        scf:rr h ;для attr=0xa000
        ;nop ;inc l для (x&4)!=0
        ret ;в середину prattr ;33 ;sum = 34+(68*18)+(24*2)-4+33 = 1335, ...-30-4+10 = 1311
;надо перейти на свою (Y) процедуру вывода атрибутов для заданной высоты!!! высота хранится в спрайте, а Y известен только здесь!!!
        ;;ld hx,a ;f(yphase)
        ;;...
        ;;pop ix
        ;;jp (ix) ;но так не получится для разных фаз Y, смещения входов различаются!
        ;ex de,hl
        ;pop hl
        ;ld h,...
        ;jp (hl)
        ;...
        ;ex de,hl
        ;jp ;в середину prattr ;+29t/спрайт!!!
        
prattr_y7_oddhgt
        POPLDr_LDd ;32
        DOWNHL8ATTR ;30
        POPLDl_LDd ;32
        POPLDr_LDd ;32
        POPLDl_LDd ;32
        POPLDr_LDd ;32
        DOWNHL8ATTR ;30
        POPLDl_LDd ;32
        POPLDr_LDd ;32
        POPLDl_LDd ;32
        POPLDr_LDd ;32
        org $-1 ;-4
        exx
        add hl,de
        ld sp,hl
        ; pop af    ;
        ; out (c),a ;можно перенести в начало prspr/prsprpause, чтобы не делать это в последнем спрайте
        ;ret ;в один из входов prspr или на выход ;53 ;sum = (32*9)+(30*2)-4+53 = 397
        exx
        if SPRPAGED
         pop de ;нельзя портить de', bc
         ld a,e
         out (0xfd),a ;pg (надо 0b010xxxxx, иначе сработает 1ffd)
         ld a,d ;f(yphase)
        else
         pop af
        endif
        pop hl ;gfx
        pop de ;scr
        ld sp,hl
        pop hl ;l = f(hgt, x&4)
        ld h,a ;f(yphase)
        jp (hl) ;+45 ;sum = 397+45 = 442
;было: 1732t/sprite (13856[-22] из 14237-219=14018 возможных, осталось 162[+22] - можно добавить 22t/спрайт каких-нибудь удобств);на 128K есть лишние 26t перед рамкой экрана - осталось 188[+22]
;теперь: 1753t/sprite

        endif

        
        
        
        
        
        
        
        
        
        
        ld a,h
        rra
        add a,attr/256 - (0x40/2)
        ld h,a ;мы в конце атрибутов, будет отрисовывать их задом наперёд

        
        ld l,b ;tile2
       dup 3;0..3
       inc l ;чтобы начать с правильного места тайла в зависимости от yphase_end
       edup
       ld h,tileattr/256/2
         add hl,hl ;7b
        
        ld a,b
        add a,3
        add a,a
        ld l,a
        adc a,tileattr/256/2
        sub l
        ld h,a ;9b
         

        
        
        
;при таком стеке не получается уместить 8 спрайтов 18x18! даже без pg!
;надо заранее рассчитать prattr = f(yphase,sprhgt)
;можно его записать в стек последним
        ;ld d, ;f(yphase)
        ;ld e,(hl)
        ;push de ;f(yphase,sprhgt)
        ;...
        ;pop ix ;prattr
        ;pop af ;pg
        ;out (c),a
        ;exx
        ;pop de ;scr
        ;pop hl ;gfx
        ;ld sp,hl
        ;ex de,hl
;или рисовать спрайт сразу с атрибутами

        ;exx
        ;add hl,de
        ;ld sp,hl
        ;ret ;prsprproc ;H=f1(y&3,x&2), L=f(sprhgt) ;или на выход
        ...
        ;pop af ;pg
        ;out (c),a
        ;exx
        ;pop de ;scr
        ;pop hl ;gfx
        ;ld sp,hl
        ;ex de,hl
