OldComp.cz

Komunitní diskuzní fórum pro fanoušky historických počítačů


Právě je 29.03.2024, 01:14

Všechny časy jsou v UTC + 1 hodina [ Letní čas ]




Odeslat nové téma Odpovědět na téma  [ Příspěvků: 585 ]  Přejít na stránku Předchozí  1 ... 24, 25, 26, 27, 28, 29, 30 ... 39  Další
Autor Zpráva
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 11.01.2023, 01:16 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Ve zkratce. Byl jsem v podstate donucen zmenit jmena pomocnych maker.

Mel jsem pro praci s daty posledniho tokenu makra zacinajici jako "__LAST_TOKEN_...".

Casem se ukazalo ze potrebuji zjistit i hodnoty co jsou pred poslednim tokenem tak vznikl "__BEFORELAST_...".

Ani to nestacilo takze jsem zavedl obecne "__BEFORE_X...(parametr)", kde parametr rovnajici se nule je to same jako __LAST_TOKEN a kdyz je tam jedna tak je to jako __BEFORELAST_. S tim ze ne vsechny manipulace atd byly podporovany. Nejvic toho bylo u __LAST_TOKEN.

Kdyz uz jsem mel funkcni __BEFORE_X tak jsem to mohl upravit na "__T_" a prepsat vsechny __LAST_TOKEN a __BEFORELAST.

Napr.
__LAST_TOKEN_NAME --> __T_NAME(0)
__BEFORELAST_TOKEN_NAME --> __T_NAME(1)
__BEFORE_X_NAME --> __T_NAME(2)

Jen jsem musel podporit vsechny varianty.
Umazal jsem moznost kdy se zjistuje cislo a zavedl jen HEX varianty. Ta ma tu vyhodu ze bud vrati cislo jako 0x0012 a to i u ciselneho vyrazu jako (10*1)-9-1 nebo prazdny retezec bez toho ze by vsude kricela chyby.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH((10*1)-9-1) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_DUP
; info: (10*1)-9-1 pick
;items: 0
;param: ()
    push DE             ; 1:11      (10*1)-9-1 pick   ( a -- a a )
    ld    D, H          ; 1:4       (10*1)-9-1 pick
    ld    E, L          ; 1:4       (10*1)-9-1 pick
; seconds: 0           ;[ 3:19]

Pravidlo si najde ze je tam PUSH(0x0000) + PICK a to se prevede na token DUP.
Predtim tam bylo neco jako "save_eval", ale tam se museli pravidla duplikovat u zapornych hodnot.
Jednou se testovala -1 a podruhe 0xFFFF. Ted se testuje jen 0xFFFF.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH((adr))PUSH(-1) OR __SHOW_TOKEN(1)'
; name: __TOKEN_PUSHS
; info: (adr) -1 or
;items: 1
;param: (            0xFFFF)
;array1: >0xFFFF<
;array: 0xFFFF
    push DE             ; 1:11      (adr) -1 or
    ex   DE, HL         ; 1:4       (adr) -1 or
    ld   HL, 0xFFFF     ; 3:10      (adr) -1 or
; seconds: 0           ;[ 5:25]


Pokud mame v testovani nejake EVAL tak se nekdy musi pouzivat trik ze se musi na zacatek pripsat nula aby ten EVAL nerval ze tam je neco jako "> 5". Napr. "eval(0__T_ITEMS(0)>1)" se zmeni na eval(00>1) nebo eval(05>1" a nebo kdyz se to vyhodocuje u prvniho tokenu tak predchozi jeste neexistuje takze se to zmeni na eval(0>1), jinak by se pri prvnim tokenu se vypsalo spoustu chyb.

Citace:
Zakladni makra jsou:
__T_NAME()
__T_INFO()
__T_ITEMS()
__T_PARAM()
__T_ARRAY()

Vypis X-teho parametru pocitano od zacatku(zleva):
__T_ARRAY_1()
__T_ARRAY_2()
__T_ARRAY_3()
__T_ARRAY_4()
__T_ARRAY_5()
__T_ARRAY_6()

Vypis X-teho parametru jako pocitano od konce(zprava)
__T_REVERSE_1()
__T_REVERSE_2()
__T_REVERSE_3()
__T_REVERSE_4()
__T_REVERSE_5()
__T_REVERSE_6()

Vypis X-teho parametru jako hex hodnota 0x0000 pocitano od zacatku(zleva):
__T_HEX_1()
__T_HEX_2()
__T_HEX_3()
__T_HEX_4()
__T_HEX_5()
__T_HEX_6()

Vypis X-teho parametru jako hex hodnota 0x0000 pocitano od konce(zprava)
__T_HEX_REVERSE_1()
__T_HEX_REVERSE_2()
__T_HEX_REVERSE_3()
__T_HEX_REVERSE_4()
__T_HEX_REVERSE_5()
__T_HEX_REVERSE_6()

Vypis X poslednich parametru:
__T_LAST_1_PAR()
__T_LAST_2_PAR()
__T_LAST_3_PAR()
__T_LAST_4_PAR()

Zjisteni zda X-ta hodnota nebo hodnoty jsou cislo ktere dokazi hned vyhodnotit. Tzn. zadny ukazatel nebo neznama promenna.
Vraci TRUE = 1 jen kdyz vsechny jsou cislo.
__T_IS_NUM_1()
__T_IS_NUM_2()
__T_IS_NUM_3()
__T_IS_NUM_4()
__T_IS_NUM_5()
__T_IS_NUM_6()
__T_IS_NUM_1_2()
__T_IS_NUM_1_3()
__T_IS_NUM_1_4()
__T_IS_NUM_2_3()
__T_IS_NUM_2_4()
__T_IS_NUM_3_4()
__T_IS_NUM_1_2_3()
__T_IS_NUM_1_2_3_4()

To same co predchozi jen jsou indexy brane pozpatku.
__T_IS_NUM_REVERSE_1()
__T_IS_NUM_REVERSE_2()
__T_IS_NUM_REVERSE_3()
__T_IS_NUM_REVERSE_4()
__T_IS_NUM_REVERSE_5()
__T_IS_NUM_REVERSE_6()
__T_IS_NUM_REVERSE_2_1()
__T_IS_NUM_REVERSE_3_1()
__T_IS_NUM_REVERSE_4_1()
__T_IS_NUM_REVERSE_3_2()
__T_IS_NUM_REVERSE_4_2()
__T_IS_NUM_REVERSE_4_3()
__T_IS_NUM_REVERSE_3_2_1()
__T_IS_NUM_REVERSE_4_3_2_1()

Zjisteni zda X-ta hodnota nebo hodnoty jsou ukazatele.
Vraci TRUE = 1 kdyz aspon jeden je ukazatek. Je to pak "otravene" pro dalsi testy.
__T_IS_PTR_1()
__T_IS_PTR_2()
__T_IS_PTR_3()
__T_IS_PTR_4()
__T_IS_PTR_5()
__T_IS_PTR_6()
__T_IS_PTR_1_2()
__T_IS_PTR_1_3()
__T_IS_PTR_1_4()
__T_IS_PTR_2_3()
__T_IS_PTR_2_4()
__T_IS_PTR_3_4()
__T_IS_PTR_1_2_3()
__T_IS_PTR_1_2_3_4()

To same co predchozi jen jsou indexy brane pozpatku.
__T_IS_PTR_REVERSE_1()
__T_IS_PTR_REVERSE_2()
__T_IS_PTR_REVERSE_3()
__T_IS_PTR_REVERSE_4()
__T_IS_PTR_REVERSE_5()
__T_IS_PTR_REVERSE_6()
__T_IS_PTR_REVERSE_2_1()
__T_IS_PTR_REVERSE_3_1()
__T_IS_PTR_REVERSE_4_1()
__T_IS_PTR_REVERSE_3_2()
__T_IS_PTR_REVERSE_4_2()
__T_IS_PTR_REVERSE_4_3()
__T_IS_PTR_REVERSE_3_2_1()
__T_IS_PTR_REVERSE_4_3_2_1()

Zbytek co umel jen __LAST_TOKEN, ale stejne to nikde nebylo pouzito. Takze jsem nedelal tyhle kombinace pro IS_PTR atd.
__T_IS_NUM_4_5()
__T_IS_NUM_5_6()
__T_IS_NUM_2_3_4()
__T_IS_NUM_3_4_5()
__T_IS_NUM_4_5_6()

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 11.01.2023, 01:55 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Dale jsem si hral s pravidlama pro (C/H)STORE.
Tohle slovo ma na zasobniku parametry "number address" a uklada to cislo na tu zadanou adresu a jako vetsina Forth slov tim odstrani parametry.

U toho jsem narazil na kombinace kdy si zachovavam adresu v zasobniku a to co chci ulozit tam vkladam na posledni chvili.

Pokud je adresa v TOS:
PUSH(num) OVER STORE

Pokud je adresa v NOS:
PUSH(num) PUSH(2) PICK STORE

atd.

Tohle jsem se snazil pridat do tokenovych pravidel protoze to tam nebylo.
Zacal jsem ale primo tim ze jsem to rozdelil na

PUSH(num) PUSH(x) PICK.

Kde jsem postupne zvedal x od nuly

x=0

PUSH(0) PICK --> DUP
Pokud pred tim je uz nejake PUSHS tak to muze uz zduplikovat jen posledni parametr a zustat u tokenu PUSHS.

x=1

PUSH(1) PICK --> OVER
Pokud je pred tim jeden parametr v PUSHS tak se to meni na PUSH_OVER
Pokud ji je vic tak to muze uz zduplikovat jen predposledni parametr a zustat u tokenu PUSHS.

x=2 uz zacne byt zajimavejsi protoze se ukazuje, ze nez se hluboko hrabat v zasobniku je lepsi to nejak osulit kombinaci jinych slov. V podstate se pokusime vytahnout neznamou co nejdriv nez zacneme na zasobnik ukladat dalsi hodnoty.

PUSH(2) PICK --> OVER
Pokud je pred tim jeden parametr v PUSHS tak se to meni na OVER_PUSH_SWAP, protoze je to mnohem lepsi nez PUSH(num1) a _2_PICK.
Pokud jsou pred tim dva parametry v PUSHS tak se to meni na DUP_PUSH_SWAP a PUSH_SWAP, protoze je to mnohem lepsi nez PUSH(num1,num2) a _2_PICK.
Pokud ji je vic tak to muze uz zduplikovat jen predpredposledni parametr a zustat u tokenu PUSHS.

x=3

PUSH(3) PICK --> _3_PICK
Pokud je pred tim jeden parametr v PUSHS tak se to meni na _2_PICK a PUSH_SWAP, protoze je to mnohem lepsi PUSH(num1) a _3_PICK.
Pokud jsou pred tim dva parametry v PUSHS tak se to meni na OVER_PUSH_SWAP a PUSH_SWAP, protoze je to mnohem lepsi nez PUSH(num1,num2) a _3_PICK.
Pokud jsou pred tim tri parametry v PUSHS tak se to meni na DUP_PUSH_SWAP a PUSH_SWAP_PUSH_SWAP, protoze je to mnohem lepsi nez PUSH(num1,num2,num3) a _3_PICK.
Pokud ji je vic tak to muze uz zduplikovat jen predpredposledni parametr a zustat u tokenu PUSHS.

x=4
atd.


Tohle nejak fungovalo, jen jsem musel vyresit jak zapsat __INFO. Kdyz jsem pokud se to rozpadlo zadal pro oba tokeny stejne info tak to vypadalo dobre...

...jenze kdyz jsem zacal psat pravidla ze za to hodim STORE (pripadne CSTORE nebo HSTORE), tak vznikly komplikace.
Nemluvim jen o tom ze najednou kdyz ocekavam ze pred tim je PUSHS token a _3_PICK token tak tam je nejaka kombinace jinych tokenu.
Ale hlavne o INFU, protoze se me nekdy zdvojuje a ja nemam informaci ze je to zdvojene. A kdyz to bylo napr. PUSH(num1) PUSH(3) PICK STORE tak to najednou bylo "num1 3 pick num1 3 pick !".

Kdyz bych info u druheho tokenu umazal tak by nekdy byla fakt velka mezera v komentarich.
Osetril jsem to nejak ale vysledek proste nekdy vytvarel chyby nebo uplne nesmysly. Protoze STORE uz nevi zda predtim tam bylo
"OVER PUSH(num1) SWAP PUSH(num2) SWAP" a nebo "PUSH(num1,num2) _3_PICK". A pro obe varianty by se mel chova jinak.

Nakonec jsem to vyresil tak ze jsem zavedl specialni info "__dtto". Pokud pri uz vytvareni kodu ten token ma hodnotu stale __dtto tak se mu priradi info predchoziho tokenu. Pokud naopak se vola makro/fce __CONCATENATE_WITH a nejaky parametr ma hodnotu __dtto tak se tvari jako by tam nebyl. Tahlo makro/fce odstranuje i zbytecne mezery, protoze ignoruje i prazdne retezce. Prvni parametr fce je cim se bude oddelovat takze se to vola vetsinou jako __CONCATENATE_WITH({ },__T_INFO(1),__T_INFO(0),$2). To by melo spojit info z predchoziho, posledniho a $2 je aktualne ukladaneho tokenu.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_DUP
; info: 0 pick
;items: 0
;param: ()
    push DE             ; 1:11      0 pick   ( a -- a a )
    ld    D, H          ; 1:4       0 pick
    ld    E, L          ; 1:4       0 pick
; seconds: 0           ;[ 3:19]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xaa) PUSH(0) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_PUSHS
; info: 0xaa 0 pick
;items: 2
;param: (0xaa,0xaa)
;array1: >0xaa<
;array2: >0xaa<
;array: 0xaa,0xaa
                        ;[7:40]     0xaa 0 pick   ( -- 0xaa 0xaa )
    push DE             ; 1:11      0xaa 0 pick
    push HL             ; 1:11      0xaa 0 pick
    ld   DE, 0x00AA     ; 3:10      0xaa 0 pick
    ld    L, E          ; 1:4       0xaa 0 pick   L = E = 0xAA
    ld    H, D          ; 1:4       0xaa 0 pick   H = D = 0x00
