Login

Subversion Repositories NedoOS

Rev

Rev 746 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

;4000: 64 канала(H) * 64 позиции(L) = 4096 треков
;8000..ffff: dynamic memory

BIGENDIAN=0 ;0=LSB,HSB

setscrpg
        ld a,(user_scr0_high) ;ok
        SETPG16K
        ret
setpgroots
pgroots=$+1
        ld a,0
        SETPG16K
        ret
setpgsamples
pgsamples=$+1
        ld a,0
        SETPG16K
        ret

pokecurtime_curtrack_c
;c=data
        ld a,(curtrack)
;pokecurtime_tracka_c
;a=track
;c=data
        ld hl,(curtime)
        call tracktime_totrackpartindex
poketrackpartindex_c
;hl=index
;ly=part
;a=track
;c=data
        ex de,hl
        call getroot ;out: hl=root
        call writetopoi_c ;keeps de ;c<->mem
        ex de,hl
;c<->mem
        ret

peekplaytime_tracka
;a=track
        ld hl,(playtime)
        call tracktime_totrackpartindex
peektrackpartindex
;hl=index
;ly=part
;a=track
;out: a=data
        ex de,hl
        call getroot ;out: hl=root
        call readfrompoi ;keeps de
        ex de,hl
        ret

getroot
;ly=part
;a=track
        add a,0x40
        ld h,a ;номер трека
        ;ld l,0*4
        ld a,ly ;part
        add a,a
        add a,a
        ld l,a
;hl=root
        ret

getendaddr
;ly=part
;a=track
        call getroot ;out: hl=root
        ld de,0xffff
        jp findleft ;out: de=nonempty index (or 0), a=data
;de=addr ;последний байт трека

tracktime_totrackpartindex
;a=track
;hl=time
;если канал подписан на ордер, то найти на месте или влево цифру ордера, index=(time-digittime)
;иначе index=time
        push af
        push hl
        call gettrackorder ;номер ордера (0=нет)
        pop hl
        or a ;канал подписан на ордер?
        jr z,tracktime_toindexpart_noorder ;part=a=0
        ;push af
         push de
        push hl
        ex de,hl
        xor a ;TODO номер канала ордера
        ld ly,0 ;у ордера всегда берём дефолтную часть (part=0), т.к. ордер не подчиняется ордерам
        call getroot
        call findleft ;out: de=nonempty index (or 0), a=data (1..62 or 0)
        pop hl ;time
        or a
        sbc hl,de ;time-digittime
         pop de
        ;pop af
tracktime_toindexpart_noorder
        ld ly,a
        pop af
;hl=index
;ly=part
;a=track
        ret

;пусть номер трека и смещение в треке - это функция от номера канала и времени (зависит от ордера, если канал привязан к ордеру). всего 64 канала * 64 позиции = 4096 треков (одна страница адресов)
;адрес в треке - функция номера трека и смещения в треке
;для этого каждый трек (длиной 64K) храним как бинарное дерево: адрес левой части, адрес правой части
;и так до минимального элемента (4 байта, которые смотрим непосредственно)
;адрес делится на 4, поэтому 2 байтами можно адресовать 256K (16 страниц)
;но так будет медленно, поэтому выделим 32K для каждого (канал & 7)

        macro BITINC_D nbit
        bit nbit,d
        jr z,$+4
         inc l
         inc l
        endm
        macro BITINC_E nbit
        bit nbit,e
        jr z,$+4
         inc l
         inc l
        endm

        macro HLFROMHL
        ld a,(hl)
        inc l
        ld h,(hl)
        ld l,a
        or h
        endm

readfrompoi
;hl=track root (4 bytes: left poi, right poi)
;de=index (kept)
;out: a=data
        BITINC_D 7
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 6
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 5
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 4
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 3
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 2
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 1
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_D 0
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 7
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 6
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 5
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 4
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 3
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        BITINC_E 2
        HLFROMHL
        ret z ;пусто, возвращает 0=NOTE_SPACE (только для чтения!!!)
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
        ld a,(hl)
        ret

        macro WRITETOPOI_D nbit,addr
        BITINC_D nbit
        inc l
        ld a,(hl)
        dec l
        or (hl)
        jp z,addr ;пусто
        ld a,(hl)
        inc l
        ld h,(hl)
        ld l,a
        endm

        macro WRITETOPOI_E nbit,addr
        BITINC_E nbit
        inc l
        ld a,(hl)
        dec l
        or (hl)
        jp z,addr ;пусто
        ld a,(hl)
        inc l
        ld h,(hl)
        ld l,a
        endm

