OldComp.cz

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


Právě je 19.04.2024, 21:23

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




Odeslat nové téma Odpovědět na téma  [ Příspěvků: 598 ]  Přejít na stránku Předchozí  1 ... 5, 6, 7, 8, 9, 10, 11 ... 40  Další
Autor Zpráva
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 02.07.2020, 22:40 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Kubik píše:
Co jsou rekurzivni smycky? Nemyslis vnorene?


Pod vnorene bych si predstavil
Kód:
for(i=100;i>=0;i--)
   for(j=100;j>=0;j--)
     neco();

Tahle smycka jde napsat tak ze ulozis do pameti promenou (v kodu je treba ld BC, 100 ... dec BC \ ld A, B \ or C \ jr nz, $-x) a nemuze se nic stat. Ta "j" smycka se proste vykona a pak vytvori znova.

Pod rekurzivni myslim kdy mam funkci.
Kód:
funkce() {
   int i;
   for(i=100;i>=0;i--)
   {
       funkce();
   }
}
Kde ta funkce vola sama sebe a nebo uvnitr smycky vola jinou funkci ktera nekdy zase bola zpetne ji. Takze pokud by promenna "i" byla definovana v pameti tak bude prepsana znovu na 100 a pak ukoncena na -1. Takze puvodni funkce bude zacinat 100 a pak hned skonci. Takze rekurzivni smycky jsem myslel ty co preziji rekurzi.

PS: Takze te rekurzivni smycky nezajimaji pokud nemas rekurzivni funkce a v nich smycky udelane tak nestastne ze se mohou volat znovu.

_________________
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: 02.07.2020, 22:47 
Offline
Óm Nejvyšší
Uživatelský avatar

Registrován: 28.01.2016, 23:57
Příspěvky: 3756
Has thanked: 213 times
Been thanked: 388 times
V normalnim FORTHu "i" neni promenna, ale slovo (jako ostatne vsechno ve FORTHu, co neni cislo). Parametry smycky jsou na zasobniku navratovych adres, tim padem jim je rekurze uplne jedno.

_________________
Nikdy nediskutujte s blbcem. Stáhne vás na svoji úroveň a vyhraje zkušeností.


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

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Abych to dorekl. Tak druha funkce kterou jsem zkoumal byla MUL. Puvodni byla
Kód:
; Input: HL,DE
; Output: HL=HL*DE ((un)signed)
; It does not matter whether it is signed or unsigned multiplication.
; Pollutes: AF, B, DE
MULTIPLY:
    ld    A, H          ; 1:4
    sub   D             ; 1:4
    jr    c, $+3        ; 2:7/12
    ex   DE, HL         ; 1:4       H=>D faster 7+4<12

    ld    B, H          ; 1:4       
    ld    A, L          ; 1:4
    ld   HL, 0x0000     ; 3:10

    srl   B             ; 2:8
    rra                 ; 1:4       divide BA by 2
    jr   nc, $+3        ; 2:7/12
MUL_LOOP:
    add  HL, DE         ; 1:11
    sla   E             ; 2:8
    rl    D             ; 2:8       multiply DE by 2   
    srl   B             ; 2:8
    rra                 ; 1:4       divide BA by 2
    jr    c, MUL_LOOP   ; 2:7/12
    jp   nz, MUL_LOOP+1 ; 3:10      B = ?

    db   0x06           ; 2:7
MUL_LOOP2:
    add  HL, DE         ; 1:11
    sla   E             ; 2:8
    rl    D             ; 2:8       multiply DE by 2
    srl   A             ; 2:8       divide A by 2
    jr    c, MUL_LOOP2  ; 2:7/12
    jp   nz, MUL_LOOP2+1; 3:10      A = ?

    ret                 ; 1:10