; seconds: 0           ;[ 7:40]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(1) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_OVER
; info: 1 pick
;items: 0
;param: ()
    push DE             ; 1:11      1 pick   ( b a -- b a b )
    ex   DE, HL         ; 1:4       1 pick
; seconds: 0           ;[ 2:15]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xaa) PUSH(1) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_PUSH_OVER
; info: 0xaa 1 pick
;items: 1
;param: (0xaa)
;array1: >0xaa<
;array: 0xaa
    push DE             ; 1:11      0xaa 1 pick   ( a -- a 0xaa a )
    push HL             ; 1:11      0xaa 1 pick
    ld   DE, 0xaa       ; 3:10      0xaa 1 pick
; seconds: 0           ;[ 5:32]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xbb) PUSH(0xaa) PUSH(1) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_PUSHS
; info: 0xbb 0xaa 1 pick
;items: 3
;param: (0xbb,0xaa,0xbb)
;array1: >0xbb<
;array2: >0xaa<
;array3: >0xbb<
;array: 0xbb,0xaa,0xbb
    push DE             ; 1:11      0xbb 0xaa 1 pick   ( -- 0xbb 0xaa 0xbb ) push3.m4
    push HL             ; 1:11      0xbb 0xaa 1 pick
    ld   HL, 0x00BB     ; 3:10      0xbb 0xaa 1 pick
    push HL             ; 1:11      0xbb 0xaa 1 pick
    ld   DE, 0x00AA     ; 3:10      0xbb 0xaa 1 pick
; seconds: 0           ;[ 9:53]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(2) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_2_PICK
; info: 2 pick
;items: 0
;param: ()
                       ;[ 6:44]     2 pick   ( c b a -- c b a c )
    pop  BC             ; 1:10      2 pick
    push BC             ; 1:11      2 pick
    push DE             ; 1:11      2 pick
    ex   DE, HL         ; 1:4       2 pick
    ld    H, B          ; 1:4       2 pick
    ld    L, C          ; 1:4       2 pick
; seconds: 0           ;[ 6:44]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xaa) PUSH(2) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_OVER_PUSH_SWAP
; info: 0xaa 2 pick
;items: 1
;param: (0xaa)
;array1: >0xaa<
;array: 0xaa
                        ;[6:36]     0xaa 2 pick   ( x1 x0 -- x1 x0 0xaa x1 )
    push DE             ; 1:11      0xaa 2 pick
    push HL             ; 1:11      0xaa 2 pick
    ld   HL, 0xaa       ; 3:10      0xaa 2 pick
    ex   DE, HL         ; 1:4       0xaa 2 pick
; seconds: 0           ;[ 6:36]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xbb) PUSH(0xaa) PUSH(2) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_DUP_PUSH_SWAP
; info: 0xbb 0xaa 2 pick
;items: 2
;param: (0xbb,0xaa)
;array1: >0xbb<
;array2: >0xaa<
;array: 0xbb,0xaa
; name: __TOKEN_PUSH_SWAP
; info: __dtto
;items: 1
;param: (2)
;array1: >2<
;array: 2
    push DE             ; 1:11      0xbb 0xaa 2 pick   ( a -- a 0xbb a )
    push HL             ; 1:11      0xbb 0xaa 2 pick
    ld   DE, 0xbb       ; 3:10      0xbb 0xaa 2 pick
    push DE             ; 1:11      0xbb 0xaa 2 pick   ( x -- 2 x )
    ld   DE, 2          ; 3:10      0xbb 0xaa 2 pick
; seconds: 0           ;[ 9:53]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xcc) PUSH(0xbb) PUSH(0xaa) PUSH(2) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_PUSHS
; info: 0xcc 0xbb 0xaa 2 pick
;items: 4
;param: (0xcc,0xbb,0xaa,0xcc)
;array1: >0xcc<
;array2: >0xbb<
;array3: >0xaa<
;array4: >0xcc<
;array: 0xcc,0xbb,0xaa,0xcc
; name:
; info:
;items: 0
;param:
    push DE             ; 1:11      0xcc 0xbb 0xaa 2 pick
    push HL             ; 1:11      0xcc 0xbb 0xaa 2 pick
    ld   HL, 0x00CC     ; 3:10      0xcc 0xbb 0xaa 2 pick
    push HL             ; 1:11      0xcc 0xbb 0xaa 2 pick
    ld   DE, 0x00BB     ; 3:10      0xcc 0xbb 0xaa 2 pick
    push DE             ; 1:11      0xcc 0xbb 0xaa 2 pick
    ld    E, 0xAA       ; 2:7       0xcc 0xbb 0xaa 2 pick
; seconds: 1           ;[12:71]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(3) PICK __SHOW_TOKEN(1)'
; name: __TOKEN_3_PICK
; info: 3 pick
;items: 0
;param: ()
                       ;[ 8:65]     3 pick   ( d c b a -- d c b a d )
    pop  AF             ; 1:10      3 pick
    pop  BC             ; 1:10      3 pick
    push BC             ; 1:11      3 pick
    push AF             ; 1:11      3 pick
    push DE             ; 1:11      3 pick
    ex   DE, HL         ; 1:4       3 pick
    ld    H, B          ; 1:4       3 pick
    ld    L, C          ; 1:4       3 pick
; seconds: 1           ;[ 8:65]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xaa) PUSH(3) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_2_PICK
; info: 0xaa 3 pick
;items: 0
;param: ()
; name: __TOKEN_PUSH_SWAP
; info: __dtto
;items: 1
;param: (0xaa)
;array1: >0xaa<
;array: 0xaa
                       ;[ 6:44]     0xaa 3 pick   ( c b a -- c b a c )
    pop  BC             ; 1:10      0xaa 3 pick
    push BC             ; 1:11      0xaa 3 pick
    push DE             ; 1:11      0xaa 3 pick
    ex   DE, HL         ; 1:4       0xaa 3 pick
    ld    H, B          ; 1:4       0xaa 3 pick
    ld    L, C          ; 1:4       0xaa 3 pick
    push DE             ; 1:11      0xaa 3 pick   ( x -- 0xaa x )
    ld   DE, 0xaa       ; 3:10      0xaa 3 pick
; seconds: 0           ;[10:65]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xbb) PUSH(0xaa) PUSH(3) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_OVER_PUSH_SWAP
; info: 0xbb 0xaa 3 pick
;items: 1
;param: (0xbb)
;array1: >0xbb<
;array: 0xbb
; name: __TOKEN_PUSH_SWAP
; info: __dtto
;items: 1
;param: (0xaa)
;array1: >0xaa<
;array: 0xaa
                        ;[6:36]     0xbb 0xaa 3 pick   ( x1 x0 -- x1 x0 0xbb x1 )
    push DE             ; 1:11      0xbb 0xaa 3 pick
    push HL             ; 1:11      0xbb 0xaa 3 pick
    ld   HL, 0xbb       ; 3:10      0xbb 0xaa 3 pick
    ex   DE, HL         ; 1:4       0xbb 0xaa 3 pick
    push DE             ; 1:11      0xbb 0xaa 3 pick   ( x -- 0xaa x )
    ld   DE, 0xaa       ; 3:10      0xbb 0xaa 3 pick
; seconds: 0           ;[10:57]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xcc) PUSH(0xbb) PUSH(0xaa) PUSH(3) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_DUP_PUSH_SWAP
; info: 0xcc 0xbb 0xaa 3 pick
;items: 1
;param: (0xcc)
;array1: >0xcc<
;array: 0xcc
; name: __TOKEN_PUSH_SWAP_PUSH_SWAP
; info: __dtto
;items: 2
;param: (0xbb,0xaa)
;array1: >0xbb<
;array2: >0xaa<
;array: 0xbb,0xaa
    push DE             ; 1:11      0xcc 0xbb 0xaa 3 pick   ( a -- a 0xcc a )
    push HL             ; 1:11      0xcc 0xbb 0xaa 3 pick
    ld   DE, 0xcc       ; 3:10      0xcc 0xbb 0xaa 3 pick
    push DE             ; 1:11      0xcc 0xbb 0xaa 3 pick   ( x -- 0xbb 0xaa x )
    ld   DE, 0xbb       ; 3:10      0xcc 0xbb 0xaa 3 pick
    push DE             ; 1:11      0xcc 0xbb 0xaa 3 pick
    ld    E, 0xAA       ; 2:7       0xcc 0xbb 0xaa 3 pick
; seconds: 1           ;[12:71]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(0xdd) PUSH(0xcc) PUSH(0xbb) PUSH(0xaa) PUSH(3) PICK __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_PUSHS
; info: 0xdd 0xcc 0xbb 0xaa 3 pick
;items: 5
;param: (0xdd,0xcc,0xbb,0xaa,0xdd)
;array1: >0xdd<
;array2: >0xcc<
;array3: >0xbb<
;array4: >0xaa<
;array: 0xdd,0xcc,0xbb,0xaa,0xdd
; name:
; info:
;items: 0
;param:
    push DE             ; 1:11      0xdd 0xcc 0xbb 0xaa 3 pick
    push HL             ; 1:11      0xdd 0xcc 0xbb 0xaa 3 pick
    ld   HL, 0x00DD     ; 3:10      0xdd 0xcc 0xbb 0xaa 3 pick
    push HL             ; 1:11      0xdd 0xcc 0xbb 0xaa 3 pick
    ld   DE, 0x00CC     ; 3:10      0xdd 0xcc 0xbb 0xaa 3 pick
    push DE             ; 1:11      0xdd 0xcc 0xbb 0xaa 3 pick
    ld    E, 0xBB       ; 2:7       0xdd 0xcc 0xbb 0xaa 3 pick
    push DE             ; 1:11      0xdd 0xcc 0xbb 0xaa 3 pick
    ld    E, 0xAA       ; 2:7       0xdd 0xcc 0xbb 0xaa 3 pick
; seconds: 2           ;[15:89]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$


PS: Nevyhoda je ze se to zacina komplikovat... a pokud neco zmenim a token se rozpadne nebo zmeni jinak tak uz ho nezachyti STORE nebo jiny navazujici token. Pokud by se me to neustale nemenilo pod rukama tak by to tak nevadilo...

PPS: Opraveno eval(0__T_ITEMS(0)>1) na eval(1__T_ITEMS(0)>11). Protoze kdyz bylo parametru vic jak sedm a zaroven se tam objevila cislice 8 nebo 9 tak to vyhodilo chybu protoze uvodni nula oznamuje ze je to oktalove cislo. Myslel jsem ze to nevadi ale 08>5 vadi. Musim si hlidat i levou stranu.
Mozna jsem to mel prohodit a udelat eval(__T_ITEMS(0)0>10) ktere by se menilo na (0>10) nebo (10>10) nebo (20>10)...

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 18.01.2023, 03:40 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Rozdelil jsem soubor __macro.m4 na nekolik souboru, protoze uz zacal byt prilis velky.