writetopoi_c
;hl=track root (4 bytes: left poi, right poi)
;de=index (kept)
;c=data
;out: c<->mem
        ld a,c
        or a
        jp z,writetopoi_space
        WRITETOPOI_D 7,writetopoi_create15 ;если надо, создать узел из 32768 байт
        WRITETOPOI_D 6,writetopoi_create14
        WRITETOPOI_D 5,writetopoi_create13
        WRITETOPOI_D 4,writetopoi_create12
        WRITETOPOI_D 3,writetopoi_create11
        WRITETOPOI_D 2,writetopoi_create10
        WRITETOPOI_D 1,writetopoi_create9
        WRITETOPOI_D 0,writetopoi_create8
        WRITETOPOI_E 7,writetopoi_create7
        WRITETOPOI_E 6,writetopoi_create6
        WRITETOPOI_E 5,writetopoi_create5
        WRITETOPOI_E 4,writetopoi_create4
        WRITETOPOI_E 3,writetopoi_create3
        WRITETOPOI_E 2,writetopoi_create2 ;если надо, создать узел из 4 байт
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
        ld a,(hl)
        ld (hl),c
        ld c,a
        ret

        macro WRITETOPOI_CREATE_D nbit
        push de
        ex de,hl
        call newmem ;keep de
        ex de,hl
        ld (hl),e
        inc l
        ld (hl),d
        ex de,hl
        pop de
        BITINC_D nbit
        endm

        macro WRITETOPOI_CREATE_E nbit
        push de
        ex de,hl
        call newmem ;keep de
        ex de,hl
        ld (hl),e
        inc l
        ld (hl),d
        ex de,hl
        pop de
        BITINC_E nbit
        endm

writetopoi_create15 ;создать узел из 32768 байт
        WRITETOPOI_CREATE_D 6
writetopoi_create14 ;создать узел из 16384 байт
        WRITETOPOI_CREATE_D 5
writetopoi_create13 ;создать узел из 8192 байт
        WRITETOPOI_CREATE_D 4
writetopoi_create12 ;создать узел из 4096 байт
        WRITETOPOI_CREATE_D 3
writetopoi_create11 ;создать узел из 2048 байт
        WRITETOPOI_CREATE_D 2
writetopoi_create10 ;создать узел из 1024 байт
        WRITETOPOI_CREATE_D 1
writetopoi_create9 ;создать узел из 512 байт
        WRITETOPOI_CREATE_D 0
writetopoi_create8 ;создать узел из 256 байт
        WRITETOPOI_CREATE_E 7
writetopoi_create7 ;создать узел из 128 байт
        WRITETOPOI_CREATE_E 6
writetopoi_create6 ;создать узел из 64 байт
        WRITETOPOI_CREATE_E 5
writetopoi_create5 ;создать узел из 32 байт
        WRITETOPOI_CREATE_E 4
writetopoi_create4 ;создать узел из 16 байт
        WRITETOPOI_CREATE_E 3
writetopoi_create3 ;создать узел из 8 байт
        WRITETOPOI_CREATE_E 2
writetopoi_create2 ;создать узел из 4 байт
        push de
        ex de,hl
        call newmem ;keep de
        ex de,hl
        ld (hl),e
        inc l
        ld (hl),d
        ex de,hl
        pop de
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
        ld a,(hl)
        ld (hl),c
        ld c,a
        ret

        macro WRITETOPOI_SPACE_D nbit,addr
        BITINC_D nbit
        push hl ;класть в стек адрес указателя, который мы удаляем (всю цепочку)
        HLFROMHL
        jp z,addr ;уже пусто
        endm
       
        macro WRITETOPOI_SPACE_E nbit,addr
        BITINC_E nbit
        push hl ;класть в стек адрес указателя, который мы удаляем (всю цепочку)
        HLFROMHL
        jp z,addr ;уже пусто
        endm
       
writetopoi_space
;hl=track root (4 bytes: left poi, right poi)
;de=index
;умеет удалять пустое поддерево
        WRITETOPOI_SPACE_D 7,writetopoi_space_nodel15
        WRITETOPOI_SPACE_D 6,writetopoi_space_nodel14
        WRITETOPOI_SPACE_D 5,writetopoi_space_nodel13
        WRITETOPOI_SPACE_D 4,writetopoi_space_nodel12
        WRITETOPOI_SPACE_D 3,writetopoi_space_nodel11
        WRITETOPOI_SPACE_D 2,writetopoi_space_nodel10
        WRITETOPOI_SPACE_D 1,writetopoi_space_nodel9
        WRITETOPOI_SPACE_D 0,writetopoi_space_nodel8
        WRITETOPOI_SPACE_E 7,writetopoi_space_nodel7
        WRITETOPOI_SPACE_E 6,writetopoi_space_nodel6
        WRITETOPOI_SPACE_E 5,writetopoi_space_nodel5
        WRITETOPOI_SPACE_E 4,writetopoi_space_nodel4
        WRITETOPOI_SPACE_E 3,writetopoi_space_nodel3
        WRITETOPOI_SPACE_E 2,writetopoi_space_nodel2

        push hl
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
        ld c,(hl)
        ld (hl),0
        pop hl
        ld a,(hl)
        inc l
        or (hl)
        inc l
        or (hl)
        inc l
        or (hl)
        jp nz,writetopoi_space_nodel2 ;непусто - не удаляем
        push de
        ld a,l
        and 0xfc
        ld e,a
        ld d,h
        call delmem
        pop de