A kdyz jsem napsal nejlepsi rozbalenou variantu tak s uzasem zjistil ze je pomalejsi jak tato. A pritom rozhodne nema nejrychlejsi kod na smycku. Ale ten trik co jsem pouzil pro predcasne ukonceni je proste prilis silny. Uz jsem to chtel vzdat. Ale aby kratsi kod byl rychlejsi nez dlouhy rozbaleny... Nakonec se mi podarilo nehezky vymyslet zrychleni pri pocatecnich nulach mensiho cisla a byt trochu rychlejsi za cenu 99 bajtu.

_________________
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: 02.07.2020, 22:52 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Kód:
; Input: HL,DE
; Output: HL=HL*DE ((un)signed)
; It does not matter whether it is signed or unsigned multiplication.
; Pollutes: AF, B, DE
MULTIPLY:
; fast variant
    ld    A, H          ; 1:4
    sub   D             ; 1:4
    jr    c, $+3        ; 2:7/12
    ex   DE, HL         ; 1:4       H=>D faster 7+4<12
   
    ld    A, H          ; 1:4
    ld    C, L          ; 1:4
    ld   HL, 0x0000     ; 3:10
   
    add   A, A          ; 1:4
    jr    c, MULTIPLY1  ; 2:7/12
    jr    z, MULTIPLY_LO; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY2  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY3  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY4  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY5  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY6  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY7  ; 2:7/12   
    jp   MULTIPLY8      ; 3:10
MULTIPLY_LO:
    ld    A, C          ; 1:4
    add   A, A          ; 1:4
    jr    c, MULTIPLY9  ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY10 ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY11 ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY12 ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY13 ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY14 ; 2:7/12
    add   A, A          ; 1:4
    jr    c, MULTIPLY15 ; 2:7/12
    add   A, A          ; 1:4
    ret  nc             ; 1:5/11
    ex   DE, HL         ; 1:4
    ret                 ; 1:10

MULTIPLY1:
    ld    H, D          ; 1:4
    ld    L, E          ; 1:4
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY2:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY3:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY4:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY5:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY6:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY7:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY8:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    ld    A, C          ; 1:4
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY9:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY10:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY11:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY12:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY13:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY14:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
MULTIPLY15:
    add  HL, DE         ; 1:11
    add  HL, HL         ; 1:11
    add   A, A          ; 1:4
    jr   nc, $+3        ; 2:7/12
    add  HL, DE         ; 1:11
    ret                 ; 1:10
PS: Zapomnel jsem dodat, ze i s touto optimalizaci se to zkrati na 44.83 vterin z 47.1 vterin. V zcc jsem jeste nezjistoval jak zapnout to rozbaleni smycek. Takze muzu porovnat jen 58.58 ku 100.47 vterin. A samozrejme to mam zas katsi. Za me dobry, na to ze jsem amater. Mozna spis smutny jak spatne jsou C prekladace pro Z80.

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


Naposledy upravil _dworkin dne 02.07.2020, 23:12, celkově upraveno 1

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

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Kubik píše:
V normalnim FORTHu "i" neni promenna, ale slovo (jako ostatne vsechno ve FORTHu, co neni cislo). Parametry smycky jsou na zasobniku navratovych adres, tim padem jim je rekurze uplne jedno.


Ja vim. Ukazoval jsem to pro C syntaxi. Ono je to prece jedno. Cely ten prekladac beru jako pochopeni jak to funguje, bez ohledu na jazyk. Forth je proste prima, ze je podle me na nizsi urovni jeste nez C. Takze, jde snaz prelozit do assembleru. Uz ty zakladni slova, postfix notace atd. Takhle v C nemas pod kontrolou co ti vyleze za kod.

Vsechny smycky jsem mel na tom zasobniku navratovych adres. Ale Z80 je proste spatne navrzeny procesor pro vic zasobniku. Jde to, ale je to pomale. A neni to potreba! Jen kdyz pouzivas rekurzi. To byl ten duvod proc jsem puvodni smycky presunul pod R. A vytvoril nove, kratsi a rychlejsi. I kdyz to take neni hitparada. .)

Viz ten priklad
Kód:
   ld BC 100