Vznikly soubory __t_rules.m4, kde jsou tokenova pravidla a __eval.m4, kde jsou makra pro aritmeticke vypocty
Kód:
dnl # Input:
dnl #    operation num_1 num_2
dnl #    operation num_1 num_2 num_3
dnl # Output:
dnl #    eval(            (num_1) operation (num_2))
dnl #    eval(            (num_1) operation (num_2)),eval(            (num_1) operation (num_2))
dnl #    eval(((num_1)<<16+num_2) operation (num_3))
dnl #    eval(((num_1)<<16+num_2) operation (num_3)),eval(((num_1)<<16+num_2) operation (num_3))
define({__EVAL_S16},{dnl

Kód:
dnl # Input:
dnl #    $1 ...operation
dnl #    $2 ...hi16(num_1)
dnl #    $3 ...lo16(num_1)
dnl #    $4 ...hi16(num_2)
dnl #    $5 ...lo16(num_2)
dnl # Output:
dnl #    eval(            (num_1) operation (num_2))
define({__EVAL_S32},{dnl


Pak jsem mel nejaka nedodelana pravidla s indexem a naslednym push, kde jsem mel poznamku ze to mam prevest do pravidel do druheho pruchodu. Plus to umelo jen I a ne J a K.

Kdyz jsem to zacal testovat ve smyckach pres check_word.sh a objevil jsem nejakou nesrovnalost... Pokud jsem zadal ze ty smycky jsou typu S (stack) tak kdyz jsem dal za smycku FOR, tak ta ma jen jednu polozku a to index ulozenty na zasobniku, ale index si myslel ze jsou tam dve polozky, vcetne konce, i kdyz konec je u FOR nula. Takze u J indexu a K indexu by to vytahovalo spatna data.

Tak jsem se dival na kod a snazil se to pochopit a pak to opravil. Pak jsem zjistil ze jsem to pochopil blbe a misto opravy jsem to uplne podelal. Takze jsem to vratil ze souboru co je na githubu a postupne pridaval znovu zmeny co jsem tam mel.
Postupne jsem to cele zjednodusoval a pouzival dalsi pomocne makra, aby to vypadalo prehledne.

Kdyz jsem pouzival stack smycky tak jsem na rozdil od ostatnich smycek pokud zjistit hodnotu STOP tak ji necham v NOS (DE) a v TOS (HL) je index. Ta smycka je pak rychlejsi i kdyz to zabira dve polozky misto jedne.
Jedina vyjimka byla STOP hodnota nula a jedna. Kdy se to nevyplati nechat v DE, protoze test na nulu nebo jednicku jde udelat snadneji. FOR smycka je to same co DO ADDLOOP(-1) smycka kde znam END ze je nula.

A u tehle vyjimky jsem kdy nedrzim dve hodnoty jsem to zapomnel opravit u indexu. Mel jsem tam ze pokud neznam END tak jsou to dve polozky a kdyz END znam tak je jedna polozka. A to plati prave jen u te nuly a jednicky.

Nanestesti to bylo jeste zamotanejsi a kdyz jsem LOOP konec zmenil za ADDLOOP, tak me to stale bralo ze je to LOOP smycka.
Chyba se objevovala jen u vnorenych smycek, tak jsem zacal vsude delat vypisy a nechapal jsem... vse bylo dobre, po tokenovych pravidlech me __SHOW_LOOP ukazovalo spravny STEP a pak se to nekdy nejak preplo na STEP je +1.
Prokrokoval jsem vsechny ADDLOOP atd a nic.
Nastesti jsem zjistil jsem ze kdyz mam jen ADDLOOP tak to funguje a jakmile za to pridam LOOP tak to selze.
Krokoval jsem i LOOP a nic a pak jsem to nasel. Mel jsem jen primo v LOOP kde se vytvari volani pro token __TOKEN_LOOP mel misto STACK_LOOP promennou COUNT_LOOP... Takhle nenapadne to bylo.

Fixnul jsem to, k I tokenovym pravidlum pridal i J a K pravidla. Krome vyjimky na nulu a jednicku jsem pridal i -1. Snad jsem tim nezavlekl dalsi regresi...
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'DO(S) FOR(S) PUSH(1) PUSH(10) DO(S,,,) K PUSH(5) LOOP NEXT LOOP'
do101:                  ;           do_101(s)   ( stop index -- stop index )
for102:                 ;           for_102(s) ( index -- index )
    push DE             ; 1:11      1 10 do_103(s)
    ex   DE, HL         ; 1:4       1 10 do_103(s)
    ld   HL, 10         ; 3:10      1 10 do_103(s)
do103:                  ;           1 10 do_103(s)   ( stop index -- index )  stop = 1
Tady K saha jen ob dve polozky. Protoze smycka 103 konci v nule a 102 je FOR, takze taky konci v nule. A smycka 101 je Stack, takze K je ulozena na zasobniku jako ostatni indexy. To ze smycka 101 ma stale i STOP na zasobniku uz K nezajima, protoze Index je prvni.
Takze to ( c b a -- c b a c 5 ) jde cist jako ( k j i -- k j i k 5 )
Kód:
                        ;           k_101 5(s)   ( -- k 5 )
    pop  BC             ; 1:10      k_101 5(s)   ( c b a -- c b a c 5 )
    push BC             ; 1:11      k_101 5(s)
    push DE             ; 1:11      k_101 5(s)
    push HL             ; 1:11      k_101 5(s)
    ld    D, B          ; 1:4       k_101 5(s)
    ld    E, C          ; 1:4       k_101 5(s)
    ld   HL, 5          ; 3:10      k_101 5(s)
Kód:
    ld    A, L          ; 1:4       loop_103(s)
    or    H             ; 1:4       loop_103(s)
    inc  HL             ; 1:6       loop_103(s)   index++
    jp   nz, do103      ; 3:10      loop_103(s)
leave103:               ;           loop_103(s)
    ex   DE, HL         ; 1:4       unloop_103(s)   ( i -- )
    pop  DE             ; 1:10      unloop_103(s)
exit103:                ;           loop_103(s)
    ld    A, H          ; 1:4       next_102(s)
    or    L             ; 1:4       next_102(s)
    dec  HL             ; 1:6       next_102(s)   index--
    jp  nz, for102      ; 3:10      next_102(s)
leave102:               ;           next_102(s)
    ex   DE, HL         ; 1:4       unloop_102(s)   ( i -- )
    pop  DE             ; 1:10      unloop_102(s)
    inc  HL             ; 1:6       loop_101(s)   index++
    ld    A, L          ; 1:4       loop_101(s)
    xor   E             ; 1:4       loop_101(s)   lo(index - stop)
    jp   nz, do101      ; 3:10      loop_101(s)
    ld    A, H          ; 1:4       loop_101(s)
    xor   D             ; 1:4       loop_101(s)   hi(index - stop)
    jp   nz, do101      ; 3:10      loop_101(s)
leave101:               ;           loop_101(s)
    pop  HL             ; 1:10      unloop_101(s)   ( stop_i i -- )
    pop  DE             ; 1:10      unloop_101(s)
exit101:                ;           loop_101(s)
; seconds: 1           ;[43:224]


PS: Ten kod je samozrejme nesmysl, protoze by neustale pridaval polozky na zasobnik. Nedal jsem tam neco co ve vnitrni smycce smaze ty dve nove pridane polozky.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 07.02.2023, 15:05 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Lol, Z80 dokaze stale prekvapit.

Dival jsem se na reseni co me leze pokud volame fci MOVE co kopiruje blok dat s tim ze zname posledni parametr, ktery je pocet word slov.
A to je presne rovno jedne.
Takze PUSH(1) MOVE. Pak v TOS(HL) je cilova adresa a NOS(DE) je zdrojova adresa.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(5-4) MOVE __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_PUSH_MOVE
; info: 5-4 move
;items: 1
;param: (5-4)
;array1: >5-4<
;array: 5-4
; name:
; info:
;items: 0
;param:
                        ;[7:56]     5-4 move   ( from_addr to_addr -- )   u = 1 word
    ex   DE, HL         ; 1:4       5-4 move   HL = from_addr, DE = to_addr
    ldi                 ; 2:16      5-4 move   addr++
    ldi                 ; 2:16      5-4 move   addr++
    pop  HL             ; 1:10      5-4 move
    pop  DE             ; 1:10      5-4 move
; seconds: 0           ;[ 7:56]


Zkousel jsem ty dva bajty kopirovat rucne pomoci
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(5-4) MOVE __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_PUSH_MOVE
; info: 5-4 move
;items: 1
;param: (5-4)
;array1: >5-4<
;array: 5-4
; name:
; info:
;items: 0
;param:
                        ;[8:60]     5-4 move   ( from_addr to_addr -- )   u = 1 word
    ld    A,(DE)        ; 1:7       5-4 move
    ld  (HL),A          ; 1:7       5-4 move
    inc  DE             ; 1:6       5-4 move
    inc  HL             ; 1:6       5-4 move
    ld    A,(DE)        ; 1:7       5-4 move
    ld  (HL),A          ; 1:7       5-4 move
    pop  HL             ; 1:10      5-4 move
    pop  DE             ; 1:10      5-4 move
; seconds: 0           ;[ 8:60]

Kopirovani je sice rychlejsi, ale to rucni zvedani adres je i pres odpadnuti prohozeni DE za HL drazsi reseni. LDI je proste efektivnejsi.
Ale... LDI zveda adresu az POTE co prekopiruje bajt a ja nepotrebuji na konci mit adresy o jednicku za koncem. Takze kdyz posledni LDI nahradim za proste kopirovani tak usetrim 2 takty!
A tohle reseni funguje pokazde kdyz pouzivame opakovane LDI!
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH(5-4) MOVE __SHOW_TOKEN(1) __SHOW_TOKEN(2)'
; name: __TOKEN_PUSH_MOVE
; info: 5-4 move
;items: 1
;param: (5-4)
;array1: >5-4<
;array: 5-4
; name:
; info:
;items: 0
;param:
                        ;[7:54]     5-4 move   ( from_addr to_addr -- )   u = 1 word
    ex   DE, HL         ; 1:4       5-4 move   HL = from_addr, DE = to_addr
    ldi                 ; 2:16      5-4 move   addr++
    ld    A,(HL)        ; 1:7       5-4 move
    ld  (DE),A          ; 1:7       5-4 move
    pop  HL             ; 1:10      5-4 move
    pop  DE             ; 1:10      5-4 move
; seconds: 0           ;[ 7:54]


Nikdy by me nenapadlo kdyz se divam na 2 LDI za sebou, ze to jde zrychlit.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 08.02.2023, 23:41 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Upravoval jsem soubor if.m4. Protoze tam mam hodne
Kód:
define({__INFO},dup_push_lt_if){}dnl
...
   nejaky kod          ; bajty:takty     dup $1 < if

kde to define jsem delal automaticky skriptem s nazvu makra a to "dup $1 < if" byl puvodni rucne psany info.

A nove chci
Kód:
define({__INFO},__COMPILE_INFO){}dnl
...
   nejaky kod          ; bajty:takty     __INFO

Protoze info se prebira "zhora" a nekdy muze byt vic tokenu spojeno a tvarit se jako spojenene slovo, i kdyz to muze byt spojeni uplne jinych tokenu se stejnym efektem. Z vysledenho kodu to uz neni poznat jak to bylo generovane. Nevim jak to vysvetli jednoduse na prikladu, protoze by se to jeste vic zamotalo... .)

Poznamka: bavime se u forthu o 16 bitovych cislech se ZNAMENKEM.

A zjistil jsem ze me chybi nektere kombinace slov

mel jsem

_0LT_IF
DUP_0LT_IF
_0GE_IF
DUP_0GE_IF

ale uz ne

_0GT_IF
DUP_0GT_IF
_0LE_IF
DUP_0LE_IF

ani samotne

_0GT
_0LE

protoze jsem udelal jen _0LT a _0GE protoze je to fakt snadny napsat. Staci jen zkontrolovat nejvyssi (znamenkovy) bit.

Takze jsem neco vyplodil pro ty dve zbyvajici varianty.

Kód:
                        ;[9:41/20]  0>   ( x -- flag )  flag: x > 0
    ld    A, L          ; 1:4       0>
    or    H             ; 1:4       0>
    jr    z, $+7        ; 2:7/12    0>   zero is false and result
    ld    A, H          ; 1:4       0>
    sub   0x80          ; 2:7       0>
    sbc  HL, HL         ; 2:15      0>

_0LE bylo trosku jinak resene, myslim ze to bylo nejak
Kód:
                        ;[8:39]  0<=   ( x -- flag )  flag: x <= 0
    ld    A, L          ; 1:4       0<=
    or    H             ; 1:4       0<=
    sub  0x01           ; 1:4       0<=
    sbc   A, A          ; 1:4       0<=
    or    H             ; 1:4       0<=
    add   A, A          ; 1:4       0<=
    sbc  HL, HL         ; 2:15      0<=


a pak me pri psani v kombinaci s IFem doslo ze to jde udelat jinak, efektivneji a ze ty slova nemit byla celou dobu jen ma lenost a hloupost. Staci na to v podstate 3 instrukce. Nactu si do A znamenkovy bit. Snizim HL o jedna a tim se stane nula zapornym cislem a udelam obycejny bitovy OR. Znamenko me ukazuje vysledek! Pri snizeni znamenka me nejvic zaporne cislo pretece do nejvysiho kladneho cisla, ale proto si drzim to znamenko uz v A, takze to nevadi.

Kód:
                        ;[7:36]     0>   ( x -- flag )  flag: x > 0
    ld    A, H          ; 1:4       0>   save sign
    dec  HL             ; 1:6       0>   zero to negative
    or    H             ; 1:4       0>
    sub   0x80          ; 2:7       0>
    sbc  HL, HL         ; 2:15      0>


Kód:
                        ;[6:33]     0<=   ( x -- flag )  flag: x <= 0
    ld    A, H          ; 1:4       0<=
    dec  HL             ; 1:6       0<=
    or    H             ; 1:4       0<=
    add   A, A          ; 1:4       0<=   carry if zero or negative HL
    sbc  HL, HL         ; 2:15      0<=

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 02:32 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Mel jsem ted tyden volno.

Takze jsem sedel 7 dni doma(v pokoji), protoze taky co delat, kdyz jste v miste kde vsichni mluvi jazykem kterym nerozumite.

To je spousta casu pro divani se do zdi nebo programovani.

Jak jiste vsichni vite, na rootu po serii clanku o programovani pro NES ted konecne (znovu) vychazi serie clanku o programovani na Spectru. Coz oceni kazdy programator v asembleru pro Z80. .)

https://www.root.cz/clanky/kouzlo-minimalismu-potreti-vyvoj-her-a-dem-pro-slavne-zx-spectrum/
https://www.root.cz/clanky/vyvoj-pro-zx-spectrum-mikroprocesor-zilog-z80-a-smycky-v-assembleru/
https://www.root.cz/clanky/vyvoj-pro-zx-spectrum-vypis-informaci-na-obrazovku/
dalsi vyjde v utery rano 28.2.2023

Ten druhy clanek by o smyckach, tak jsem se hned dival jak to vlastne resim v rutine PUSH3_FILL, ktera dela obdobu toho co se popisovalo v clanku, nastavuje rozsah adres na nejakou hodnotu.

Nejefektivnejsi je pouzita zasobnik:

push HL ...11 taktu na 2 bajty = 5.5 taktu na bajt

Ale to vyzaduje vedet zda je povolene preruseni nebo zakazane a zakazat ho, schovat si hodnotu SP, presunout ho a opakovane od hornich adres pushovat ke spodnim.
Jenze co kdyz nekdo bude chtit aby bezelo neco na pozadi a s konstantnim intevalem 50x za vterinu?
Hudbu asi na pozadi ne, to se bude muset asi resit nejen prerusenim (dokonce by melo byt asi zakazane), ale kouskovat kod na casove konstatni intervaly mnohem kratsi jak 50 za vterinu (klidne s pouzitim vyplne) a mezitim pravidelne obsluhovat zvuk (teda menit jeden bit na zapnuto vypnuto). Ale nastesti jsem to pro Z80 nikdy nepsal. .)

Takze push nepouzivam i kdyz bych mohl mit na to nejaky flag pro pouziti.

Co teda zbyva?

LDIR ...21 taktu na bajt

LDI ...16 taktu na bajt ale to uz je lepsi

LD (HL), A
INC HL ...13 taktu na bajt

LD (HL), A
INC L ...11 taktu na bajt, ale musime vede ze neprelezame segment

Podivame se co dela nejhorsi/default varianta
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x4801,0x4321,xx)'
                       ;[17:360941] 0x4801 0x4321 xx fill   fill(addr,u,char)   default variant: fill(no ptr,?,?)
    push DE             ; 1:11      0x4801 0x4321 xx fill
    push HL             ; 1:11      0x4801 0x4321 xx fill
    ld   HL, 0x4801     ; 3:10      0x4801 0x4321 xx fill   HL = addr from
    ld   DE, 0x4802     ; 3:10      0x4801 0x4321 xx fill   DE = to
    ld   BC, 0x4320     ; 3:10      0x4801 0x4321 xx fill   = 0x4321-1
    ld  (HL),xx         ; 2:10      0x4801 0x4321 xx fill
    ldir                ; 2:u*21/16 0x4801 0x4321 xx fill
    pop  HL             ; 1:10      0x4801 0x4321 xx fill
    pop  DE             ; 1:10      0x4801 0x4321 xx fill