;удалять пустое поддерево, пока в узле выше вторая ссылка NULL
        macro WRITETOPOI_SPACE_DEL nodeladdr
        pop hl ;адрес указателя на узел уровня N
        ld (hl),a
        inc l
        ld (hl),a
        ld a,l
        xor 2
        ld l,a ;его брат
        ld a,(hl)
        dec l
        or (hl)
        jp nz,nodeladdr
        push de
        ld a,l
        and 0xfc
        ld e,a
        ld d,h
        call delmem
        pop de
        endm
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel3 ;удалили узел из 4 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel4 ;удалили узел из 8 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel5 ;удалили узел из 16 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel6 ;удалили узел из 32 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel7 ;удалили узел из 64 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel8 ;удалили узел из 128 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel9 ;удалили узел из 256 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel10 ;удалили узел из 512 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel11 ;удалили узел из 1024 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel12 ;удалили узел из 2048 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel13 ;удалили узел из 4096 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel14 ;удалили узел из 8192 байт
        WRITETOPOI_SPACE_DEL writetopoi_space_nodel15 ;удалили узел из 16384 байт
        pop hl ;адрес указателя на узел уровня 15 в корне
        ld (hl),a
        inc l
        ld (hl),a ;удалили узел из 32768 байт
        ret

;снять со стека все уровни
writetopoi_space_nodel2
        pop hl
writetopoi_space_nodel3
        pop hl
writetopoi_space_nodel4
        pop hl
writetopoi_space_nodel5
        pop hl
writetopoi_space_nodel6
        pop hl
writetopoi_space_nodel7
        pop hl
writetopoi_space_nodel8
        pop hl
writetopoi_space_nodel9
        pop hl
writetopoi_space_nodel10
        pop hl
writetopoi_space_nodel11
        pop hl
writetopoi_space_nodel12
        pop hl
writetopoi_space_nodel13
        pop hl
writetopoi_space_nodel14
        pop hl
writetopoi_space_nodel15
        pop hl
        ret

;найти ближайший непустой байт на месте или слева (для ордера)
findleft
;hl=track root (4 bytes: left poi, right poi)
;de=index
;out: de=nonempty index (or 0), a=data
;если на месте непустой байт, то выходим
;иначе (мы на пустом поддереве):
;если мы на правом поддереве, то проверить левое, иначе подняться выше (если мы уже на корне, вернуть 0)
        BITINC_D 7
findleft_findleft15 ;мы в нужном месте узла из 65536 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft14 ;мы в пустом узле из 32768 байт, искать левее или выйти (а не выше)
        BITINC_D 6
findleft_findleft14 ;мы в нужном месте узла из 32768 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft13 ;мы в пустом узле из 16384 байт, искать левее или выше
        BITINC_D 5
findleft_findleft13 ;мы в нужном месте узла из 16384 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft12 ;мы в пустом узле из 8192 байт, искать левее или выше
        BITINC_D 4
findleft_findleft12 ;мы в нужном месте узла из 8192 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft11 ;мы в пустом узле из 4096 байт, искать левее или выше
        BITINC_D 3
findleft_findleft11 ;мы в нужном месте узла из 4096 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft10 ;мы в пустом узле из 2048 байт, искать левее или выше
        BITINC_D 2
findleft_findleft10 ;мы в нужном месте узла из 2048 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft9 ;мы в пустом узле из 1024 байт, искать левее или выше
        BITINC_D 1
findleft_findleft9 ;мы в нужном месте узла из 1024 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft8 ;мы в пустом узле из 512 байт, искать левее или выше
        BITINC_D 0
findleft_findleft8 ;мы в нужном месте узла из 512 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft7 ;мы в пустом узле из 256 байт, искать левее или выше
        BITINC_E 7
findleft_findleft7 ;мы в нужном месте узла из 256 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft6 ;мы в пустом узле из 128 байт, искать левее или выше
        BITINC_E 6
findleft_findleft6 ;мы в нужном месте узла из 128 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft5 ;мы в пустом узле из 128 байт, искать левее или выше
        BITINC_E 5
findleft_findleft5 ;мы в нужном месте узла из 64 байт ;найти de
        push hl
        HLFROMHL
        jp z,findleft_noleft4 ;мы в пустом узле из 128 байт, искать левее или выше
        BITINC_E 4
findleft_findleft4 ;мы в нужном месте узла из 32 байт ;найти de
        push hl
        HLFROMHL
        jr z,findleft_noleft3 ;мы в пустом узле из 16 байт, искать левее или выше
        BITINC_E 3
findleft_findleft3 ;мы в нужном месте узла из 16 байт ;найти de
        push hl
        HLFROMHL
        jr z,findleft_noleft2 ;мы в пустом узле из 8 байт, искать левее или выше
        BITINC_E 2
findleft_findleft2 ;мы в нужном месте узла из 8 байт ;найти de
        push hl
        HLFROMHL
        jr z,findleft_noleft1 ;мы в пустом узле из 4 байт, искать левее или выше