loop:
   ...
   ...
   dec bc
   ld a,b
   or c
   jr nz loop
je mnohem efektivnejsi. Ale to si muze dovolit jen clovek a nebo hodne chytry prekladac. Co zjistuje ze je to posledni smycka a nikde v ni nepouzije BC atd. Na datovy zasobnik se nemuzes spolehnout tam se muze dit ve Forthu divocina. Proto je to psany
Kód:
   ld BC 100
   ld (xxx), BC
loop:
   ...
   ...
xxx EQU $+1
   ld BC, 0
   ld a,b
   or c
   dec bc
   ld (xxx), BC
   jr nz loop
a nebo jeste sloziteji protoze tohle je nejsnazsi FOR NEXT smycka, ktera vzdy konci na nule (vcetne).

PS: A porad je to rychlejsi jak si hrat s RAS.

_________________
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: 02.07.2020, 23:37 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
A zdrojak posledniho bechmarku.
Kód:
include(`../M4/FIRST.M4')dnl
ORG 0x8000
INIT(60000)
SCALL(_bench)
STOP

define({TYPMUL},{})
define({TYPDIV},{})

COLON(_decomp,( n -- ))
    PUSH(2)
    BEGIN 
        _2DUP DUP MUL
    UGE_WHILE 
        _2DUP UDIVMOD SWAP
        IF
            DROP _1ADD PUSH_OR(1) ; next odd number
        ELSE
            NROT NIP
        THEN
    REPEAT
    _2DROP
SEMICOLON

SCOLON(_bench,( -- ))
    PUSH(10000) SFOR SI CALL(_decomp) SNEXT
SSEMICOLON

include({../M4/LAST.M4})dnl
takze je videt, ze tam neni skoro ani zadne optimalizovane slovo. Jen ">= WHILE" a "1 OR". Ani jsem nehrotil tu funkci, ktera sezere jeden parametr. A lepsi by byla kdyby vracela zase jeden a sla by volat pres datovy zasobnik jako SCALL.
Kód:
#include <stdio.h>
 
int decompose(unsigned int n)
{
    unsigned int p = 2;
       
    while (n > p * p) {
        if ( n % p ) {
            p++;
            p|=1;
        } else
        {
            n /= p;
//             printf(" %d",p);
        }
    }
//     printf(" %d",n);
}
 
int main()
{   
    int i;
    for (i = 10000; i >= 0; i--)
        decompose(i);
    return 0;
}
Je mozne ze C dokonce deli 2x.
https://github.com/DW0RKiN/M4_FORTH/blob/master/Benchmark/decomp.asm

_________________
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: 03.07.2020, 16:31 
Offline
Óm Nejvyšší
Uživatelský avatar

Registrován: 28.01.2016, 23:57
Příspěvky: 3756
Has thanked: 213 times
Been thanked: 388 times
Jeste kdyz jsme u toho, dival jsem se na rekurzi ve FORTHu. Ocividne to jde, ale zpusob, jak je to implemenovane mi naznacuje, ze je to spis hack :) Pokud potrebujes volat slovo, ktere prave definujes, tak pouzijes slovo RECURSE (nekdy se jmenuje MYSELF).

Kód:
: FACTORIAL ( +n1 -- +n2)
   DUP 2 < IF DROP 1 EXIT THEN
   DUP 1- RECURSE *
;


Dalsi moznosti je pouzit slovo RECURSIVE, to by potom bylo nejak takhle:

Kód:
: FACTORIAL ( +n1 -- +n2) RECURSIVE
   DUP 2 < IF DROP 1 EXIT THEN
   DUP 1- FACTORIAL *
;


Vzajemna rekurze neni explicitne mozna, ale existuji slova DEFER a IS, ktera umoznuji vytvorit slovo a definovat ho pozdeji, coz se da vyuzit na vzajemnou rekurzi. Ne, ze by to bylo k necemu dobre (krome matematickeho cviceni), ale moznost to je.

_________________
Nikdy nediskutujte s blbcem. Stáhne vás na svoji úroveň a vyhraje zkušeností.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 04.07.2020, 08:53 
Offline
Óm Nejvyšší

Registrován: 22.05.2013, 21:14
Příspěvky: 3663
Bydliště: Bratislava
Has thanked: 373 times
Been thanked: 797 times
Kubik píše:
Vzajemna rekurze neni explicitne mozna, ale existuji slova DEFER a IS, ktera umoznuji vytvorit slovo a definovat ho pozdeji, coz se da vyuzit na vzajemnou rekurzi. Ne, ze by to bylo k necemu dobre (krome matematickeho cviceni), ale moznost to je.
Cize nieco ako v cecku deklaracia a definicia funkcie ? Ani tam to vecsinou k nicomu nie je, ale umoznuje to napriklad pisat programy z hladiska cloveka prehladnejsie a flexibilnejsie (deklaracie do "h" suboru a pod.)


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 04.07.2020, 11:42 
Offline
Óm Nejvyšší
Uživatelský avatar

Registrován: 28.01.2016, 23:57
Příspěvky: 3756
Has thanked: 213 times
Been thanked: 388 times
No, ano a ne. Ono cely FORTH je trosku zvlastni, a divat se na nej jako na C je zavadejici, cehoz prikladem je prave kolega _dworkin, ktery vytvari zajimavy kompilator jazyka "téměř úplně, ale ne zcela naprosto nepodobného FORTHu" :)

Ve FORTHu se slova ukladaji do slovniku. Typicka definice slova (funkce) je treba
Kód:
: jednicka 1 . CR ;

Slovo ":" vytvori na konci slovniku hlavicku noveho slova a nazve ho "jednicka". Soucasne se FORTH prepne z interpretacniho modu do kompilacniho, takze dalsi slova se nebudou primo provadet, ale jejich adresy se budou ukladat do slovniku.
Dalsi slovo je "1" - to muze byt nejake definovane slovo, ale rekneme, ze neni, takze se to bere jako cislo. Protoze jsme v kompilacnim modu, tak se cislo 1 ulozi do slovniku. Presneji receno se ulozi adresa slova "LIT" a za nim jednicka, protoze jinak by se ta jednicka brala jako adresa nejakeho slova, a cele by to pri spusteni padlo.
Dalsi slovo je ".", to jest vypsani hodnoty - opet se adresa slova "." ulozi do slovniku.
To same s dalsim slovem "CR" (novy radek) - zase se jeho adresa ulozi do slovniku.
Dalsi slovo je ";", to jest konec definice. Tohle slovo ulozi do slovniku adresu slova ";EXIT", zmeni nejake ukazatele a prepne zpatky do interpretacniho modu, takze dalsi slova se zas budou primo provadet.

V pripade DEFER a IS je to tak, ze "DEFER jednicka" vytvori hlavicku slova "jednicka" ve slovniku, ale s prazdnym telem. To slovo sice nic nedela, ale uz je definovane a muze se pouzit. Pozdeji vytvoris jine slovo, treba "novajednicka" a pomoci IS ho priradis tomu puvodnimu slovu "jednicka". Jak to presne funguje netusim, musel bych se v tom povrtat :)

Rozdil proti C je ten, ze DEFER skutecne vytvari nove slovo a alokuje pro nej pamet, zatimco v C jenom reknes kompilatoru, ze nejaka takova funkce bude nekdy definovana, takze je mozne se na ni odkazovat.

_________________
Nikdy nediskutujte s blbcem. Stáhne vás na svoji úroveň a vyhraje zkušeností.


Nahoru
 Profil  
 
 Předmět příspěvku: Re: Macro FORTH
PříspěvekNapsal: 09.07.2020, 14:36 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Náhodně jsem objevil a opravil chybu v xloop. Kdy při jedne optimalizované variantě jsem pomoci copy&paste vytvořil chybu kdy podminka smyčky byla "jp c" místo "jp nz".
Kód:
idx101 EQU $+1          ;           xloop 101 lo stop == 0  && hi index != hi stop
    ld   BC, 0x0000     ; 3:10      xloop 101 idx always points to a 16-bit index
    inc  BC             ; 1:6       xloop 101 index++
    ld  (idx101),BC     ; 4:20      xloop 101 save index
    ld    A, B          ; 1:4       xloop 101
    sub  high 0         ; 2:7       xloop 101 index - stop
    jp   nz, xdo101     ; 3:10      xloop 101
xleave101:              ;           xloop 101
xexit101:               ;           xloop 101

V kodu to je videt hned, v M4 makrech se to ztraci. I kdyz delam nejake automaticke testy tak uz mam pocit, ze je to na jednoho cloveka i s testovanim velke sousto.

Puvodně jsem testoval dělení a měl jsem smyčku od 30000 včetně do 0 (vyjma) a divil se, že to proběhne moc rychle a když jsem dal výpis indexu tak to napsalo jen 30000.

_________________
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: 09.07.2020, 14:47 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
U dělení jsem opravil svůj testovaci program, kde jsem měl také špatně smyčky a netestovalo to co mělo a zjistil, že jsem to při optimalizaci dopustil chyby v dělení. Která se projevuje když se dělí číslem větším jak 128 a menším jak 256.
Puvodní fragment kódu:
Kód:
; Divide 16-bit unsigned values (with 16-bit result)
; In: DE / HL
; Out: HL = DE / HL, DE = DE % HL
UDIVIDE:
    ex   DE, HL         ; 1:4       HL/DE
    ld    A, D          ; 1:4
    or    A             ; 1:4
    jr   nz, UDIVIDE_16 ; 2:7/12
       
    ld    B, 16         ; 2:7     

    add  HL, HL         ; 1:11      2*HL
    rla                 ; 1:4                              <---------- tady nastane chyba
    cp    E             ; 1:4
    jr    c, $+4        ; 2:7/12
    inc   L             ; 1:4
    sub   E             ; 1:4
    djnz $-7            ; 2:13/8

    ld    E, A          ; 1:4       DE = DE % HL
    ret                 ; 1:10      HL = DE / HL

Tahle část je pro případ kdy zjistíme že dělitel je osmibitový. Idea je že se vytvoří 24 bitový registr AHL, kde postupně posunem po bitu načítáme do A vyšší bity z HL a pokud to jde odečteme od A dělitele.
Pokud je ale dělitel větší jak 128 tak se od A nepodaří nic odečíst dokud A nepřeteče.

Takže rychlá oprava je udělat pokaždé test po RLA a pokud se zjistí přetečení tak se skočí hned na odčítání. Prvních 8 posunů tu nemůže nastat, až u devátého.
Kód:
; Divide 16-bit unsigned values (with 16-bit result)
; In: DE / HL
; Out: HL = DE / HL, DE = DE % HL
UDIVIDE:
    ex   DE, HL         ; 1:4       HL = HL / DE
   
    ld    A, D          ; 1:4
    or    A             ; 1:4
    jr   nz, UDIVIDE_16 ; 2:7/12
       
    ld    B, 16         ; 2:7     
    add  HL, HL         ; 1:11      2*HL
    jr    c, $+7        ; 2:7/12
    djnz $-3            ; 2:13/8

    ld    E, A          ; 1:4       DE = 0 % 0E = 0
    ret                 ; 1:10      HL = 0 / 0E = 0
   
    add  HL, HL         ; 1:11      2*HL
    rla                 ; 1:4
    jr    c, $+5        ; 2:7/12
    cp    E             ; 1:4
    jr    c, $+4        ; 2:7/12
    inc   L             ; 1:4
    sub   E             ; 1:4
    djnz $-9            ; 2:13/8

    ld    E, A          ; 1:4       DE = DE % HL
    ret                 ; 1:10      HL = DE / HL
   
UDIVIDE_16:             ;           HL/256+
    ld    A, L          ; 1:4
    ld    L, H          ; 1:4
    ld    H, 0x00       ; 2:7       HLA = 0HL
    ld    B, 0x08       ; 2:7
       
    rla                 ; 1:4
    adc  HL, HL         ; 2:15
    sbc  HL, DE         ; 2:15      HL-DE
    jr   nc, $+3        ; 2:7/12
    add  HL, DE         ; 1:11      back
    djnz $-8            ; 2:8/13
   
    rla                 ; 1:4
    cpl                 ; 1:4
    ex   DE, HL         ; 1:4
    ld    H, B          ; 1:4
    ld    L, A          ; 1:4
    ret                 ; 1:10

PS: Ještě jsem nedořešil, zda ten samý problém není i při dělení 0x8000+.

_________________
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: 09.07.2020, 15:08 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Jinak celou dobu jsem řešil to dělení. Hledal jsem nějaký rychlejší algoritmus až nakonec jsem narazil na odkaz https://www.msx.org/forum/development/msx-development/fastest-possible-multiplication-routine?page=4
Kde mimo jine nekdo napsal kod vyprodukovany Hi-Tech crosscompiler for windows (v7.8).

Docela oskliva a nepochopitelna rutina. Takze me dost prekvapilo, ze je rychlejsi nez co mam. Okomentoval jsem si ji a prepsal podle sebe. Funguje na myslence, ze prvne budeme nasobit delitele dvema tolikrat nez bude tak velky, nebo skoro tak velky jako dělenec. Ten pocet nasobeni, je pocet kroku co se musi pak nasledne zase delitel podelit dvema a postupne vracet na puvodni hodnotu. A od te nejvyssi hodnoty delitele se v kazdem kroku pokusime odecist delitele od delence. Poprve by to melo vzdy vyjit, pokud neni delitel vetsi jak delenec.

Pozdeji jsem zjistil, ze pri testovani mam polovinu pripadu kdy delitel je vetsi a tak je vysledek nula, coz byl i jeden z duvodu proc je ta rutina tak rychla. Druhy duvod je, ze i kdyz je SKORO dvojnasobne pomala, protoze to nasobeni dvema a zjistovani zda je delitel stale mensi jak delenec je SKORO tak narocne jako deleni dvema a odcitani pokud to jde. Coz je normalni postup, jen se místo dělení vlevo posunutého dělitele se násobí o 8 nebo 16 bitů vpravo posunutý dělenec. Cas usetri nova metoda na tom, ze prumerná vzdálenost nejvyssiho jedničkového bitu mezi dělencem a dělitelem je cca 8. U normalní metody se prochazí všech 16 kroku pokaždé pokud dělím 0..255 a nebo 8 kroku pokud dělím 256+, ale to je zase hodně pomalá smyčka.
Kód:
; Divide 16-bit unsigned values (with 16-bit result)
; In: DE / HL
; Out: HL = DE / HL, DE = DE % HL
UDIVIDE:
    ld    A, H          ; 1:4
    or    L             ; 1:4       HL = DE / HL
    ret   z             ; 1:5/11    HL = DE / 0
    ld    BC, 0x0000    ; 3:10
UDIVIDE_LE:   
    inc   B             ; 1:4       B++
    add  HL, HL         ; 1:11   
    jr    c, UDIVIDE_GT ; 2:7/12
    ld    A, H          ; 1:4       
    sub   D             ; 1:4
    jr    c, UDIVIDE_LE ; 2:7/12
    jp   nz, UDIVIDE_GT ; 3:10
    ld    A, E          ; 1:4
    sub   L             ; 1:4
    jp   nc, UDIVIDE_LE ; 3:10
    or    A             ; 1:4       HL > DE
UDIVIDE_GT:             ;
    ex   DE, HL         ; 1:4       HL = HL / DE
    ld    A, C          ; 1:4       CA = 0x0000 = result
UDIVIDE_LOOP:
    rr    D             ; 2:8
    rr    E             ; 2:8       DE >> 1
    sbc  HL, DE         ; 2:15
    jr   nc, $+3        ; 2:7/12
    add  HL, DE         ; 1:11      back
    ccf                 ; 1:4       inverts carry flag
    adc   A, A          ; 1:4
    rl    C             ; 2:8
    djnz UDIVIDE_LOOP   ; 2:8/13    B--
   
    ex   DE, HL         ; 1:4   
    ld    L, A          ; 1:4
    ld    H, C          ; 1:4
    ret                 ; 1:10

Nakonec když jsem ji dal do benchmarku na faktorizaci čísla tak byla nová rutina pomalejší, ale přesto jsem ji nastavil jako implicitní.

PS: Schvalně se podívejte na ten original.

_________________
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: 10.07.2020, 08:39 
Offline
Pan Generální
Uživatelský avatar

Registrován: 13.05.2013, 09:15
Příspěvky: 2287
Bydliště: Brno
Has thanked: 846 times
Been thanked: 318 times
Myslim, ze si rozběhal nějakeho hada. Rozběhal si ješte něco v tomhle duchu, nebo se o to snažíš?

_________________
Amiga - PMD 85


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

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
_dworkin píše:
Kód:
; Divide 16-bit unsigned values (with 16-bit result)
; In: DE / HL
; Out: HL = DE / HL, DE = DE % HL
UDIVIDE:
    ld    A, H          ; 1:4
    or    L             ; 1:4       HL = DE / HL
    ret   z             ; 1:5/11    HL = DE / 0
    ld    BC, 0x0000    ; 3:10
UDIVIDE_LE:   
    inc   B             ; 1:4       B++
    add  HL, HL         ; 1:11   
    jr    c, UDIVIDE_GT ; 2:7/12
    ld    A, H          ; 1:4       
    sub   D             ; 1:4
    jr    c, UDIVIDE_LE ; 2:7/12
    jp   nz, UDIVIDE_GT ; 3:10
    ld    A, E          ; 1:4
    sub   L             ; 1:4
    jp   nc, UDIVIDE_LE ; 3:10
    or    A             ; 1:4       HL > DE
UDIVIDE_GT:             ;

By melo byt
Kód:
    ld    A, H          ; 1:4       
    sub   D             ; 1:4
    jp    c, UDIVIDE_LE ; 3:10                <--- zmena z jr na jp
    jp   nz, UDIVIDE_GT ; 3:10
    ...
A protoze cast za ... je vic jak 50x mene casta tak jsem se pokusil zamenit
Kód:
    ld    A, H          ; 1:4       
    sub   D             ; 1:4
za
Kód:
    ld    A, D          ; 1:4
UDIVIDE_LE:   
    inc   B             ; 1:4       B++
    add  HL, HL         ; 1:11   
    jr    c, UDIVIDE_GT ; 2:7/12
    cp    H             ; 1:4
    jr    c, UDIVIDE_GT-1 ; 2:7/12
    jp   nz, UDIVIDE_LT ; 3:10
    ld    A, E          ; 1:4
    sub   L             ; 1:4
    jp   nc, UDIVIDE_LE-1; 3:10
    or    A             ; 1:4       HL > DE
UDIVIDE_GT:             ;
S myslenkou, ze kdyz cp H probiha prumerne cca 4-7x, tak ztratim 1x na "or A", ale stale budu v plusu. Ukazalo se ale, ze ztratim mnohem vic na
Kód:
    jr    c, UDIVIDE_GT-1 ; 2:7/12
    jp   nz, UDIVIDE_LT ; 3:10
protoze ta prvni podminka neodfiltruje hodne a tak se musi vyhodnocovat casto i druha.

Ale... nakonec se ukazalo jako hodne efektivni ne uplne ciste reseni.
Kód:
    ld   BC, 0x0000     ; 3:10
    ld    A, D          ; 1:4
UDIVIDE_LE:   
    inc   B             ; 1:4       B++
    add  HL, HL         ; 1:11   
    jr    c, UDIVIDE_GT ; 2:7/12
    cp    H             ; 1:4
    jp   nc, UDIVIDE_LE ; 3:10
    or    A             ; 1:4       HL > DE
kde proste rovnost hornich bitu a tedy spodnich 8 bitu ignoruji, takze obcas je "B" o jednicku vyssi nez musi, takze to prodlouzi i druhou cast deleni o jeden krok, ale v prumeru je to efektivnejsi. Nejvic trpi kdyz se deli 8bit / 8 bit protoze tady se porovnava nula s nulou a delitel musi prelezt do vyssiho bitu i kdyby se delilo dvema... ale u 16 bit / 16 bit je to okrajovy pripad.

Snazil jsem se o nejaky mix teto rutiny a me stare, ale nedari se. Neni snadne/levne zjistit ktera bud rychlejsi a tu zvolit. Zkousel jsem dat test, kdyz je H nulove tak prejdi na 16 bit / 8 bit ze stare rutiny. Ale vysledky zklamaly.

_________________
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.07.2020, 19:12 
Offline
Pan Štábní

Registrován: 23.06.2013, 23:49
Příspěvky: 1114
Has thanked: 100 times
Been thanked: 160 times
Lisiak4 píše:
Myslim, ze si rozběhal nějakeho hada. Rozběhal si ješte něco v tomhle duchu, nebo se o to snažíš?

Udelal jsem jeste tu hru zivota. Ale oboje, zvlast to druhe bylo dost rucni prace. I kdyz jsem ten automaticky prevodnik forth->M4 FORTH dost zlepsil. Tak to chce znalost forthu. Nejde neco vzit a ted si to zkompiluji. Chce to vedet jak se vytvareji promenne, pole atd. Protoze forth pise ze chce alokovat 8096 bunek pod jmenem XXX a v M4 FORTHU proste na konci udelam label XXX. Pripadne kdyby byly pole dve tak:

A equ $
B equ A+2*8096

A ten zivot si na rosettacode vytvari myslim vlastni slova. Takze je to pro zacatecnika dost necitelne a spousta kodu co najdes ani nejde spustit, protoze je to psane pro nejakou starou verzi. Proste to chce vedet kam mas sahnout.

Jde mi vic o ten prekladac a principy jak to funguje. Jak moc je Z80 vhodny nebo nevhodny pro jazyk "vyssi" urovne. Kde to dre. Jinak bych si usetril cas a rovnou to napsal v assembleru.
Ten prekladac a knihovny k tomu se dotyka snad vsech moznych IT temat, takze na nic jineho neni ani cas.
Vedlejsim efektem je spis ze jsem se naucil trosku znackovaci jazyk M4 a ten forth. I kdyz je pro me stale citelnejsi vyraz v C, protoze ve forthu si proste musim pomoct a v komentarich si vypsat jak pokazde vypada zasobnik, kde co zrovna lezi.
Kód:
COLON(test_muldivmod,( -- ))
    XDO(512,0)
    XDO(256,1)
        J I
        _2DUP
        UDIVMOD     ; a b (a%b) (a/b)
        OVER  I UGE_IF
breakpoint:
            J UDOT PUTCHAR('/')
            I  UDOT PUTCHAR('=')
            DUP UDOT OVER UDOT
            CR
        THEN         
        ROT         ; a (a%b) (a/b) b
        MUL         ; a (a%b) (a/b)*b
        ADD         ; a ((a%b) + (a/b)*b)
        SUB
        DUP_IF
             J UDOT PUTCHAR('/')
             I UDOT PUTCHAR('=')
            DUP UDOT PUTCHAR('?')
            CR
        THEN
        DROP
    XLOOP
    XLOOP
SEMICOLON

PS: Kratka odpoved: ne

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


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ů: 598 ]  Přejít na stránku Předchozí  1 ... 5, 6, 7, 8, 9, 10, 11 ... 40  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 1 návštěvní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:  
Založeno na phpBB® Forum Software © phpBB Group
Český překlad – phpBB.cz