; seconds: 0           ;[15:82]

LDIR je otesanek, vyzaduje obsazeni HL,DE,BC a to neco stoji.
Je to 17 bajtu a tech cca 21*bajt taktu.
A tady vyzva zacina, napsat to o hodne rychleji a ne o moc delsi a nebo kratsi a stejne rychle ci rychleji.

Variant je vic jak 10 tak nevim kolik toho zaspamovat...

Varianty do 7 bajtu nebudu ukazovat, ale jsou dulezite aby se aktivovaly protoze nasledujici varianty pouzivaji smycku a pocitaji s tim ze pocet bajtu je minimalne o velikosti smycky, jinak selzou.

Varianta kdy oblast konci na 0x..00 (vyjma) a nepreleza segment a pocet je delitelny trema:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000-5*19,5*19,xx)'
                       ;[13:1528]   0x5000-5*19 5*19 xx fill   fill(addr,u,char)   variant >0: fill(num,max 256,?)
    ld   BC, 0x4FA1     ; 3:10      0x5000-5*19 5*19 xx fill   addr
    ld    A, xx         ; 2:7       0x5000-5*19 5*19 xx fill   char
    ld  (BC),A          ; 1:7       0x5000-5*19 5*19 xx fill
    inc   C             ; 1:4       0x5000-5*19 5*19 xx fill
    ld  (BC),A          ; 1:7       0x5000-5*19 5*19 xx fill
    inc   C             ; 1:4       0x5000-5*19 5*19 xx fill
    jp   nz, $-4        ; 3:10      0x5000-5*19 5*19 xx fill
    ld  (BC),A          ; 1:7       0x5000-5*19 5*19 xx fill
; seconds: 0           ;[13:56]

To same jen to neni delitelne trema(takze je to delitelne dvema s pripadnym zbytkem 1 jako je v nasledujici ukazce):
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000-19,19,xx)'
                       ;[13:312]    0x5000-19 19 xx fill   fill(addr,u,char)   variant >0: fill(num,max 256,?)
    ld   BC, 0x4FED     ; 3:10      0x5000-19 19 xx fill   addr
    ld    A, xx         ; 2:7       0x5000-19 19 xx fill   char
    ld  (BC),A          ; 1:7       0x5000-19 19 xx fill
    inc   C             ; 1:4       0x5000-19 19 xx fill
    ld  (BC),A          ; 1:7       0x5000-19 19 xx fill
    inc   C             ; 1:4       0x5000-19 19 xx fill
    jp   nz, $-4        ; 3:10      0x5000-19 19 xx fill
    ld  (BC),A          ; 1:7       0x5000-19 19 xx fill
; seconds: 0           ;[13:56]


Nebudu ukazovat skoro to same kdyz rozsah zacina na nule (vcetne).

Ted tu mame jeste efektivni smycku pro 256 opakovani pri pouziti B registru takze:

Varianta kdy pocet je delitelny trema, ale mensi nebo roven 256*3:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5033,3*83,xx)'
                       ;[17:4024]   0x5033 3*83 xx fill   fill(addr,u,char)   variant: fill(num,3*83 (max 767),no ptr)
    push HL             ; 1:11      0x5033 3*83 xx fill
    ld   HL, 0x5033     ; 3:10      0x5033 3*83 xx fill   addr
    ld    B, 0x53       ; 2:7       0x5033 3*83 xx fill   (3*83)/3
    ld    A, xx         ; 2:7       0x5033 3*83 xx fill   char
    ld  (HL),C          ; 1:7       0x5033 3*83 xx fill
    inc  HL             ; 1:6       0x5033 3*83 xx fill   0x50FF=0x5033+0+3*68
    ld  (HL),C          ; 1:7       0x5033 3*83 xx fill
    inc   L             ; 1:4       0x5033 3*83 xx fill
    ld  (HL),C          ; 1:7       0x5033 3*83 xx fill
    inc   L             ; 1:4       0x5033 3*83 xx fill
    djnz $-6            ; 2:13/8    0x5033 3*83 xx fill
    pop  HL             ; 1:10      0x5033 3*83 xx fill
; seconds: 0           ;[17:93]

Kdy neni delitelny trema, ale dvema s pripadnym zbytkem 1:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5033,2*83,xx)'
                       ;[15:2948]   0x5033 2*83 xx fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      0x5033 2*83 xx fill
    ld   HL, 0x5033     ; 3:10      0x5033 2*83 xx fill   addr
    ld   BC, 0x5300+xx  ; 3:10      0x5033 2*83 xx fill   B = 83x, C = xx
    ld  (HL),C          ; 1:7       0x5033 2*83 xx fill
    inc   L             ; 1:4       0x5033 2*83 xx fill
    ld  (HL),C          ; 1:7       0x5033 2*83 xx fill
    inc   L             ; 1:4       0x5033 2*83 xx fill   only even numbers
    djnz $-4            ; 2:13/8    0x5033 2*83 xx fill
    pop  HL             ; 1:10      0x5033 2*83 xx fill
; seconds: 0           ;[14:76]


Specialni varianty kdy rozsah zabira presne cely jeden segment ukazu jen pro 7*256 protoze tady se vyplati jiny pristup:
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000,7*256,xx)'
                       ;[23:24078]  0x5000 7*256 xx fill   fill(addr,u,char)   variant: fill(0x??00,7*256,?)
    ld    A, xx         ; 2:7       0x5000 7*256 xx fill   char
    ld    C, 0x00       ; 2:7       0x5000 7*256 xx fill   lo(addr)
    ld    B, 0x50       ; 2:7       0x5000 7*256 xx fill   hi(addr)
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   B             ; 1:4       0x5000 7*256 xx fill
    ld  (BC),A          ; 1:7       0x5000 7*256 xx fill
    inc   C             ; 1:4       0x5000 7*256 xx fill
    jp   nz, $-16       ; 3:10      0x5000 7*256 xx fill
; seconds: 0           ;[23:108]

Pamet se nastavuje postupne v kazdem segmentu na shodnem ofsete soucasne, protoze se pouziva jen jedna smycka pro offset.
Takze misto pomaleho djnz jde pouzit rychly jp. Zato se musi opakovane na zacatku smycky pokazde nastavit nejnizsi segment rozsahu. Nikde nehrozi zadne pouziti INC BC.

Pokud vyzkousime to same pro 6 segmentu tak vyhraje to ze je to delitelne ctyrma. Vlastne je dost dulezite jak je ten rozsah velky a jak se faktorizuje na prvocisla. Myslim tim ze 6*256=2×2×2×2×2×2×2×2×2×3
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000,6*256,xx)'
                       ;[22:20874]  0x5000 6*256 xx fill   fill(addr,u,char)   variant >0: fill(no ptr,4*384 (no limit),?)
    push HL             ; 1:11      0x5000 6*256 xx fill
    ld   HL, 0x5000     ; 3:10      0x5000 6*256 xx fill   HL = addr
    ld   BC, 0x0600+xx  ; 3:10      0x5000 6*256 xx fill   B = 6x, C = char
    ld  (HL),C          ; 1:7       0x5000 6*256 xx fill
    inc   L             ; 1:4       0x5000 6*256 xx fill
    ld  (HL),C          ; 1:7       0x5000 6*256 xx fill
    inc   L             ; 1:4       0x5000 6*256 xx fill
    ld  (HL),C          ; 1:7       0x5000 6*256 xx fill
    inc   L             ; 1:4       0x5000 6*256 xx fill
    ld  (HL),C          ; 1:7       0x5000 6*256 xx fill
    inc   L             ; 1:4       0x5000 6*256 xx fill
    jp   nz, $-8        ; 3:10      0x5000 6*256 xx fill
    inc   H             ; 1:4       0x5000 6*256 xx fill
    djnz $-12           ; 2:13/8    0x5000 6*256 xx fill
    pop  HL             ; 1:10      0x5000 6*256 xx fill
; seconds: 0           ;[22:112]

Nasobek 4 je fajn, protoze obdovna varianta jde pouzit na cokoliv dalsiho, a budeme vedet ze jen jen INC bude muset byt 16 bitovy. A zbytek jsou max 3 bajty. Jen ta velikost je uz dost velka.

Co takhle varianty kdy rozsah je nasobek peti? A neodchyti to varianta pro rozsah do 513.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000,5*113,xx)'
                       ;[20:8172]   0x5000 5*113 xx fill   fill(addr,u,char)   variant: fill(num,5*113 (max 767),no ptr)
    push HL             ; 1:11      0x5000 5*113 xx fill
    ld   HL, 0x5000     ; 3:10      0x5000 5*113 xx fill
    ld   BC, 0x7100+xx  ; 3:10      0x5000 5*113 xx fill
    ld  (HL),C          ; 1:7       0x5000 5*113 xx fill
    inc  HL             ; 1:6       0x5000 5*113 xx fill   0x50FF=0x5000+0+5*51
    ld  (HL),C          ; 1:7       0x5000 5*113 xx fill
    inc  HL             ; 1:6       0x5000 5*113 xx fill   0x51FF=0x5000+1+5*102
    ld  (HL),C          ; 1:7       0x5000 5*113 xx fill
    inc   L             ; 1:4       0x5000 5*113 xx fill
    ld  (HL),C          ; 1:7       0x5000 5*113 xx fill
    inc   L             ; 1:4       0x5000 5*113 xx fill
    ld  (HL),C          ; 1:7       0x5000 5*113 xx fill
    inc   L             ; 1:4       0x5000 5*113 xx fill
    djnz $-10           ; 2:8/13    0x5000 5*113 xx fill
    pop  HL             ; 1:10      0x5000 5*113 xx fill