;мы в узле из 4 байт ;найти de
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
;мы в нужном месте узла из 4 байт
        ld a,(hl)
        or a
        jp nz,findleft_ret2 ;return de, a
        bit 0,e
        jr z,findleft_noleft0
;мы в правой половине узла из 2 байт
        dec e ;res 0,e
        dec l
        or (hl)
        jp nz,findleft_ret2 ;return de, a
findleft_noleft0 ;мы уже в левой половине узла из 2 байт ;подняться выше
        bit 1,e
        jr z,findleft_noleft1
;мы в правой половине узла из 4 байт
        dec e
        dec l
        or (hl)
        jp nz,findleft_ret2 ;return de, a
        dec e
        dec l
        or (hl)
        jp nz,findleft_ret2 ;return de, a

;на месте не найдено - поднимаемся и ищем левее и выше

        macro FINDLEFTDECE addr,nbit
;мы в правой половине узла из N байт
        dec e
        dec l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,addr ;поиск de в узле из N байт (левой половине)
        endm
        macro FINDLEFTDECDE addr,nbit
;мы в правой половине узла из N байт
        dec de
        dec l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,addr ;поиск de в узле из N байт (левой половине)
        endm

findleft_noleft1 ;мы уже в левой половине узла из 4 байт ;подняться выше
         ld a,e
         and 0xfc
         ld e,a
        pop hl ;узел из 8 байт ;адрес указателя на пустой узел из 4 байт ;искать левее или выше
        and 4 ;bit 2,e
        jr z,findleft_noleft2
        FINDLEFTDECE findleft_findleft2,2 ;мы в правой половине узла из 8 байт ;поиск de в левой половине, если она есть
findleft_noleft2 ;мы уже в левой половине узла из 8 байт ;подняться выше
         ld a,e
         and 0xf8
         ld e,a
        pop hl ;узел из 16 байт ;адрес указателя на пустой узел из 8 байт ;искать левее или выше
        and 8 ;bit 3,e
        jr z,findleft_noleft3
        FINDLEFTDECE findleft_findleft3,3 ;мы в правой половине узла из 16 байт ;поиск de в левой половине, если она есть
findleft_noleft3 ;мы уже в левой половине узла из 16 байт ;подняться выше
         ld a,e
         and 0xf0
         ld e,a
        pop hl ;узел из 32 байт ;адрес указателя на пустой узел из 16 байт ;искать левее или выше
        and 0x10 ;bit 4,e
        jr z,findleft_noleft4
        FINDLEFTDECE findleft_findleft4,4 ;мы в правой половине узла из 32 байт ;поиск de в левой половине, если она есть
findleft_noleft4 ;мы уже в левой половине узла из 32 байт ;подняться выше
         ld a,e
         and 0xe0
         ld e,a
        pop hl ;узел из 64 байт ;адрес указателя на пустой узел из 32 байт ;искать левее или выше
        and 0x20 ;bit 5,e
        jr z,findleft_noleft5
        FINDLEFTDECE findleft_findleft5,5 ;мы в правой половине узла из 64 байт ;поиск de в левой половине, если она есть
findleft_noleft5 ;мы уже в левой половине узла из 64 байт ;подняться выше
         ld a,e
         and 0xc0
         ld e,a
        pop hl ;узел из 128 байт ;адрес указателя на пустой узел из 64 байт ;искать левее или выше
        and 0x40 ;bit 6,e
        jr z,findleft_noleft6
        FINDLEFTDECE findleft_findleft6,6 ;мы в правой половине узла из 128 байт ;поиск de в левой половине, если она есть
findleft_noleft6 ;мы уже в левой половине узла из 128 байт ;подняться выше
         ld a,e
         and 0x80
         ld e,a
        pop hl ;узел из 256 байт ;адрес указателя на пустой узел из 128 байт ;искать левее или выше
        ;bit 7,e
        jr z,findleft_noleft7
        FINDLEFTDECE findleft_findleft7,7 ;мы в правой половине узла из 256 байт ;поиск de в левой половине, если она есть
findleft_noleft7 ;мы уже в левой половине узла из 256 байт ;подняться выше
         ld e,a;0
        pop hl ;узел из 512 байт ;адрес указателя на пустой узел из 256 байт ;искать левее или выше
        bit 0,d
        jr z,findleft_noleft8
        FINDLEFTDECDE findleft_findleft8,0 ;мы в правой половине узла из 512 байт ;поиск de в левой половине, если она есть
findleft_noleft8 ;мы уже в левой половине узла из 512 байт ;подняться выше
         ld e,a;0
         res 0,d
        pop hl ;узел из 1024 байт ;адрес указателя на пустой узел из 512 байт ;искать левее или выше
        bit 1,d
        jr z,findleft_noleft9
        FINDLEFTDECDE findleft_findleft9,1 ;мы в правой половине узла из 1024 байт ;поиск de в левой половине, если она есть
