Názor k článku Specifika instrukční sady mikroprocesorů Intel 8086/8088 (2) od _dw - Vymenit deleni za nasobeni neni az tak trivialni...

  • 18. 9. 2024 1:47

    _dw

    Vymenit deleni za nasobeni neni az tak trivialni jak muze vypadat.
    Vetsinou ti podminky umozni to nasobit s dvojnasobnou sirkou.
    A na konci to nekdy musis posouvat o par bitu doprava.
    Vse kvuli zaokrouhleni.
    Nedavno jsem cetl nejaky par let stary clanek, ktery ukazoval, ze ani nejlepsi prekladace nenajdou vzdy nejlepsi reseni. A vysvetloval nejake podminky, za kterych to jde udelat lepe.
    Pisi jako hobby projekt prekladac pro Z80 a deleni konstanotou je... PEKLO. Vetsina veci kde se objevi konstanta je tezka, ale deleni je extrem. I modulo je lehci i kdyz jsem dlouho nevedel ze to jde delat bez deleni.
    Metod na ktere jsem prisel jak udelat deleni je nekolik a kazda ma svoje podvarianty a ty nikdy nevis, ktery kod pujde nejlepe optimalizovat a bude nakonec nejlepsi.

    Nasobit 6554? 16x16=32 bit...
    To je zbytecne slozite (pokud procesor neumi nasobit).
    U deleni 10 me nejlepe vychazi pouzit deleni 5. Protoze delit deseti je to same co "delit"dvema a pak deseti. Nebo naopak. Ale prvni se lepe optimalizuje, protoze mas uz zadarmo nasobek 2. Ktery vyuzijes protoze to prevadis na to nasobeni.
    Deleni 5 se dela pres nasobeni 13107, ale drzi se to v 16x16=24 bit protoze se pouziva trik, ze ti staci to nasobit 51.
    Osetrit zaokrouhleni.
    A pak to vynasobit 257! 51*257=13107
    A nasobeni 257 je brnkacka... protoze v ramci toho neustale to drzet na co nejmensim poctu bitu se to dela jako
    (N*257)>>8
    Takze ti staci hornich 8 bitu dat do spodnich a secist s puvodni hodnotou.

    A ted si vem ze najit tohle pro kazde cislo je dost prace... a stejne nevis zda to nejde lepe... i kdyz to delas rucne.

    dworkin@dw-A15:~/repositories/M4_FORTH$ ./check_word.sh 'PUSH(10) UDIV'
                           ;[32:185]    10 u/   Variant HL/10 = (HL/2)*(65536/5)/65536 = (HL/2)*51*257/65536
        ld    B, H          ; 1:4       10 u/
        ld    C, L          ; 1:4       10 u/
        srl   B             ; 2:8       10 u/
        rr    C             ; 2:8       10 u/   1x base
        xor   A             ; 1:4       10 u/
        inc  BC             ; 1:6       10 u/   +19 rounding constant
        add  HL, BC         ; 1:11      10 u/
        adc   A, A          ; 1:4       10 u/   3x  AHL
        add  HL, HL         ; 1:11      10 u/
        inc  HL             ; 1:6       10 u/   +8 rounding constant
        adc   A, A          ; 1:4       10 u/   6x  AHL
        add  HL, HL         ; 1:11      10 u/
        adc   A, A          ; 1:4       10 u/   12x AHL
        add  HL, HL         ; 1:11      10 u/
        adc   A, A          ; 1:4       10 u/   24x AHL
        add  HL, BC         ; 1:11      10 u/
        adc   A, 0x00       ; 2:7       10 u/   25x AHL
        add  HL, HL         ; 1:11      10 u/
        adc   A, A          ; 1:4       10 u/   50x AHL
        add  HL, BC         ; 1:11      10 u/
        adc   A, 0x00       ; 2:7       10 u/   51x AHL with rounding constant 26..35
        ld    B, A          ; 1:4       10 u/   (AHL * 257) >> 16 = (AHL0 + 0AHL) >> 16 = AH.L0 + A.HL = A0 + H.L + A.H
        ld    C, H          ; 1:4       10 u/   BC = "A.H"
        add  HL, BC         ; 1:11      10 u/   HL = "H.L" + "A.H"
        ld    L, H          ; 1:4       10 u/
        adc   A, 0x00       ; 2:7       10 u/   + carry
        ld    H, A          ; 1:4       10 u/   HL/10 = (HL/2)*(65536/5)/65536 = (HL/2)*(1+256)*51 >> 16
    ; seconds: 0           ;[32:185]

    Sorry, Z80 je trosku offtopic. .)