; seconds: 0           ;[20:108]


A co kdyz to bude koncit v nulovem ofsetu? Zmeni to neco?
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000-5*113,5*113,xx)'
                       ;[18:7814]   0x5000-5*113 5*113 xx fill   fill(addr,u,char)   variant >0: fill(num,5*113 (max 1280),?)
    ld   BC, 0x4DCB     ; 3:10      0x5000-5*113 5*113 xx fill   addr = (0x4DCB..0x4FFF)
    ld    A, xx         ; 2:7       0x5000-5*113 5*113 xx fill   char
    ld  (BC),A          ; 1:7       0x5000-5*113 5*113 xx fill
    inc   C             ; 1:4       0x5000-5*113 5*113 xx fill
    ld  (BC),A          ; 1:7       0x5000-5*113 5*113 xx fill
    inc   C             ; 1:4       0x5000-5*113 5*113 xx fill
    ld  (BC),A          ; 1:7       0x5000-5*113 5*113 xx fill
    inc  BC             ; 1:6       0x5000-5*113 5*113 xx fill   0x4DFF=0x5000-5*113+2+5*10
    ld  (BC),A          ; 1:7       0x5000-5*113 5*113 xx fill
    inc  BC             ; 1:6       0x5000-5*113 5*113 xx fill   0x4EFF=0x5000-5*113+3+5*61
    ld  (BC),A          ; 1:7       0x5000-5*113 5*113 xx fill
    inc   C             ; 1:4       0x5000-5*113 5*113 xx fill
    jp   nz, $-10       ; 3:10      0x5000-5*113 5*113 xx fill
; seconds: 0           ;[18:86]

Jo hodne, uz nemusime mit jedno pocitadlo. Pro zacatek v nulovem ofsetu to ale nefunguje. Vysvetlim pozdeji.

Nebudu ukazovat vsechny, muzete si to vyzkouset sami. .)

Kód:
fill(addr,u,char)   variant: fill(no ptr,ptr,?)
fill(addr,u,char)   variant: fill(no ptr,ptr,?)
   ;[8:40]     fill(addr,u,char)   variant u = ??? = 1 byte
   ;[7:34]     fill(addr,u,char)   variant u = ??? = 1 byte
   ;[6:26]     fill(addr,u,char)   variant u = ??? = 1 byte
   ;[5:20]     fill(addr,u,char)   variant u = ??? = 1 byte
  ;[10:53]     fill(addr,u,char)   variant u = ??? = 2 byte
   ;[9:47]     fill(addr,u,char)   variant u = ??? = 2 byte
   ;[9:39]     fill(addr,u,char)   variant u = ??? = 2 byte
   ;[7:30]     fill(addr,u,char)   variant u = ??? = 2 byte
  ;[12:66]     fill(addr,u,char)   variant u = ??? = 3 byte
  ;[11:60]     fill(addr,u,char)   variant u = ??? = 3 byte
   ;[12:52]    fill(addr,u,char)   variant u = ??? = 3 byte
   ;[11:46]    fill(addr,u,char)   variant u = ??? = 3 byte
  ;[14:79]     fill(addr,u,char)   variant u = ??? = 4 byte
  ;[13:73]     fill(addr,u,char)   variant u = ??? = 4 byte
   ;[13:61]    fill(addr,u,char)   variant u = ??? = 4 byte
   ;[11:50]    fill(addr,u,char)   variant u = ??? = 4 byte
  ;[16:92]     fill(addr,u,char)   variant u = ??? = 5 byte
  ;[15:86]     fill(addr,u,char)   variant u = ??? = 5 byte
   ;[16:74]    fill(addr,u,char)   variant u = ??? = 5 byte
  ;[15:67]     fill(addr,u,char)   variant u = ??? = 5 byte
  ;[18:105]    fill(addr,u,char)   variant u = ??? = 6 byte
  ;[17:99]     fill(addr,u,char)   variant u = ??? = 6 byte
   ;[17:81]    fill(addr,u,char)   variant u = ??? = 6 byte
  ;[15:70]     fill(addr,u,char)   variant u = ??? = 6 byte
fill(addr,u,char)   variant u = ??? > 6
fill(addr,u,char)   variant u = ???
   ;           fill(addr,u,char)   variant: fill(?,0,?)},
   ;[8:40]     fill(addr,u,char)   variant: fill(ptr,1,ptr)
   ;[7:34]     fill(addr,u,char)   variant: fill(ptr,1,no ptr)
   ;[6:26]     fill(addr,u,char)   variant: fill(no ptr,1,ptr)
   ;[5:20]     fill(addr,u,char)   variant: fill(no ptr,1,no ptr)
  ;[10:53]     fill(addr,u,char)   variant: fill(ptr,2,ptr)
   ;[9:47]     fill(addr,u,char)   variant: fill(ptr,2,no ptr)
   ;[9:39]     fill(addr,u,char)   variant: fill(no ptr,2,ptr)
   ;[7:30]     fill(addr,u,char)   variant: fill(no ptr,2,no ptr)
  ;[12:66]     fill(addr,u,char)   variant: fill(ptr,3,ptr)
  ;[11:60]     fill(addr,u,char)   variant: fill(ptr,3,no ptr)
   ;[12:52]    fill(addr,u,char)   variant: fill(no ptr,3,ptr)
   ;[11:46]    fill(addr,u,char)   variant: fill(no ptr,3,no ptr)
  ;[14:79]     fill(addr,u,char)   variant: fill(ptr,4,ptr)
  ;[13:73]     fill(addr,u,char)   variant: fill(ptr,4,no ptr)
   ;[13:61]    fill(addr,u,char)   variant: fill(no ptr,4,ptr)
   ;[11:50]    fill(addr,u,char)   variant: fill(no ptr,4,no ptr)
  ;[16:92]     fill(addr,u,char)   variant: fill(ptr,5,ptr)
  ;[15:86]     fill(addr,u,char)   variant: fill(ptr,5,no ptr)
   ;[16:74]    fill(addr,u,char)   variant: fill(no ptr,5,ptr)
  ;[15:67]     fill(addr,u,char)   variant: fill(no ptr,5,no ptr)
  ;[18:105]    fill(addr,u,char)   variant: fill(ptr,6,ptr)
  ;[17:99]     fill(addr,u,char)   variant: fill(ptr,6,no ptr)
   ;[17:81]    fill(addr,u,char)   variant: fill(no ptr,6,ptr)
  ;[15:70]     fill(addr,u,char)   variant: fill(no ptr,6,no ptr)
fill(addr,u,char)   variant >0: fill(num,3*__TMP_X (max 256),?)
fill(addr,u,char)   variant >0: fill(num,max 256,?)
fill(addr,u,char)   variant 0>: fill(num,3*eval(($2)/3) max(256),?)
fill(addr,u,char)   variant 0>: fill(num,max 256,?)
fill(addr,u,char)   variant: fill(ptr,7,ptr)
fill(addr,u,char)   variant: fill(anything,7,0)
fill(addr,u,char)   variant: fill(ptr,7,no ptr)
fill(addr,u,char)   variant: fill(no ptr,7,ptr)
fill(addr,u,char)   variant: fill(num,3*__TMP_X (max 767),ptr)
fill(addr,u,char)   variant: fill(num,3*eval(($2)/3) (max 767),no ptr)
fill(addr,u,char)   variant: fill(?,max 513,ptr)
fill(addr,u,char)   variant: fill(?,max 513,no ptr)
fill(addr,u,char)   variant 0>0: fill(0x??00,5*256,hi(addr))
fill(addr,u,char)   variant >0: fill(num,5*eval($2/5) (max 1280),?)
fill(addr,u,char)   variant >0: fill(num,5*__TMP_X-2 (max 1280),?)
fill(addr,u,char)   variant: fill(num,5*__TMP_X (max 767),ptr)
fill(addr,u,char)   variant: fill(num,5*__TMP_X (max 767),no ptr)
fill(addr,u,char)   variant: fill(0x??00,4*256,?)
fill(addr,u,char)   variant: fill(0x??00,4*256,ptr)
fill(addr,u,char)   variant: fill(0x??00,4*256,no ptr)
fill(addr,u,char)   variant >0: fill(no ptr,4*384 (no limit),?)
fill(addr,u,char)   variant: fill(0x??00,6*256,?)
fill(addr,u,char)   variant: fill(?,6*eval(($2)/6)(max 1536),ptr)
fill(addr,u,char)   variant: fill(?,6*eval(($2)/6)(max 1536),no ptr)
fill(addr,u,char)   variant >0: fill(no ptr,4*512 (no limit),?)
fill(addr,u,char)   variant: fill(0x??00,7*256,?)
fill(addr,u,char)   variant >0: fill(no ptr,4*512 (no limit),?)
fill(addr,u,char)   variant: fill(0x??00,8*256,?)
fill(addr,u,char)   variant: fill(?,max 1027,ptr)
fill(addr,u,char)   variant: fill(?,max 1027,no ptr)
fill(addr,u,char)   variant: fill(0x??00,n*6*256,?)
fill(addr,u,char)   variant >0: fill(no ptr,4*__TMP_X (no limit),?)
fill(addr,u,char)   variant 0>: fill(no ptr,4*__TMP_X (no limit),?)
fill(addr,u,char)   variant: fill(ptr,4*eval(__TMP_X) (no limit),?)
fill(addr,u,char)   variant: fill(no ptr,4*eval(__TMP_X) (no limit),?)
fill(addr,u,char)   variant 0>: fill(no ptr,no limit,?)
fill(addr,u,char)   default variant: fill(ptr,?,?)
fill(addr,u,char)   default variant: fill(no ptr,?,?)


Z tohoto ukazi uz jen posledni, jednu z nejhnusnejsich variant, ale stale lepsi nez LDIR. Tu predpredposledni "variant 0>: fill(no ptr,no limit,?)".
Specialni podminka je, ze zaciname na nulovem ofestu. Chceme napsat stejne velky kod jako s LDIR ale rychlejsi.
Pocitadlo staci jen na segmenty, protoze budeme sestupne nastavovat adresy od konce rozsahu.
Prvne se nastavi neuplny segment a pak ty cele pod nim.
Do smycky se nam vleze zmena jen 2 bajtu. To je 6 bajtu kodu i se skokem. Mala vyhoda je, ze to nedelame pres djnz takze misto 13 taku bude 12 taktu pro relativni skok a ve smycce nikdy neprelezame segment, takze zadne 16 bitove dec, coz setri 2 takty pro kazde dec.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000,2142,xx)'
                       ;[17:36558]  0x5000 2142 xx fill   fill(addr,u,char)   variant 0>: fill(no ptr,no limit,?)
    push HL             ; 1:11      0x5000 2142 xx fill   0x5000..0x585D
    ld   HL, 0x575E     ; 3:10      0x5000 2142 xx fill   HL = addr+u
    ld   BC, 0x0900+xx  ; 3:10      0x5000 2142 xx fill   B = 9x, C = char
    dec   L             ; 1:4       0x5000 2142 xx fill
    ld  (HL),C          ; 1:7       0x5000 2142 xx fill
    dec   L             ; 1:4       0x5000 2142 xx fill
    ld  (HL),C          ; 1:7       0x5000 2142 xx fill
    jr   nz, $-4        ; 2:7/12    0x5000 2142 xx fill
    dec   H             ; 1:4       0x5000 2142 xx fill
    djnz $-7            ; 2:13/8    0x5000 2142 xx fill
    pop  HL             ; 1:10      0x5000 2142 xx fill
; seconds: 0           ;[17:87]
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(0x5000,2141,xx)'
                       ;[18:36531]  0x5000 2141 xx fill   fill(addr,u,char)   variant 0>: fill(no ptr,no limit,?)
    push HL             ; 1:11      0x5000 2141 xx fill   0x5000..0x585C
    ld   HL, 0x575C     ; 3:10      0x5000 2141 xx fill   HL = addr+u
    ld   BC, 0x0900+xx  ; 3:10      0x5000 2141 xx fill   B = 9x, C = char
    ld  (HL),C          ; 1:7       0x5000 2141 xx fill
    dec   L             ; 1:4       0x5000 2141 xx fill
    ld  (HL),C          ; 1:7       0x5000 2141 xx fill
    dec   L             ; 1:4       0x5000 2141 xx fill
    ld  (HL),C          ; 1:7       0x5000 2141 xx fill
    jr   nz, $-4        ; 2:7/12    0x5000 2141 xx fill
    dec   H             ; 1:4       0x5000 2141 xx fill
    djnz $-7            ; 2:13/8    0x5000 2141 xx fill
    pop  HL             ; 1:10      0x5000 2141 xx fill