findleft_noleft9 ;мы уже в левой половине узла из 1024 байт ;подняться выше
         ld e,a;0
         ld a,d
         and 0xfc
         ld d,a
        pop hl ;узел из 2048 байт ;адрес указателя на пустой узел из 1024 байт ;искать левее или выше
        and 4 ;bit 2,d
        jr z,findleft_noleft10
        FINDLEFTDECDE findleft_findleft10,2 ;мы в правой половине узла из 2048 байт ;поиск de в левой половине, если она есть
findleft_noleft10 ;мы уже в левой половине узла из 2048 байт ;подняться выше
         ld e,a;0
         ld a,d
         and 0xf8
         ld d,a
        pop hl ;узел из 4096 байт ;адрес указателя на пустой узел из 2048 байт ;искать левее или выше
        and 8 ;bit 3,d
        jr z,findleft_noleft11
        FINDLEFTDECDE findleft_findleft11,3 ;мы в правой половине узла из 4096 байт ;поиск de в левой половине, если она есть
findleft_noleft11 ;мы уже в левой половине узла из 4096 байт ;подняться выше
         ld e,a;0
         ld a,d
         and 0xf0
         ld d,a
        pop hl ;узел из 8192 байт ;адрес указателя на пустой узел из 4096 байт ;искать левее или выше
        and 0x10 ;bit 4,d
        jr z,findleft_noleft12
        FINDLEFTDECDE findleft_findleft12,4 ;мы в правой половине узла из 8192 байт ;поиск de в левой половине, если она есть
findleft_noleft12 ;мы уже в левой половине узла из 8192 байт ;подняться выше
         ld e,a;0
         ld a,d
         and 0xe0
         ld d,a
        pop hl ;узел из 16384 байт ;адрес указателя на пустой узел из 8192 байт ;искать левее или выше
        and 0x20 ;bit 5,d
        jr z,findleft_noleft13
        FINDLEFTDECDE findleft_findleft13,5 ;мы в правой половине узла из 16384 байт ;поиск de в левой половине, если она есть
findleft_noleft13 ;мы уже в левой половине узла из 16384 байт ;подняться выше
         ld e,a;0
         ld a,d
         and 0xc0
         ld d,a
        pop hl ;узел из 32768 байт ;адрес указателя на пустой узел из 16384 байт ;искать левее или выше
        and 0x40 ;bit 6,d
        jr z,findleft_noleft14
        FINDLEFTDECDE findleft_findleft14,6 ;мы в правой половине узла из 32768 байт ;поиск de в левой половине, если она есть
findleft_noleft14 ;мы уже в левой половине узла из 32768 байт ;подняться выше
         ;ld e,a;0
         ;ld a,d
         ;and 0x80
         ;ld d,a
        pop hl ;узел из 65536 байт ;адрес указателя на пустой узел из 32768 байт ;искать левее или выйти (а не выше)
        bit 7,d
        jr z,findleft_0 ;ret z ;дальше некуда левее, de=0, a=0
;мы в правой половине узла из 65536 байт
        ld de,0x7fff;dec de
        dec l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,findleft_findleft15 ;поиск de в узле из 65536 байт (левой половине)
findleft_0
        ld d,a
        ld e,a
        ret ;дальше некуда выше, de=0, a=0

findleft_ret2
        ;pop hl ;адрес указателя на узел из 4 байт
        ;pop hl ;адрес указателя на узел из 8 байт
        ;pop hl ;адрес указателя на узел из 16 байт
        ;pop hl ;адрес указателя на узел из 32 байт
        ;pop hl ;адрес указателя на узел из 64 байт
        ;pop hl ;адрес указателя на узел из 128 байт
        ;pop hl ;адрес указателя на узел из 256 байт
        ;pop hl ;адрес указателя на узел из 512 байт
        ;pop hl ;адрес указателя на узел из 1024 байт
        ;pop hl ;адрес указателя на узел из 2048 байт
        ;pop hl ;адрес указателя на узел из 4096 байт
        ;pop hl ;адрес указателя на узел из 8192 байт
        ;pop hl ;адрес указателя на узел из 16384 байт
        ;pop hl ;адрес указателя на узел из 32768 байт
        ld hl,14*2
        add hl,sp
        ld sp,hl
        ret

;найти ближайший непустой байт на месте или справа (для громкости и т.п.)
findright
;hl=track root (4 bytes: left poi, right poi)
;de=index
;out: de=nonempty index (or 0xffff), a=data
;если на месте непустой байт, то выходим
;иначе (мы на пустом поддереве):
;если мы на левом поддереве, то проверить правое, иначе подняться выше (если мы уже на корне, вернуть 0xffff)
        BITINC_D 7
findright_findright15 ;мы в нужном месте узла из 65536 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright14 ;мы в пустом узле из 32768 байт, искать правее или выйти (а не выше)
        BITINC_D 6
findright_findright14 ;мы в нужном месте узла из 32768 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright13 ;мы в пустом узле из 16384 байт, искать правее или выше
        BITINC_D 5
findright_findright13 ;мы в нужном месте узла из 16384 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright12 ;мы в пустом узле из 8192 байт, искать правее или выше
        BITINC_D 4