; seconds: 0           ;[18:94]

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 03:22 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Co jsem zmenil jako prvni?

Urcovani zda INC preleza segment nebo ne.
Mel jsem na to jednoduchou metodu kdy vim ze u nasobku 2 jako je 2,4,8,16,32,64,128 max bude v te smycce max jeden 16 bitovy inc. A to kdyz mame hodnotu 0x..FF a delame ten inc a nebo kdyz ta aktualni (hodnota+1) == 0x..00.

a protoze vstup muze byt i neznama hodnota tak jsem resil odlisne pripad kdy vim ze to preleza nebo muze prelezat segment a kdy vim ze nepreleza.

Dosel jsem k zaveru ze by se me hodila nejaka funkce a dlouhe uvaze jake ma mit parametry a nasledne nekolika prepsanich, protoze to slo udelat lepe jsem dospel k tomuto:

__INC_REG16(jmeno_registroveho_paru, pocatecni_adresa, pocatecni_prirustek, delka_smycky. pocet_opakovani)

Pocatecni prirustek je v podstate jen proto, aby me nemrsil pocatecni hodnotu u ktere musi jit poznat ze to je hodnota, ukazatel nebo neznama. A taky se pouziva prehledne v tech smyckach na jake pozici je to INC.

Pokud totiz udelam "(0x8000)+1" tak uz by to nebyl ukazatel. Pokud je to totiz ukazatel tak je to konecna a vysledek bude vzdy 16 bitovy inc.

Pokud je to hodnota tak to bude vnitrne krokovat do poctu opakovani a vrati 8 bitovy inc a nebo v prubehu krokovani narazi na hodnotu 0x..FF a vrati 16 bitovy inc s peknym popiskem kde to absolutne nastava a v jakem opakovani smycky atd.

Pokud je to neznama tak tady zacinaji cachry. Pro kazdy kro bude generovat jednu podminku do IF prekladace.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh 'PUSH3_FILL(adresa,11,xx)'
                       ;[15:228]    adresa 11 xx fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      adresa 11 xx fill
    ld   HL, adresa     ; 3:10      adresa 11 xx fill   addr
    ld   BC, 0x0500+xx  ; 3:10      adresa 11 xx fill   B = 5x, C = xx
    ld  (HL),C          ; 1:7       adresa 11 xx fill
  if (1&&255&(adresa+1)&&255&(adresa+3)&&255&(adresa+5)&&255&(adresa+7)&&255&(adresa+9))
    inc   L             ; 1:4       adresa 11 xx fill
  else
    inc  HL             ; 1:6       adresa 11 xx fill
  endif
    ld  (HL),C          ; 1:7       adresa 11 xx fill
  if (1&&255&(adresa+2)&&255&(adresa+4)&&255&(adresa+6)&&255&(adresa+8)&&255&(adresa+10))
    inc   L             ; 1:4       adresa 11 xx fill
  else
    inc  HL             ; 1:6       adresa 11 xx fill
  endif
    djnz $-4            ; 2:13/8    adresa 11 xx fill
    ld  (DE),A          ; 1:7       adresa 11 xx fill
    pop  HL             ; 1:10      adresa 11 xx fill
; seconds: 0           ;[17:95]

Takze vysledek bude skoro stejny jako kdyz adresu M4 zna, coz ale neni uplna pravda, protoze M4 muze zvolit jiny algoritmus pokud napr. adresa zacina v nule.

Existuji ale pripady kdy uz obecne je znamo ze to musi byt 16 bitovy inc a nebo nikdy nebude.

Napriklad pokud pocet opakovani je vic jak 256 a krok je lichy tak vzdy preleza segment.
Pokud je pocet opakovani vic jak 256 a cislo je nasobkem 2 tak v jednom pripade vzdy preleza segment a v ostatnich nikdy. Takze misto postupneho uvadeni vsech kroku tady uz staci mit jen tu podminku pro ((adresa+1) & (krok-1)) != 0 --> nepreleza.

Po case me docvaklo ze pro jakekoliv sudy krok smycky bude polovina INC vzdy mijet predel. Ale druha polovina se bude chovat jako kdyby ten krok byl polovicni.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/Automatic$ ../check_word.sh '__INC_REG16(HL,adr,0,6,271)'
  if (1 & (adr+1))
    inc   L             ; 1:4       __INFO   only even numbers
  else
    inc  HL             ; 1:6       __INFO   6 is even step && (271 times>255) && odd number
  endif
; seconds: 0           ;[ 2:10]


Takze shrnuti do 256 opakovani se provede postupny test a nad staci obecny test.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 05:38 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Ted trochu pokus o matematiku (nebo spis poctarstvi).

Nemel jsem vubec tuseni jak se vlastne chovaji ty nasobky cisel a kdy pretinaji ten segment a tohle asi neni tema, ktere bych nasel na wiki a v semestrech matiky jsme tohle neprobirali a i kdyby ano jako jak prevest kouli na plochu pres imaginarni zobrazeni tak, aby se zachovalaly v lokalnim miste uhly, nebo delky, nebo neco jineho (vsechno zachovat nejde) tak uz jsem to davno zapomnel. Az na to ze se tam delali derivace derivaci derivaci a ten wtf moment proc sakra potrebuji to i. Ale matika je takova, proste nejaka realne neexistuji plocha jako mezivysledek mezi kouli a rovinou pomaha. Ke vsemu jsme to meli nastudovat my a vysvetlit tride a na vyber byla knizka v rustine nebo anglictine a ja se ucil nemecky... internet v pocatcich... Sorry za oftopic.

A protoze me to nezastavi, tak jsem si na papir to pokousel aspon nejak sesumirovat.

Jak to popsat srozumitelne... hmm...

Mame treba smycku o kroku 5 a vime ze budeme zacinat v nulovem ofsetu (vyjma).
Kód:
5->4 dec HL/L
     ld (HL),A
4->3 dec HL/L
     ld (HL),A
3->2 dec HL/L
     ld (HL),A
2->1 dec HL/L
     ld (HL),A
1->0 dec L      ...chceme nastavit vlajku na zero
     ld (HL),A  ...vcetne takze ukladame

Co potrebujeme vedet zda v tom poslednim dec L se ta smycka neukonci predcasne v nejakem jinem segmentu a jaky je maximalni rozsah.
Pak by bodlo zjistit kolik v te smycce bude dec L a kolik dec HL.
Pro jednoduchost budeme predpokladat ze zaciname taky na nulovem ofsetu.

Budeme analyzovat to posledni dec L.
Adresa tam (zpetne) nabyva hodnot:
adr+0, +5, +10, +15, ...+255,+260=+4,+9,+14,...+249,+254,+259=+3,+8,...

Takze pokud chceme vedet zda tam bude nekdy nula tak staci pouzit x*265 mod 5

256 mod 5 = 1
512 mod 5 = 2
768 mod 5 = 3
1024 mod 5 = 4
1280 mod 5 = 0

Takze dalsi nula by byla pro adr+5*256.

A kdy nastane predel uvnitr smycky?
To bude kdyz adresa+x byla nulova a po dec je 0x..FF.
Pro posledni dec je to
Kód:
dec
4 9 14 ..   3 8 13 ..   2 7 12 ..   1 6 11 ..   0 5 10 +5 255
dec
3 8 13 ..   2 7 12 ..   1 6 11 ..   0 5 10 +5 255 4
dec
2 7 12 ..   1 6 11 ..  [0]5 10 +5 255 4  9 ..     3
dec
1 6 11 ..  (0)5 10 +5 255 4  9 ..     3  8 ..     2
dec
0 5 10 +5 255 4  9 ..     3  8 ..     2  7 ..     1

presne adr+256. Dal jsem to do kulatych zavorek. Pro predposledni 512 viz hranate zavorky atd.
To je ale problem, protoze posledni dec ma byt 8 bitove aby nastavilo vlajky a ted se dozvidame ze zaroven musi byt 16 bitove uz od 256 hodnot.
To same vyleze pro krok 3,15,17 atd. Pokazde kdyz 256 mod krok je 1.
Nastesti ta smycka jde otocit kdyz konci v nule a pouzit INC...

Pro jine kroky to dela jine vysledky takze ukazi prvne tabulku kdy v B sloupci je KROK, v radku 2 je segment. Segment*256=offset.
A v te tabulce je zbytek po deleni toho nasobku segmentu velikosti kroku.
Příloha:
step_loop_1600.png
step_loop_1600.png [ 738.85 KiB | Zobrazeno 1604 krát ]

Je videt ze nejlepsi volbou jsou prvocisla. Ale krome nich vedou i (2^x)+-1.
Pak tu jsou nejake prekvapive hodnoty jako 9,15 atd. a z nich se nakonec da odvodit, ze asi plati vzorec, kdy po faktoricaci hodnoty KROKU zrusite vsechny dvojky (nebo nahradite dvojku jednickou) a zbyvajici prvocisla znovu vynasobite, tak mate kolik segmentu muze byt velky rozsah, nez by se to opakovalo. Bez hlubsich dukazu.
Stejne pro prakticky pouziti ma vyznam jen maly krok kvuli setreni mistem ve smycce, takze misto matiky staci pouzit tabulku. :D
A pokochat se tou diagonalou co je optimum (rozsah = krok*256) a videt i ostatni paprsky, nektere zatim jen v naznaku, ale je videt ze se budou opakovat.

Hmm... uz je pozde a nedostal jsem se ani k polovine co jsem chtel rici. .)))

Tak snad jindy.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 11:47 
Offline
Óm Nejvyšší

Registrován: 22.05.2013, 21:14
Příspěvky: 3642
Bydliště: Bratislava
Has thanked: 371 times
Been thanked: 788 times
Ty sa teraz na mna asi budes velmi hnevat, ale celu tu tvoju rozsiahlu uvahu o delitelnosti a prekracovani segmentu s INC HL alebo INC L kludne zahod do kosa :)

Totiz, toto vobec nie je treba. Pokial chces robit rychle zmazanie bloku, tak si uplne vystacis so zakladnou strudlou kodu typu
Kód:
DUP 16
ld (hl),a
inc l
EDUP
(DUP znamena opakuj N-krat nasledujuci kod)
Pokial potrebujes mazat menej bajtov nez 16, tak proste skocis niekam doprostred tejto strudly, podla toho kolko bajtov potrebujes mazat. Pokial potrebujes mazat viac, napr. 16*N+X bajtov, tak celu strudlu uzavries do slucky, prvy krat skocis na miesto ktore najprv zmaze X bajtov, a nasledne sa v slucke N-krat vykona cela tato strudla kodu. Pokial potrebujes prechadzat cez hranicu 256b segmentov, tak ako prvu slucku mozes pouzit
Kód:
slucka:
DUP 16
ld (hl),a
inc l
EDUP
jr nz,slucka
inc h
pricom pre cast bloku v prvom 256b segmente skocis do strudle na vhodne miesto tak, aby si na konci strudle bol s adresou na nasobku 16 a nasledne jr nz,slucka zabezpeci zmazanie pameti az do konca segmentu. Potom staci inc h a ak potrebujes zmazat cely dalsi segment, tak postaci znovu skok na zaciatok strudly. Ak posledny segment, ktory mazes, nevyplna celych 256 bajtov, potom postupujes vyssie spominanym sposobom pre mazanie 16*N+X bajtov.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 18:17 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Busy píše:
Ty sa teraz na mna asi budes velmi hnevat, ale celu tu tvoju rozsiahlu uvahu o delitelnosti a prekracovani segmentu s INC HL alebo INC L kludne zahod do kosa :)

Totiz, toto vobec nie je treba. Pokial chces robit rychle zmazanie bloku, tak si uplne vystacis so zakladnou strudlou kodu typu
Kód:
DUP 16
ld (hl),a
inc l
EDUP
(DUP znamena opakuj N-krat nasledujuci kod)
Pokial potrebujes mazat menej bajtov nez 16, tak proste skocis niekam doprostred tejto strudly, podla toho kolko bajtov potrebujes mazat. Pokial potrebujes mazat viac, napr. 16*N+X bajtov, tak celu strudlu uzavries do slucky, prvy krat skocis na miesto ktore najprv zmaze X bajtov, a nasledne sa v slucke N-krat vykona cela tato strudla kodu. Pokial potrebujes prechadzat cez hranicu 256b segmentov, tak ako prvu slucku mozes pouzit
Kód:
slucka:
DUP 16
ld (hl),a
inc l
EDUP
jr nz,slucka
inc h
pricom pre cast bloku v prvom 256b segmente skocis do strudle na vhodne miesto tak, aby si na konci strudle bol s adresou na nasobku 16 a nasledne jr nz,slucka zabezpeci zmazanie pameti az do konca segmentu. Potom staci inc h a ak potrebujes zmazat cely dalsi segment, tak postaci znovu skok na zaciatok strudly. Ak posledny segment, ktory mazes, nevyplna celych 256 bajtov, potom postupujes vyssie spominanym sposobom pre mazanie 16*N+X bajtov.