findright_findright12 ;мы в нужном месте узла из 8192 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright11 ;мы в пустом узле из 4096 байт, искать правее или выше
        BITINC_D 3
findright_findright11 ;мы в нужном месте узла из 4096 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright10 ;мы в пустом узле из 2048 байт, искать правее или выше
        BITINC_D 2
findright_findright10 ;мы в нужном месте узла из 2048 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright9 ;мы в пустом узле из 1024 байт, искать правее или выше
        BITINC_D 1
findright_findright9 ;мы в нужном месте узла из 1024 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright8 ;мы в пустом узле из 512 байт, искать правее или выше
        BITINC_D 0
findright_findright8 ;мы в нужном месте узла из 512 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright7 ;мы в пустом узле из 256 байт, искать правее или выше
        BITINC_E 7
findright_findright7 ;мы в нужном месте узла из 256 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright6 ;мы в пустом узле из 128 байт, искать правее или выше
        BITINC_E 6
findright_findright6 ;мы в нужном месте узла из 128 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright5 ;мы в пустом узле из 128 байт, искать правее или выше
        BITINC_E 5
findright_findright5 ;мы в нужном месте узла из 64 байт ;найти de
        push hl
        HLFROMHL
        jp z,findright_noright4 ;мы в пустом узле из 128 байт, искать правее или выше
        BITINC_E 4
findright_findright4 ;мы в нужном месте узла из 32 байт ;найти de
        push hl
        HLFROMHL
        jr z,findright_noright3 ;мы в пустом узле из 16 байт, искать правее или выше
        BITINC_E 3
findright_findright3 ;мы в нужном месте узла из 16 байт ;найти de
        push hl
        HLFROMHL
        jr z,findright_noright2 ;мы в пустом узле из 8 байт, искать правее или выше
        BITINC_E 2
findright_findright2 ;мы в нужном месте узла из 8 байт ;найти de
        push hl
        HLFROMHL
        jr z,findright_noright1 ;мы в пустом узле из 4 байт, искать правее или выше
;мы в узле из 4 байт ;найти de
        ld a,e
        rra
        jr nc,$+3
         inc l
        rra
        jr nc,$+4
         inc l
         inc l
;мы в нужном месте узла из 4 байт
        ld a,(hl)
        or a
        jp nz,findright_ret2 ;return de, a
        bit 0,e
        jr nz,findright_noright0
;мы в левой половине узла из 2 байт
        inc e ;set 0,e
        inc l
        or (hl)
        jp nz,findright_ret2 ;return de, a
findright_noright0 ;мы уже в правой половине узла из 2 байт ;подняться выше
        bit 1,e
        jr nz,findright_noright1
;мы в левой половине узла из 4 байт
        inc e
        inc l
        or (hl)
        jp nz,findright_ret2 ;return de, a
        inc e
        inc l
        or (hl)
        jp nz,findright_ret2 ;return de, a

;на месте не найдено - поднимаемся и ищем правее и выше

        macro FINDRIGHTINCE addr,nbit
;мы в левой половине узла из N байт
        inc e
        inc l
        inc l
        inc l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,addr ;поиск de в узле из N байт (правой половине)
        endm
        macro FINDRIGHTINCDE addr,nbit
;мы в левой половине узла из N байт
        inc de
        inc l
        inc l
        inc l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,addr ;поиск de в узле из N байт (правой половине)
        endm

findright_noright1 ;мы уже в правой половине узла из 4 байт ;подняться выше
         ld a,e
         or 0x03
         ld e,a
        pop hl ;узел из 8 байт ;адрес указателя на пустой узел из 4 байт ;искать правее или выше
        and 4 ;bit 2,e
        jr nz,findright_noright2
        FINDRIGHTINCE findright_findright2,2 ;мы в левой половине узла из 8 байт ;поиск de в правой половине, если она есть
findright_noright2 ;мы уже в правой половине узла из 8 байт ;подняться выше
         ld a,e
         or 0x07
         ld e,a
        pop hl ;узел из 16 байт ;адрес указателя на пустой узел из 8 байт ;искать правее или выше
        and 8 ;bit 3,e
        jr nz,findright_noright3
        FINDRIGHTINCE findright_findright3,3 ;мы в левой половине узла из 16 байт ;поиск de в правой половине, если она есть
findright_noright3 ;мы уже в правой половине узла из 16 байт ;подняться выше
         ld a,e
         or 0x0f
         ld e,a
        pop hl ;узел из 32 байт ;адрес указателя на пустой узел из 16 байт ;искать правее или выше
        and 0x10 ;bit 4,e
        jr nz,findright_noright4
        FINDRIGHTINCE findright_findright4,4 ;мы в левой половине узла из 32 байт ;поиск de в правой половине, если она есть
findright_noright4 ;мы уже в правой половине узла из 32 байт ;подняться выше
         ld a,e
         or 0x1f
         ld e,a
        pop hl ;узел из 64 байт ;адрес указателя на пустой узел из 32 байт ;искать правее или выше
        and 0x20 ;bit 5,e
        jr nz,findright_noright5
        FINDRIGHTINCE findright_findright5,5 ;мы в левой половине узла из 64 байт ;поиск de в правой половине, если она есть