Diky za rekaci! Precetl jsem, pochopil jsem, ale nic noveho.

Moje rekace na reakci.
Zaprve se urcite nezlobim a jsem jen rad, ze se me nekdo snazi pomoct. .)
V prvni casti uvadis variantu kdy zname adresu a vime ze nepreleza segment a rozsah je 16 bajtu.
Predpokladam ze konkretne 16 uvadis prave protoze ze jsi ochotny a mas nekde rutinu co ty useky deli na bloky o 16 bajtech.
Je to nasobek 2 takze to ma nejake specialni efekty.
Ja uz nasobek 8 povazuji za prilis velky a volim nasobek 4 kvuli velikosti kodu nebo 2.

Takze pokud mam rozsah 16 a nedelim segment a nepomuze me zadna optimalizace, tak kod bude
Kód:
                       ;[14:316]    0x5678 16 0x33 fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      0x5678 16 0x33 fill
    ld   HL, 0x5678     ; 3:10      0x5678 16 0x33 fill   addr
    ld   BC, 0x0833     ; 3:10      0x5678 16 0x33 fill   B = 8x, C = 0x33
    ld  (HL),C          ; 1:7       0x5678 16 0x33 fill
    inc   L             ; 1:4       0x5678 16 0x33 fill   only even numbers
    ld  (HL),C          ; 1:7       0x5678 16 0x33 fill
    inc   L             ; 1:4       0x5678 16 0x33 fill
    djnz $-4            ; 2:13/8    0x5678 16 0x33 fill
    pop  HL             ; 1:10      0x5678 16 0x33 fill
; seconds: 0           ;[14:76]

Je to 14 bajtu oproti 32, jak jsem rikal snazim se to velikostne drzet v rozumnych mezich te varianty s LDIR.
Ale co udelas kdyz nebudes znat tu adresu?
Me to vygeneruje neco jineho
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH3_FILL(_a,16,0x33)'
                       ;[14:332]    _a 16 0x33 fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      _a 16 0x33 fill
    ld   HL, _a         ; 3:10      _a 16 0x33 fill   addr
    ld   BC, 0x0833     ; 3:10      _a 16 0x33 fill   B = 8x, C = 0x33
    ld  (HL),C          ; 1:7       _a 16 0x33 fill
  if (1&&255&(_a+1)&&255&(_a+3)&&255&(_a+5)&&255&(_a+7)&&255&(_a+9)&&255&(_a+11)&&255&(_a+13)&&255&(_a+15))
    inc   L             ; 1:4       _a 16 0x33 fill
  else
    inc  HL             ; 1:6       _a 16 0x33 fill
  endif
    ld  (HL),C          ; 1:7       _a 16 0x33 fill
  if (1&&255&(_a+2)&&255&(_a+4)&&255&(_a+6)&&255&(_a+8)&&255&(_a+10)&&255&(_a+12)&&255&(_a+14)&&255&(_a+16))
    inc   L             ; 1:4       _a 16 0x33 fill
  else
    inc  HL             ; 1:6       _a 16 0x33 fill
  endif
    djnz $-4            ; 2:13/8    _a 16 0x33 fill
    pop  HL             ; 1:10      _a 16 0x33 fill
; seconds: 1           ;[16:88]

U te posloupnosti LD (HL),A INC L by asi mozna slo pouzit nejake makro prekladace. Snad.

U druhe casti ukazujes metodu ktera zacina nekde uprostred segmentu, preleza nahoru 1x segment a konci na nulovem ofsetu( vyjma).
Tady me to bude genorovat kod zavisly od toho jestli je ten rozsah nasobkem neceho.
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH3_FILL(0x5000-5*81,5*81,0x33)'
                       ;[14:6092]   0x5000-5*81 5*81 0x33 fill   fill(addr,u,char)   variant >0: fill(num,3*135 (max 256),?)
    ld   BC, 0x4E6B     ; 3:10      0x5000-5*81 5*81 0x33 fill   addr
    ld    A, 0x33       ; 2:7       0x5000-5*81 5*81 0x33 fill   char
    ld  (BC),A          ; 1:7       0x5000-5*81 5*81 0x33 fill
    inc   C             ; 1:4       0x5000-5*81 5*81 0x33 fill
    ld  (BC),A          ; 1:7       0x5000-5*81 5*81 0x33 fill
    inc  BC             ; 1:6       0x5000-5*81 5*81 0x33 fill   0x4EFF=0x5000-5*81+1+3*49
    ld  (BC),A          ; 1:7       0x5000-5*81 5*81 0x33 fill
    inc   C             ; 1:4       0x5000-5*81 5*81 0x33 fill
    jp   nz, $-6        ; 3:10      0x5000-5*81 5*81 0x33 fill
; seconds: 0           ;[14:62]
nebo neni
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH3_FILL(0x5000-5*81-1,5*81+1,0x33)'
                       ;[14:7547]   0x5000-5*81-1 5*81+1 0x33 fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      0x5000-5*81-1 5*81+1 0x33 fill
    ld   HL, 0x4E6A     ; 3:10      0x5000-5*81-1 5*81+1 0x33 fill   addr
    ld   BC, 0xCB33     ; 3:10      0x5000-5*81-1 5*81+1 0x33 fill   B = 203x, C = 0x33
    ld  (HL),C          ; 1:7       0x5000-5*81-1 5*81+1 0x33 fill
    inc   L             ; 1:4       0x5000-5*81-1 5*81+1 0x33 fill   only even numbers
    ld  (HL),C          ; 1:7       0x5000-5*81-1 5*81+1 0x33 fill
    inc  HL             ; 1:6       0x5000-5*81-1 5*81+1 0x33 fill   0x??FF=0x5000-5*81-1+1+2*180
    djnz $-4            ; 2:13/8    0x5000-5*81-1 5*81+1 0x33 fill
    pop  HL             ; 1:10      0x5000-5*81-1 5*81+1 0x33 fill
; seconds: 1           ;[14:78]
Nebo adresu neznam
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH3_FILL(_a,5*81+1,0x33)'
                       ;[14:7547]   _a 5*81+1 0x33 fill   fill(addr,u,char)   variant: fill(?,max 513,no ptr)
    push HL             ; 1:11      _a 5*81+1 0x33 fill
    ld   HL, _a         ; 3:10      _a 5*81+1 0x33 fill   addr
    ld   BC, 0xCB33     ; 3:10      _a 5*81+1 0x33 fill   B = 203x, C = 0x33
    ld  (HL),C          ; 1:7       _a 5*81+1 0x33 fill  if 0x01 & (_a+1)
    inc   L             ; 1:4       _a 5*81+1 0x33 fill
  else
    inc  HL             ; 1:6       _a 5*81+1 0x33 fill
  endif
    ld  (HL),C          ; 1:7       _a 5*81+1 0x33 fill  if 0x01 & (_a+2)
    inc   L             ; 1:4       _a 5*81+1 0x33 fill
  else
    inc  HL             ; 1:6       _a 5*81+1 0x33 fill
  endif
    djnz $-4            ; 2:13/8    _a 5*81+1 0x33 fill
    pop  HL             ; 1:10      _a 5*81+1 0x33 fill
; seconds: 0           ;[16:88]


Ohledne toho skoku doprostred toho LD (HL),A INC C.
Ano jsem si to vedom ze tohle jde pouzivat.
Ja mam takovy skok zatim jen jeden, protoze kdyz mam smycku kde se nacitaji 4 bajty tak vznikaji moznosti:

je to delitelne 4 -> ok nic neresim
zbyva jeden bajt -> to je rychlejsi a kratsi na konec pridat jeden ld (HL),A
zbyvaji 2 bajty -> velka sance ze to odchytne delitelnost 6, pokud ne tak priavam 3 bajty misto 2 u skoku ale je to rychlejsi, protoze tam neni skok a jeste tam neni jeden skok pro smycku
zbyvaji 3 bajty -> je sance ze to odchytne delitelnost 5 nebo 7, pokud ne tak priavam 5 bajtu :( misto 2 u skoku ale je to stale rychlejsi, protoze tam neni skok a jeste tam neni jeden skok pro smycku.

Otazka toho ze usetrim 2 taky pro smycku, kdyz to budu resit metodou, ze smycka bude koncit na nule.
V nekterych variantach to pouzivam.
Chapu jak to myslis, ze skokem (vhodne pro podprogram), nebo pridanim na zacatek pred smyckou bonusove LD (HL),A si nastavim konec smycky tak ze bude koncit v nule a behem smycky nikdy nebude prelezat segment.

To ale plati jen pro variantu kdy to konci (vyjma) na nulovem ofsetu takze obecne me to dela jine varianty.

Mam v hlave jeste variantu s podprogramem, kde by se delalo prave co navrhujes. A protoze je to podprogram tak bych si mohl dovolit vic bajtu. Myslel jsem teda krok 8 (12.25 taktu na bajt) a ne 16 (11.625 taktu na bajt)... az tak moc prostoru neobetuji, nema to byt prekladac pro dema. :)

Jen by ty smycky byly dve. Jedna co dosahne segmentu a pak nekolikrat prekroci segment podle potreby. Druha by pokracovala sestupne v tom poslednim segmentu.

K tomu jsem se ale nedostal.
Chapu teda ten bod, ze se mohu uplne obejit bez INC/DEC HL a vystacit si s INC/DEC L. Jen ty varianty jsou proste pak delsi nez co ted leze me.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 18:20 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Jeste ukazka, kde teda skok do smycky mam, ale jen proto ze to JR sezere jen jeden bajt. Protoze je to JR $+2 a spolkne to LD (BC),A a az pak skoci o 2
Kód:
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$ ../check_word.sh 'PUSH3_FILL(0x5000-5*113+2,5*113-2,0x33)'
                       ;[19:7808]   0x5000-5*113+2 5*113-2 0x33 fill   fill(addr,u,char)   variant >0: fill(num,5*113-2 (max 1280),?)
    ld   BC, 0x4DCC     ; 3:10      0x5000-5*113+2 5*113-2 0x33 fill   addr = (0x4DCD..0x4FFF)
    ld    A, 0x33       ; 2:7       0x5000-5*113+2 5*113-2 0x33 fill   char
    db 0x18             ; 1:12      0x5000-5*113+2 5*113-2 0x33 fill   db 0x18,0x02 = jr $+4
    ld  (BC),A          ; 1:7       0x5000-5*113+2 5*113-2 0x33 fill
    inc   C             ; 1:4       0x5000-5*113+2 5*113-2 0x33 fill
    ld  (BC),A          ; 1:7       0x5000-5*113+2 5*113-2 0x33 fill
    inc   C             ; 1:4       0x5000-5*113+2 5*113-2 0x33 fill
    ld  (BC),A          ; 1:7       0x5000-5*113+2 5*113-2 0x33 fill
    inc  BC             ; 1:6       0x5000-5*113+2 5*113-2 0x33 fill   0x4DFF=0x5000-5*113+2+0+5*10
    ld  (BC),A          ; 1:7       0x5000-5*113+2 5*113-2 0x33 fill
    inc  BC             ; 1:6       0x5000-5*113+2 5*113-2 0x33 fill   0x4EFF=0x5000-5*113+2+1+5*61
    ld  (BC),A          ; 1:7       0x5000-5*113+2 5*113-2 0x33 fill
    inc   C             ; 1:4       0x5000-5*113+2 5*113-2 0x33 fill
    jp   nz, $-10       ; 3:10      0x5000-5*113+2 5*113-2 0x33 fill
; seconds: 0           ;[19:98]
dworkin@dw-A15:~/Programovani/ZX/Forth/M4$

Skoro ten pripad kdy to zacina obecne a konci nulovym ofsetem. Jen tohle dokaze prelezt pres 2 segmenty, protoze to pouzije ten nasobek peti.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 27.02.2023, 18:57 
Offline
Óm Nejvyšší

Registrován: 22.05.2013, 21:14
Příspěvky: 3642
Bydliště: Bratislava
Has thanked: 371 times
Been thanked: 788 times
_dworkin píše:
Predpokladam ze konkretne 16 uvadis prave protoze ze jsi ochotny a mas nekde rutinu co ty useky deli na bloky o 16 bajtech.
Nie, 16 bol len priklad, mozes pouzit lubovolnu dlzku strudly kodu. Cim bude dlhsia, tym rychlejsie pobezi, a cim kratsia, tym kratsi bude kod. Je to o kompromise. Ale obecne je dobre volit dlzku 2^N lebo s takymito hodnotami sa lahsie pocita, hlavne celociselne delenie hodnotou 2^N s podielom a zvyskom sa robi v strojaku velmi dobre.
_dworkin píše:
Ale co udelas kdyz nebudes znat tu adresu?
Akoze nebudem ? Adresa (a aj dlzka) musi byt znamy parameter pre mazaciu rutinku, inak by nevedela co ma mazat :)
A ked vieme adresu aj dlzku, mozeme podla toho rozvetvit kod na najlepsi variant pre dane vstupne parametre.
_dworkin píše:
To ale plati jen pro variantu kdy to konci (vyjma) na nulovem ofsetu takze obecne me to dela jine varianty.
Nie, nemusi nutne koncit na nulovom offsete. Skusim to napisat nazornejsie. Ked budes chciet mazat blok o dlzke 16*N+X (ktory vobec nemusi koncit na nejakej okruhlej adrese) v ramci jedneho segmentu, tak mozes pouzit napr takuto rutinku:
Kód:
slucka:
 DUP 16
  ld (hl),a
  inc l
 EDUP
koniec:
  djnz slucka
pricom do rutinky skocis na adresu koniec-2*X a s B nastavenym na N.
_dworkin píše:
A protoze je to podprogram tak bych si mohl dovolit vic bajtu. ...
...az tak moc prostoru neobetuji, nema to byt prekladac pro dema. :)
Ten podprogram nie je zly napad, to potom nemusis ani moc priestoru obetovat, ked to cele bude iba raz v pameti. Vsetko je to o kompromise dlzky a rychlosti.
_dworkin píše:
Jen by ty smycky byly dve. Jedna co dosahne segmentu a pak nekolikrat prekroci segment podle potreby. Druha by pokracovala sestupne v tom poslednim segmentu.
Nie nutne. Tu mozes urobit taku fintu, ze problem mazania bloku cez viac segmentov prevedies na mazanie viac blokov v ramci segmentu :) Proste, nasekas si blok na segmenty a pre kazdy zavolas tu vyssie napisanu rutinku. Pre cely segment nastavis B=16 a zavolas ju od zaciatku s HL nastavenym na zaciatok segmentu. V pripade, ze DUP 16 je moc, a pouzijes napr. len DUP 8, tak potom samozrejme bude B=32.

====

Este jedna prosba: Prosim nepis skoky stylom jr $-16 lebo tam uz nie je hned jasne kam to skace, radsej pouzi nejaky label nech je to hned vidno. Nie kazdemu sa chce rucne odratavat instrukcie...


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 28.02.2023, 05:42 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1100
Has thanked: 100 times
Been thanked: 157 times
Pokud jsem to pochopil spravne a trosku upravil, protoze fakt nechci volat pro kazdy segment znovu tu funkci tak tvuj navrh je tohle.
Kód:
Fill:                  ;[37:B*191+5]Fill   B=0=4096 bytes
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc   E             ; 1:4       Fill
    ld  (DE),A          ; 1:7       Fill
    inc  DE             ; 1:6       Fill
Fill_end:
    djnz Fill_Up        ; 2:8/13    Fill
    ret                 ; 3:10      Fill
; seconds: 0           ;[37:196]

Tohle je ta funkce, ma jedno "inc DE", to je dan za to, ze je schopna prelezat segmenty.
Tim jsou vyreseny:

- vsechny pripady do 256 bajtu neprelezajici segment. Tam se to proste vola B=1+rozsah/16, a call Fill_end-2*(rozsah mod 16). Pokud je zbytek nula tak by to slo volat B=rozsah/16 a call Fill.

- vsechny pripady do cca 0..16 + 255*16 bajtu kdy to konci na adrese delitelne 16, vcetne prelezani segmentu. Dalo by se pocitat i to kdyz adresa kde to konci ma zbytek 1, pak staci jen pridat jedno ld (DE),A.

- pokud je to delsi tak se to musi volat znovu pro kazdy 4kb

- a pokud to prelezlo segment a nekonci to na adrese delitelne 16 tak se to musi volat jeste naposledy jako pro prvni pripad.

Takze obecne se to musi volat cca 2x...
A jak by vypadalo to volani?
Kód:
    exx                           ; 1:4       __INFO   fill(addr,u,char)
    ld    A, char                 ; 2:7       __INFO
    ld  (DE),addr                 ; 3:10      __INFO
    ld    B, (u+(addr&15))>>4     ; 2:7       __INFO   ma to byt mensi nez 4kb, takze to nepreleze 256, pridam vypln do 16 na zacatku a tim zvednu B o 1 (pokud to neni delitelne 16)
    call Fill+2*(addr&15)         ; 3:17      __INFO
    inc   B                       ; 1:4       __INFO
    call Fill_end-2*((u+addr)&15) ; 3:17      __INFO   zde zjistim zbytek v rozsahu do 16, co jsem prvne vyhodil pres >>4
    exx                           ; 1:4       __INFO
; seconds: 0           ;[16:70]

16 bajtu... to neni vubec pekne, to uz je skoro jako nektere kratsi rutiny. LDIR rutina ma 17, ale zase je nejpomalejsi.
Dal by se ubrat bajt a 4 takty, kdyby char urcite nebyl ukazatel, takze misto exx by se pouzil push/pop hl a char by sel do registru C a podprogram by fungoval na LD (HL),C. Ale pokud by byl posledni parametr ukazatel, tak by se to otocilo a HL varianta by byla zase o bajt a 4 takty horsi.

Kdybych nacital jen ty tri parametry a zbytek si pomalu osetroval az za behu ten podprogram, tak je to 12 bajtu. To je uplne minimum (a jeste neprakticke minimum) pokud chci zachovat co musim.
Kód:
    ld   BC, addr       ; 3:10      __INFO
    push BC             ; 1:11      __INFO
    ld   BC, u          ; 3:10      __INFO
    ld    A, char       ; 2:7       __INFO
    call Fill           ; 3:17      __INFO
; seconds: 0           ;[12:55]


Z praktickeho hlediska me prijde, ze asi nesnazsi varianta je mit ten podprogram udelany tak, ze kazdy lichy bajt je INC E a kazdy sudy bajt INC DE. Tim se zaruci ze to nebudu muset volat pro ukonceni a bud to sedne a nebo pridam jen LD (DE),A.
Kód:
    exx                           ; 1:4       __INFO   fill(addr,u,char)
    ld    A, char                 ; 2:7       __INFO
    ld  (DE),addr                 ; 3:10      __INFO
    ld    B, (u+(addr&1))>>4     ; 2:7       __INFO   ma to byt mensi nez 4kb, takze to nepreleze 256, pridam vypln do 16 na zacatku a tim zvednu B o 1 (pokud to neni delitelne 16)
    call Fill+2*(addr&1)         ; 3:17      __INFO
  if ((u+addr)%1)
    ld  (DE),A                    ; 1:7       __INFO
  endif
    exx                           ; 1:4       __INFO
; seconds: 0           ;[13:56]

12 nebo 13 bajtu. Jedine omezeni je ten rozsah 4 kb pokud rozkopiruji 16x ld (DE), A
Tady se vlastne uz ani nemusim drzet toho ze by to mela byt mocnina dvou a staci sude cislo. Idealne podle toho na co se to pouzije. Pokud se tim bude opakovane mazat obrazovka tak 24 (28 i s atributami). Pokud neco mensiho tak mensi cislo.
A vlastne i to zda je to inc DE/E by slo osetrit podle vsech pouziti... ale to uz je na bolest hlavy.

PS: Parametr muze byt cislo/hodnota, tim myslim cokoliv co lze spocitat na hodnotu. Pak parametr muze byt neznama hodnota, to je nejake jmeno nezname promenne, nebo vyraz, ktery ho obsahuje. Mysleno neznama pro prekladac (M4 Forth), ale ne uz pro linker (pasmo). M4 proste nevi, a musi si pomoct pres makra linkeru, ale vysledek byva horsi nez kdyz je to znama hodnota, protoze ne vse se osetruje a vetsinou se voli jiny algoritmus. Posledni a nejhorsi pripad je, kdyz je to ukazatel. .) Ale i tam se obcas snazi o nejake optimalizace (stejne jako u nezname), ale to uz je jen takove porovnani retezcu a kdyz potrebuji do HL nacist "abc" a vi ze v DE je "1+abc-1" tak to nepozna ze je to shodne.

_________________
Z80 Forth compiler (ZX Spectrum 48kb): https://codeberg.org/DW0RKiN/M4_FORTH


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 28.02.2023, 12:19 
Offline
Óm Nejvyšší

Registrován: 22.05.2013, 21:14
Příspěvky: 3642
Bydliště: Bratislava
Has thanked: 371 times
Been thanked: 788 times
Ty sa teraz na mna asi budes velmi hnevat, ale celu tu nasu doterajsiu diskusiu mozeme kludne zahodit do kosa :)
_dworkin píše:
Nejefektivnejsi je pouzit zasobnik:
push HL ...11 taktu na 2 bajty = 5.5 taktu na bajt
Ale to vyzaduje vedet zda je povolene preruseni nebo zakazane a zakazat ho, schovat si hodnotu SP, presunout ho a opakovane od hornich adres pushovat ke spodnim.
Jenze co kdyz nekdo bude chtit aby bezelo neco na pozadi a s konstantnim intevalem 50x za vterinu?
Hudbu asi na pozadi ne, to se bude muset asi resit nejen prerusenim (dokonce by melo byt asi zakazane), ale kouskovat kod na casove konstatni intervaly mnohem kratsi jak 50 za vterinu (klidne s pouzitim vyplne) a mezitim pravidelne obsluhovat zvuk (teda menit jeden bit na zapnuto vypnuto).
Pravdepodobne hlavny dovod, preco nechces pouzit mazanie zasobnikom, je to prerusenie, ktore ti zasvini pamet na ktoru ukazuje SP.
To je sice pravda, a v pripade (napriklad) citania dat pomocou SP je to velmi kriticke, ale v pripade mazania bloku PUSHmi to mozeme veselo odignorovat. Prerusenie totiz zasvini iba tu pamet, ktora je pod aktualnou hodnotou SP, a teda ktora este len bude zmazana. Takze vobec netreba ani prerusenie zakazovat, a aj nejaka hudba na pozadi moze kludne hrat :)

Staci iba zabezpecit, aby nam nevadilo prepisanie pameti tesne pred mazanym blokom, t.j. ked pride prerusenie na konci mazania pred obnovou SP alebo tesne pred tymto koncom. A to mozeme urobit dvomi sposobmi:

1. Nechat pred mazanym blokom zoparbajtovu rezervu, kde nebude nic dolezite
2. Nemazat cely blok PUSHmi, ale poslednych (resp. prvych v bloku a poslednych mazanych) par bajtov nemazat PUSHmi, ale nejak inak.

Aka velka ma byt ta rezerva, resp. kusok bloku ktory sa uz nebude mazat PUSHmi, zavisi samozrejme od toho, kolko miesta na zasobniku prerusenie potrebuje.

Ale aj tu mozeme urobit jeden (skaredy) hack. Prerusenie bude vyzerat takto:
Kód:
interrupt:
  ld (old_stack+1),sp
  ld sp,my_own_stack
  push ...
  push ...
  ...
  pop ...
  pop ...
old_stack:
  ld sp,hocico
  ei
  ret
Takto napisana rutinka na obsluhu prerusenia zaberie na zasobniku iba dva (cislom 2) bajty !
Takze uplne postaci pred mazanym blokom nechat dva bajty rezervu, alebo pouzit na mazanie o jeden PUSH menej a tie dva dodatocne bajty zmazat inak.
Samozrejme takto napisana obsluha prerusenia nie je reentrantna, ale v pripade ZX Spektra a jeho 50 Hz prerusenia, ktore normalne nebude trvat moc dlho, toto nebude kriticke.
Podla mna, ta mala rezia s odpametanim a obnovenim SP stoji za to mat rychlost mazania 5.5 T/bajt, aspon pri dlhsich blokoch.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 28.02.2023, 18:01 
Offline
Profík

Registrován: 26.11.2018, 16:59
Příspěvky: 580
Bydliště: Holešov
Has thanked: 13 times
Been thanked: 90 times
no já bych byl s tím přerušením hodně opatrnej, pokud by přišlo ke konci plnění, tak nějaká rutina přerušení co zatěžuje víc zásobník by mohla přetéct do oblasti kde se nemá co zapisovat (jiná proměnná)
teda předpokládám, že se tím mají plnit proměnné, ne jen nějaké bloky paměti kde je za nima volno


Nahoru
 Profil  
 
Zobrazit příspěvky za předchozí:  Seřadit podle  
Odeslat nové téma Odpovědět na téma  [ Příspěvků: 585 ]  Přejít na stránku Předchozí  1 ... 24, 25, 26, 27, 28, 29, 30 ... 39  Další

Všechny časy jsou v UTC + 1 hodina [ Letní čas ]


Kdo je online

Uživatelé procházející toto fórum: Žádní registrovaní uživatelé a 4 návštevníků


Nemůžete zakládat nová témata v tomto fóru
Nemůžete odpovídat v tomto fóru
Nemůžete upravovat své příspěvky v tomto fóru
Nemůžete mazat své příspěvky v tomto fóru
Nemůžete přikládat soubory v tomto fóru

Hledat:
Přejít na:  
cron
Založeno na phpBB® Forum Software © phpBB Group
Český překlad – phpBB.cz