findright_noright5 ;мы уже в правой половине узла из 64 байт ;подняться выше
         ld a,e
         or 0x3f
         ld e,a
        pop hl ;узел из 128 байт ;адрес указателя на пустой узел из 64 байт ;искать правее или выше
        and 0x40 ;bit 6,e
        jr nz,findright_noright6
        FINDRIGHTINCE findright_findright6,6 ;мы в левой половине узла из 128 байт ;поиск de в правой половине, если она есть
findright_noright6 ;мы уже в правой половине узла из 128 байт ;подняться выше
         ld a,e
         or 0x7f
         ld e,a
        pop hl ;узел из 256 байт ;адрес указателя на пустой узел из 128 байт ;искать правее или выше
        ;bit 7,e
        jp m,findright_noright7
        FINDRIGHTINCE findright_findright7,7 ;мы в левой половине узла из 256 байт ;поиск de в правой половине, если она есть
findright_noright7 ;мы уже в правой половине узла из 256 байт ;подняться выше
         ld e,0xff
        pop hl ;узел из 512 байт ;адрес указателя на пустой узел из 256 байт ;искать правее или выше
        bit 0,d
        jr nz,findright_noright8
        FINDRIGHTINCDE findright_findright8,0 ;мы в левой половине узла из 512 байт ;поиск de в правой половине, если она есть
findright_noright8 ;мы уже в правой половине узла из 512 байт ;подняться выше
         ld e,0xff
         set 0,d
        pop hl ;узел из 1024 байт ;адрес указателя на пустой узел из 512 байт ;искать правее или выше
        bit 1,d
        jr nz,findright_noright9
        FINDRIGHTINCDE findright_findright9,1 ;мы в левой половине узла из 1024 байт ;поиск de в правой половине, если она есть
findright_noright9 ;мы уже в правой половине узла из 1024 байт ;подняться выше
         ld e,0xff
         ld a,d
         or 0x03
         ld d,a
        pop hl ;узел из 2048 байт ;адрес указателя на пустой узел из 1024 байт ;искать правее или выше
        and 4 ;bit 2,d
        jr nz,findright_noright10
        FINDRIGHTINCDE findright_findright10,2 ;мы в левой половине узла из 2048 байт ;поиск de в правой половине, если она есть
findright_noright10 ;мы уже в правой половине узла из 2048 байт ;подняться выше
         ld e,0xff
         ld a,d
         or 0x07
         ld d,a
        pop hl ;узел из 4096 байт ;адрес указателя на пустой узел из 2048 байт ;искать правее или выше
        and 8 ;bit 3,d
        jr nz,findright_noright11
        FINDRIGHTINCDE findright_findright11,3 ;мы в левой половине узла из 4096 байт ;поиск de в правой половине, если она есть
findright_noright11 ;мы уже в правой половине узла из 4096 байт ;подняться выше
         ld e,0xff
         ld a,d
         or 0x0f
         ld d,a
        pop hl ;узел из 8192 байт ;адрес указателя на пустой узел из 4096 байт ;искать правее или выше
        and 0x10 ;bit 4,d
        jr nz,findright_noright12
        FINDRIGHTINCDE findright_findright12,4 ;мы в левой половине узла из 8192 байт ;поиск de в правой половине, если она есть
findright_noright12 ;мы уже в правой половине узла из 8192 байт ;подняться выше
         ld e,0xff
         ld a,d
         or 0x1f
         ld d,a
        pop hl ;узел из 16384 байт ;адрес указателя на пустой узел из 8192 байт ;искать правее или выше
        and 0x20 ;bit 5,d
        jr nz,findright_noright13
        FINDRIGHTINCDE findright_findright13,5 ;мы в левой половине узла из 16384 байт ;поиск de в правой половине, если она есть
findright_noright13 ;мы уже в правой половине узла из 16384 байт ;подняться выше
         ld e,0xff
         ld a,d
         or 0x3f
         ld d,a
        pop hl ;узел из 32768 байт ;адрес указателя на пустой узел из 16384 байт ;искать правее или выше
        and 0x40 ;bit 6,d
        jr nz,findright_noright14
        FINDRIGHTINCDE findright_findright14,6 ;мы в левой половине узла из 32768 байт ;поиск de в правой половине, если она есть
findright_noright14 ;мы уже в правой половине узла из 32768 байт ;подняться выше
         ;ld e,0xff
         ;ld a,d
         ;or 0x7f
         ;ld d,a
        pop hl ;узел из 65536 байт ;адрес указателя на пустой узел из 32768 байт ;искать правее или выйти (а не выше)
        bit 7,d
        jr nz,findright_0 ;ret z ;дальше некуда правее, de=0xffff, a=0
;мы в правой половине узла из 65536 байт
        ld de,0x8000;inc de
        inc l
        inc l
        inc l
        ld a,(hl)
        dec l
        or (hl)
        jp nz,findright_findright15 ;поиск de в узле из 65536 байт (правой половине)
findright_0
        ld de,0xffff
        ret ;дальше некуда выше, de=0xffff, a=0

findright_ret2
        ;pop hl ;адрес указателя на узел из 4 байт
        ;pop hl ;адрес указателя на узел из 8 байт
        ;pop hl ;адрес указателя на узел из 16 байт
        ;pop hl ;адрес указателя на узел из 32 байт
        ;pop hl ;адрес указателя на узел из 64 байт
        ;pop hl ;адрес указателя на узел из 128 байт
        ;pop hl ;адрес указателя на узел из 256 байт
        ;pop hl ;адрес указателя на узел из 512 байт
        ;pop hl ;адрес указателя на узел из 1024 байт
        ;pop hl ;адрес указателя на узел из 2048 байт
        ;pop hl ;адрес указателя на узел из 4096 байт
        ;pop hl ;адрес указателя на узел из 8192 байт
        ;pop hl ;адрес указателя на узел из 16384 байт
        ;pop hl ;адрес указателя на узел из 32768 байт
        ld hl,14*2
        add hl,sp
        ld sp,hl
        ret

newmem
;взять первый элемент списка свободных
;вернуть его в hl
;сдвинуть указатель на первый элемент списка свободных (если NIL, то повиснуть)
;out: hl=адрес 4 байт свободных
firstfree=$+1
        ld hl,freemem_start
        push hl
        inc l
        inc l
       if BIGENDIAN
        ld a,(hl)
        inc l
        ld l,(hl)
        ld h,a ;новый указатель на первый элемент списка свободных
         or l
         jr z,$ ;если NIL, то повиснуть (TODO заказать новый 256-байтный блок)
       else
        ld a,(hl)
        inc l
        ld h,(hl)
        ld l,a ;новый указатель на первый элемент списка свободных
         or h
         jr z,$ ;если NIL, то повиснуть (TODO заказать новый 256-байтный блок)
       endif
        ld (firstfree),hl
;в value этого элемента записать NIL (чтобы был двусвязный список свободных - в будущем можно будет освобождать 256-байтные блоки)
         xor a
         ld (hl),a
         inc l
         ld (hl),a ;NIL
       if BIGENDIAN
        ld hl,FreeMem_value
        ld a,(hl)
        inc l
        ld l,(hl)
        ld h,a
       else
        ld hl,(FreeMem_value)
       endif
        dec hl
        dec hl
        dec hl
        dec hl
       if BIGENDIAN
        ld a,h
        ld h,l
        ld l,a
        ld (FreeMem_value),hl
       else
        ld (FreeMem_value),hl
       endif
        pop hl
        xor a
        ld (hl),a
        inc l
        ld (hl),a
        inc l
        ld (hl),a
        inc l
        ld (hl),a
        dec l
        dec l
        dec l
        ret

delmem
;de=адрес 4 байт, которые освободить
;добавить в список свободных (value бывшего первого элемента пусть указывает на него, а у него на NIL, чтобы был двусвязный список свободных - в будущем можно будет освобождать 256-байтные блоки)
        ld hl,(firstfree) ;TODO проверить, что это последний занятый в 256-байтном блоке и освободить блок
       if BIGENDIAN
         ld (hl),d
         inc l
         ld (hl),e ;value бывшего первого элемента
       else
         ld (hl),e
         inc l
         ld (hl),d ;value бывшего первого элемента
        endif
         dec l
        ex de,hl
        ld (firstfree),hl
         xor a
         ld (hl),a
        inc l
         ld (hl),a ;NIL
        inc l
       if BIGENDIAN
        ld (hl),d
        inc l
        ld (hl),e ;next = бывший первый элемент
       else
        ld (hl),e
        inc l
        ld (hl),d ;next = бывший первый элемент
       endif
       if BIGENDIAN
        ld hl,FreeMem_value
        ld a,(hl)
        inc l
        ld l,(hl)
        ld h,a
       else
        ld hl,(FreeMem_value)
       endif
        ld de,4
        add hl,de
       if BIGENDIAN
        ld a,h
        ld h,l
        ld l,a
        ld (FreeMem_value),hl
       else
        ld (FreeMem_value),hl
       endif
        ret

initmem
;инит одного блока 32K
;4-байтные блоки prev.next, у первого prev=0, у последнего next=0
        ld hl,freemem_start
        ld b,h
        ld c,l
        ld de,0
initmem0
;de=prev
        inc bc
        inc bc
        inc bc
        inc bc
;bc=next
        push hl
        ld (hl),e
        inc l
        ld (hl),d ;prev
        inc l
        ld (hl),c
        inc l
        ld (hl),b ;next
        inc hl
        pop de ;de=prev
        ld a,h
        or a
        jr nz,initmem0
        ld (0xfffe),hl ;у последнего next=0

        call newmem
        xor a
        ld (hl),a
        inc l
        ld (hl),a
        inc l
        ld (hl),a
        inc l
        ld (hl),a ;root
        ret

FreeMem_value
        dw 0-freemem_start;32768