[AVR][ASM] Mandelbrot bez float

W tym miejscu zadajemy pytania na temat języka Assembler, dzielimy się swoją wiedzą, udzielamy wsparcia, rozwiązujemy problemy programistyczne.
PeterB314
Posty: 8
Rejestracja: środa 20 mar 2019, 08:08

[AVR][ASM] Mandelbrot bez float

Postautor: PeterB314 » poniedziałek 29 kwie 2019, 21:31

Dzień dobry, to mój pierwszy wątek tu na forum.

Kupiwszy na odść znanym portalu aukcyjnym, przecenione i jak widać nieco wybrakowane (co w niczym nie wadzi dla celów edukacyjno rozwojowych) moduły LED P3 RGB 64x64 pix,
fot1.JPG


zbudowałem taki oto ledowizor 192x128 pix, RGB bez skali, czyli 7 barw + czarny (jak zauważył kolega, nawet potrafię diodę na czarno zaświecić, na co ja się zapytałem czy woli z wstępnym rozbłyskiem czy bez...).

fot2.JPG


Dawno temu już robiłem monochromatyczne tabliczki led i napisałem do nich soft na AVR M32 oczywiście w asemblerze, jako że prócz ( a tfuuu..) Basica, był to jeden z pierwszych języków który począłem zgłębiać będąc podrostkiem, a więc jest mi on bliższym niż koszulka z napisem C cośtam ;).

fot3.JPG


W ledowizorze zastosowałem M1284; 1 nibel na pix=12kB ram, wiem, że gubię 1bit na pixel, ale odświeżanie treści zajmuje 40% czasu, a gdybym jeszcze robił jakieś rotacje bajtów to wogóle nie dam rady tego przesłać do wyświetlaczy, nie ma tu PMP, DMA i innych gadgetów, dopasoawłem bios i porty do złącza HUB75 i ledowizor zaczął świecić, a po kilkunastu dniach debugowania, nawet poprawnie wyświetlać treści. Mój ledowizor sterowany jest ze standardowej klawiatury ze złączem PS2, do której napisanie hendlera (12 lat wstecz, też ASM) zajęło mi zylion godzin (nie udało mi się wtedy wygooglać gotowca).

fot 2a.JPG
fot4.jpg
fot 4a.JPG


Mandelbrot kusił mnie już przy małej ledownicy, ale wtedy myślałem: mono 32x64 to mało, pozatym te floaty, si, za skomplikowane...

Później, gdy czyniłem pierwsze kontakty z Pic32 na Mp-labie, dzięki Lucio DI Jasio, procek narysował Mandelbrota, no ale tam, float-y są na dzień dobry.

Kod: Zaznacz cały

// Z lucio Di Jasio Pic32 Pseudocode:
x = x0;
y = y0;
k = 0;
// core iteration
do {   x2 = x*x;
   y2 = y*y;
   y = 2*x*y+y0;
   x = x2-y2+x0;
   k++;
   } while ( (x2 + y2 < 4) & & ( k < MAXIT));
// check if the point belongs to the Mandelbrot set
   if ( k == MAXIT) plot( j, i);

// Mandelbrot Set graphic demo

// configuration bit settings, Fcy=72 MHz, Fpb=36 MHz
#pragma config POSCMOD=XT, FNOSC=PRIPLL
#pragma config FPLLIDIV=DIV_2, FPLLMUL=MUL_18, FPLLODIV=DIV_1
#pragma config FPBDIV=DIV_2, FWDTEN=OFF, CP=OFF, BWP=OFF
#include < p32xxxx.h >
#include < plib.h >
#include < explore.h >
#include < graphic.h >
#define SIZE VRES
#define MAXIT 64
void mandelbrot( float xx0, float yy0, float w)
   {
   float x, y, d, x0, y0, x2, y2;
   int i, j, k;
   // calculate increments
   d = w/SIZE;
   // repeat on each screen pixel
   y0 = yy0;
   for (i=0; i < SIZE; i++)
      {
      x0 = xx0;
      for (j=0; j < SIZE; j++)
         {
         // initialization
         x = x0;
         y = y0;
         k = 0;
         // core iteration
         do {
            x2 = x*x;
            y2 = y*y;
            y = 2*x*y + y0;
            x = x2-y2 + x0;
            k++;
         } while ( (x2 + y2 < 4) & & ( k < MAXIT));
         // check if the point belongs to the Mandelbrot set
         if ( k == MAXIT) plot( j, i); //if ( k & 2) plot( j, i);
         // compute next point x0
         x0 += d;
      } // for j
      // compute next y0
      y0 += d;
   } // for i
} // mandelbrot


Aż tu nagle kilka tygodni temu, net mi pokazał taki obrazek:

https://rbteam.wordpress.com/2011/09/11 ... andelbrot/

Przypomniałem sobie też, że kiedys gdzieś widziałem Mandela w Z80asm i był on na integerach.

Chwila rozmyślań i wniosek: przecież jeśli nie wymagać dokładności niezbędnej do zoomowania robala, to da się to zrobić na integerach traktując ich wartości stałopozycyjnie!

Założenie było takie: jedności ma rozdzielczość 6 bitów, czyli mając 192 punkty ekranu argument obliczeń mógł by przyjmować wartość od -2 do 2. Idąc dalej tą drogą wymyśliłem, że w takim razie za każdą iteracją kwadrat będzie przesuwał 'kropkę' o 6 bitów(albo o 12?), a więc aby być na bierząco w operacji porównania czy moduł |Z|>2 muszę też przesuwać wzorzec do porównań. Wyszło mi że dla maksymalnie 8 iteracji potrzebuję 48 bitowe słowa... Hmm zaczyna się robić z tego niezły makaron, ale nie martwiąc się co będzie dalej, przystąpiłem do kodowania mej świetlistej koncepcji.

Po wielu godzinach kombinowania, szukania błędów oraz dopatrzeniu się zasadniczej ułomności w samej koncepcji światłej mej, przełamałem się i zastosowałem google. No i znalazłem:

https://www.pouet.net/prod.php?which=53287

Edit: Dałem link bezpośredni, gdyż w codegolf wywalili ten assemblerowy.

fot5.png


Kolejna chwila (czytaj 60 minut) z dokładna listą instrukcji x86:
http://dsearls.org/courses/C391OrgSys/I ... n_set.html
doprowadziły do ujawnienia sprytu tego rozwiązania.

Edit: staram się tabularyzować wszystkie spacja, a nadal kolumny nie trzymają pinou...

Kod: Zaznacz cały

;===========================================================================
;
; "Microbrot" by Sir_Lagsalot

org 100h
   mov al,13h
   int 10h      ;VGA 320x200 @ 256 colors, ah domyślnie 0

   les ax,[bx]   ;do rej ES:AX załadowana zawartość pam [DS:BX] pointer 4 bajty
            ;ES segment Vram, zkąd ładowany? DI=0         
FillLoop:      
   cwd         ;if high bit of AX = 1 then DX = 0xFFFF else 0,
               ;ale można by użyć xor dx,dx? byłoby jaśniej
   mov ax,di      ;DI licznik bajtów=adres w Vram 1bajt na pix dla 256 colorów
   mov cx,320   ;CX = Maxiter oraz Xmax obrazu
   div cx      ;AX = (DX,AX)/CX; DX = remainder, czyli DX=xx AX=yy
   sub ax,100   ;yy od -100    przesunięcie układu współrzędnych
   dec dh      ;xx od -256   

   xor bx,bx      ;BX=reZ = 0; Z0=(0+i0)
   xor si,si      ;SI=imZ = 0

MandelLoop:
   mov bp,si      ;BP = imZ
   imul si,bx      ;(DX,SI) = SI * BX   SI = reZ * imZ
   add si,si      ;SI = 2 * reZ * imZ

   imul bx,bx   ;(DX,BX) = BX^2      BX = ReZ^2
   jo MandelBreak

   imul bp,bp   ;(DX,BP) = BP^2    BP = imZ^2
   jo MandelBreak

   add bx,bp      ;bx = ReZ^2 + imZ^2
   jo MandelBreak

   sub bx,bp      ;bx = reZ^2  bp = imZ^2
   sub bx,bp      ;bx = ReZ^2 - imZ^2

   sar bx,6      ;BX/64 signed
   add bx,dx      ;ReZ = BX/64 + xx
   sar si,6      ;SI/64 signed
   add si,ax      ;ImZ = SI/64 + yy

   loop MandelLoop;CX=CX-1, loop until <>0

MandelBreak:
   xchg ax,cx   ;AX (320-ilosc iteracji) = kolor, obcinany z najwyzszego bitu
   stosb      ;[ES:DI] = AL if DF = 0 then DI = DI + 1; czyli adres Vram
   jmp FillLoop

;DI-adres Vram, CX-Maxiter i Xmax, AX-imC=yy, DX-reC=xx, BX-reZ, SI-imZ, BP=t_imZ
;
;=========================================================================


Jak widać koncepcja podziału jedności na 64 i tu występuje. Sir_Lagsalot chyba lepiej ode mnie rozumie istotę systemów liczbowych i umie ją stosować...

Nie było co się dalej zastanawiać tylko czym prędzej przekodować to do AVR. Oczywiście nie obyło się bez kilku błędów, przeoczeń i literówek (kolejne 'chwile' wyjęte z pięknego życia), z których każda dawała śmieszne efekty. Choć z początku wcale nie dawała efektów bo albo było czarno albo system odjeżdżał z powodu rozjechania się stosu.

Podczas wielokrotnego czytania programu z monitora nie byłem w stanie zobaczyć ostatniego błędu, powodującego, że kolorowe plamy jakby chciały, ale z jakiegoś powodu nie potrafiły ułożyć zbioru M.

fot 8.JPG
fot6.JPG
fot7.JPG


Przypomniałem sobie wówczas jak w zamierzchłej przeszłości bawiłem się debugiem pod dosem, tam polecenie r wyświetlało zawartość rejestrów i takiego czegoś właśnie potrzebowałem tutaj. Tak więc dostosowana do potrzeby procka Print_registers zagościła w kodzie. Możliwość pracy krokowej zapewniona jest przez odpowiednie zmienne sterowane z klawiatury. Rejestr B pokazuje krok pętli.

https://youtu.be/f8bzZb-RzoA

Prośba do czepialińskich: ja wiem, że styl poniższego kodu jest mało czytelny... (edit poprawiłem), niżej zamieściłem wersje elegancką. Aha: piszę w slangu angielsko-polskim, jako, że w takim systemie mnemonicznym szybciej układam myśli.

Wersja debugowa i efekt jej pracy:

Kod: Zaznacz cały

;=========================================================================
;   M A N D E L B R O T   AVR asm bez float, code by PeterB314 (C) 2019.
;   pierwsza zdebugowana działa
;   inspiracja: http://www.pouet.net/prod.php?which=53287
;
;instrukcje z x86: Imul, Sar są zastąpione przez Mul_1616s oraz odpowiednią ilość Asr R23 Ror R22
;Mul_1616s jest na koncu następnego listingu.

Mandelbrot_regen:   .equ max_Mandel_Iter=8
   Clr R30         ;Y loop
Next_YL_Mandel:      ;sword R29:R28 = (yy - 64)
   Ldi YH,0      Mov YL,R30   
   Ldi A,64      Sub R28,A   
   Ldi A,0      Sbc R29,A

   Clr R31          ;X loop
Next_XL_Mandel:      ;sword R27:R26 = (xx - 128)
   Ldi XH,0      Mov XL,R31   
   Ldi A,128      Sub R26,A   
   Ldi A,0      Sbc R27,A

Push R30 Push R31      ;R30 R31 Używany do Mul_1616s
   
   Ldi A,max_Mandel_Iter    
   Clr R22   Clr R23
   Clr R24   Clr R25   ;Z(0) = (0+i0)
                                    Ldi B,0 call Print_registers
LooP_Mandel_Iter:          
Push R26 Push R27      ;xx
Push R24 Push R25       ;imZ
Push R22 Push R23      ;reZ   
                                    Ldi B,1 call Print_registers
   MovW R30,R22       
   MovW R26,R24
   Rcall MUL_1616s      ;R2322 = reZ * imZ
    Lsl R22 Rol R23      
    Movw R18,R22         ;R1918 = 2 * reZ * imZ [si]
                                    Ldi B,2 call Print_registers

Pop R31 Pop R30         
   MovW R26,R30         ;reZ
                                    Ldi B,3 call Print_registers

   Rcall MUL_1616s      ;[R25:R24:R23:R22]=Z[R31:R30] * X[R27:R26]

   MovW R20,R22         ; R2120 = A = reZ^2; [BX]
                                    Ldi B,4 call Print_registers
Pop R31 Pop R30         
   MovW R26,R30         ;imZ
                                    Ldi B,5 call Print_registers

   Rcall MUL_1616s      ;R2322 = B = imZ^2; [BP]   

                                    Ldi B,6 call Print_registers

   Add R20,R22   Adc R21,R23    
   Brsh Skip_003    Rjmp Break_Mandel_Iter
Skip_003:
                                    Ldi B,7 call Print_registers

   Sub R20,R22   Sbc R21,R23    
   Sub R20,R22   Sbc R21,R23
   Movw R22,R20         ;reZ = ReZ^2 - imZ^2
                                    Ldi B,8 call Print_registers    
POP R27 POP R26         ;XH:XL
                                    Ldi B,9 call Print_registers    
   Asr R23   Ror R22
   Asr R23   Ror R22
   Asr R23   Ror R22       
   Asr R23   Ror R22
   Asr R23   Ror R22
   Asr R23   Ror R22
                                    Ldi B,10 call Print_registers

   Add R22,R26   
   Adc R23,R27         ;ReZ = (ReZ^2 - imZ^2) / 64 + xx
   Movw R24,R18   
                                    Ldi B,11 call Print_registers

   Asr R25   Ror R24
   Asr R25   Ror R24
   Asr R25   Ror R24       
   Asr R25   Ror R24
   Asr R25   Ror R24
   Asr R25   Ror R24

                                    Ldi B,12 call Print_registers

   Add R24,R28   Adc R25,R29   ;ImZ = (2 * reZ * imZ) / 64 + yy
;   Add R24,R28   Adc R24,R29   = tu był główny błąd, daje ciekawe artefakty :)

                                    Ldi B,13 call Print_registers
   Dec A Tst A
   Breq End_Mandel_Iter
      Rjmp LooP_Mandel_Iter

Break_Mandel_Iter:   POP R27   POP R26   
End_Mandel_Iter:   POP R31   POP R30
                                    Ldi B,14 call Print_registers    
   Sts Pixel_put_color,A
   Mov XL,R31
Push YL
   Mov YL,R30
   SET
   Call Set_Point_XY
POP YL            ; był brak ochrony YL !
                                    Ldi B,15 call Print_registers
   Lds A,Cur_edit_cmd
    Cpi A,0x40      Breq Exit_Mandel

   Lds A,Mt_X   Inc R31   
   Cp R31,A      Brsh Next_Mandel_line   
                  Rjmp Next_XL_Mandel
Next_Mandel_line:
   Lds A,Mt_Y   Inc R30   
   Cp R30,A      Brsh Exit_Mandel   
                  Rjmp Next_YL_Mandel
Exit_Mandel:   Store Pixel_put_color,4
RET   
;
;==========================================================================


fot 9.JPG


Poniżej wersja elegancka z wycofanym wyświetlaniem rejestrów oraz szeregiem zmian porządkowych; jest inna dyspozycja rejestrów dla wyników tymczasowych, gdyż w toku dalszej rozbudowy, potrzebuję R18,19,20,21 do sterowania powiększaniem i innych efektów.

Kod: Zaznacz cały

;=========================================================================
;
;   M A N D E L B R O T   AVR asm bez float, code by PeterB314 (C) 2019.
;   inspiracja: http://www.pouet.net/prod.php?which=53287
;
/*    dla skrócenia listingu, czasem kilka instrukcji w jednym wierszu jeśli są logicznie powiązane

Funkcje zewnętrzne: Set_Point_XY, zaświeca pixel (XL,YL) w kolorze [Pixel_put_color]

Zmienne zewnętrzne: [Cur_edit_cmd] - kod ostatnio wydanego polecenia z klawiatury
          [Mt_X],[Mt_Y] - rozmiar wyświetlacza   

   Z(n+1) = Z(n)^2 + C; Z(0)=(0+i0), dla C należcego do płaszczyzny Z (pole ekranu)
*/

   .equ Init_max_Iter=32

Mandelbrot_regen:
   Clr R30         ;licznik współrzęna ekranowa Y

Next_YL_Mandel:   
   Ldi YH,0
   Mov YL,R30       ;YHYL - zmienna urojona imC
   Ldi A,64        ;czyli yy=-1
   Sub R28,A
   Ldi A,0x00
   Sbc R29,A            //   sword R29:R28 = (yy - 64)

   Clr R31       ;licznik współrzęna ekranowa X

Next_XL_Mandel:   
   Ldi XH,0
   Mov XL,R31        ;XHXL - zmienna rzeczywista reC
   Ldi A,128       ;czyli xx=-2
   Sub R26,A
   Ldi A,0x00
   Sbc R27,A            //   sword R27:R26 = (xx - 128)

Push R30 Push R31   // wskażnik piksela XY, R30 R31 Używany do Mul_1616s
   
   Ldi A,Init_max_Iter    ;A alias dla R16
   movw R22,R26      ;Ponieważ pierwsza iteracja dla Z(0)=(0+i0) zakonczy się wynikiem (xx+iyy)
   movw R24,R28       ;to odrazu Z(0) = (xx+iyy), zmniejszy to ilość iteracji o 1
            ;a nadto pozwala to na łatwe przejście do Julia set
            ;wtedy dalej, zamiast dodawać xx i yy należy dodać J(re+im)    
LooP_Mandel_Iter:       
;Jeśli w tym miejscu wykonać reZ=|reZ| oraz imZ=|imZ| uzyskamy obraz fraktala "Burning Ship"
               // yy udało się zachować nienaruszany w pętli
Push R26 Push R27          // xx
Push R24 Push R25          // imZ
Push R22 Push R23         // reZ

   MovW R30,R22             // reZ * imZ
   MovW R26,R24   
   Rcall MUL_1616s            ;[R25:R24:R23:R22]=Z[R31:R30] * X[R27:R26]         
   
;o 1 mniej, gdyż tu reZ*imZ nie jest mnożone przez 2 skoro zaraz ma być dzielone przrz 64
   Asr R23 ror R22
   Asr R23 ror R22
   Asr R23 ror R22
   Asr R23 ror R22
   Asr R23 ror R22
   Movw R12,R22            // R1213 = (reZ * imZ)/64 [si]   

Pop R31 Pop R30               // reZ   

   MovW R26,R30
   Rcall MUL_1616s   
   
;tu powinno być sprawdzenie Overflow tak jak w wersji z x86 ale brak flagi w procku oraz brak czasu na
; napisanie odpowiedniego kodu wykrywającego, spowodował że nie ma tego testu w tym miejscu, jak i poniżej.

   MovW R14,R22            // R1415 = A = reZ^2; [BX]
   
Pop R31 Pop R30               // imZ      

   MovW R26,R30
   Rcall MUL_1616s            // R2322 = B = imZ^2; [BP]

   Add R14,R22 Adc R15,R23       // break If (A+B) > 0xFFFF
      Brlo Break_Mandel_Iter

   Sub R14,R22 Sbc R15,R23    
   Sub R14,R22 Sbc R15,R23       //reZ = reZ^2 - imZ^2

;jeden Asr więcej powiększa, mniej oddala, trzeba też dostosować maxiter i ilość Lsr A koloru
   Movw R22,R14       
   Asr R23 ror R22
   Asr R23 ror R22
   Asr R23 ror R22       
   Asr R23 ror R22
   Asr R23 ror R22
   Asr R23 ror R22

POP R27 POP R26           // xx

   Add R22,R26 Adc R23,R27         //ReZ = (ReZ^2 - imZ^2) / 64 + xx
                  ;dla Julia set zamiast xx dodać reJ
   Movw R24,R12
   Add R24,R28 Adc R25,R29         //ImZ = (2 * reZ * imZ) / 64 + yy
                  ;dla Julia set zamiast yy dodać imJ
   Dec A
   Tst A
      Breq End_Mandel_Iter
   Rjmp LooP_Mandel_Iter   ; w trakcie testowania czasem przekraczało 63 instrukcje

Break_Mandel_Iter:

   POP R27 POP R26      // xx był zrzucony na początku pętli

End_Mandel_Iter:

   POP R31 POP R30      // liczniki współrzędnych ekranu

   lsr A  Lsr A        ; dopasowanie koloru Max_color=7            
   Sts Pixel_put_color,A   ; no chyba samokomentująca się? ;)
   mov XL,R31
push yl          ;ochrona lokalnego yy
   mov YL,R30
   SET
   call Set_Point_XY    ;niszczy YL
pop yl
   Lds A,Cur_edit_cmd
   Cpi A,0x40       ;Shift+Esc = przerwij i wyjdź
      Breq Exit_Mandel

   Lds A,Mt_X   
   Inc R31   
   Cp R31,A   
      Brsh Next_Mandel_line   
         Rjmp Next_XL_Mandel

Next_Mandel_line:
   Lds A,Mt_Y   
   Inc R30   
   Cp R30,A   
      Brsh Exit_Mandel      
         Rjmp Next_YL_Mandel
Exit_Mandel:   
   Store Pixel_put_color,4      ;macro
RET   

;==========================================================================
;   USAGE:   [R25:R24:R23:R22]=Z[R31:R30] * X[R27:R26]
;   DECRIPTION: Signed multiply of two 16bits numbers with 32bits result.
;   STATISTICS:   Cycles :31 + ret   Words :   23 + ret
;   Based on avr201.asm with different register usage.
Mul_1616s:   Push A    Push B 
   Clr R2   
   muls    r31, r27   
   movw    r25:r24, r1:r0

   mul    r30, r26   
   movw    r23:r22, r1:r0   

   Mov    A,R31    
   Mov    B,R26
   mulsu    A,B      
   sbc   r25, r2   
   add   r23, r0   
   adc   r24, r1   
   adc   r25, r2

   Mov    A,R27       
   Mov    B,R30   
   mulsu    A,B      
   sbc   r25, r2   
   add   r23, r0   
   adc   r24, r1   
   adc   r25, r2
Pop B    Pop A   RET   
;
;   Integer Mandelbrot End
;
;===========================================================================


fot 10.JPG


Następnie zwiększyłem Max_iter do 64 i zmieniłem kolorowanie,

fot 11.JPG


oraz powiększanie zwiększając ilość rotacji w prawo.

fot 12.JPG


W porównaniu do wersji dosowej, zostaje czarna linia pozioma dla xx=0, jeszcze nie znalazłem przyczyny.

Ciekawy materiał źródłowy - coding chelange:

https://www.youtube.com/watch?v=6z7GQewK-Ks

Na zakonczenie totalne szaleństwo obliczeniowe:

https://www.youtube.com/watch?v=u1pwtSBTnPU

Dziękuję i pozdrawiam!
Edit: w listingu powyżej odpisałem uwagę o możliwości uzyskania obrazu fraktala "Burning Ship".
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony niedziela 21 maja 2023, 09:13 przez PeterB314, łącznie zmieniany 7 razy.
Głównie AVR8 ASM, Próbowałem PIC32 ale C mi jakoś nie leży...

SuperGość
Uber Geek
Uber Geek
Posty: 2346
Rejestracja: piątek 04 wrz 2015, 09:03

Re: [AVR][ASM] Mandelbrot bez float

Postautor: SuperGość » wtorek 30 kwie 2019, 05:52

No niezłe, mówię o efekcie :)

Awatar użytkownika
piotrek
User
User
Posty: 155
Rejestracja: niedziela 05 lis 2017, 02:46

Re: [AVR][ASM] Mandelbrot bez float

Postautor: piotrek » wtorek 30 kwie 2019, 10:07

Moim zdaniem ten wyświetlacz kompletnie się nie nadaje do pokazywanie zbioru Mandelbrota. Jego mała rozdzielczość nie pozwala na ukazanie "fraktalności", którą powinniśmy dostrzec w najmniejszych detalach. Znacznie bardziej nadaje się natomiast do ukazania pracujących automatów komórkowych, np game of life lub mrówki Langtona. Coś takiego jak na zdjęciu 4a.
Tak czy inaczej, ten projekt to ciekawe wyzwanie programistyczne.

Awatar użytkownika
mokrowski
User
User
Posty: 190
Rejestracja: czwartek 08 paź 2015, 20:50
Lokalizacja: Tam gdzie Centymetro

Re: [AVR][ASM] Mandelbrot bez float

Postautor: mokrowski » wtorek 30 kwie 2019, 11:50

Punktem zaczepienia dla takich zabaw, może być program Fractint. W czasach DOS'a, wykonywał on obliczenia fraktali bez przecinka. W GNU/Linux jest także przeportowany od dawna. Zwie się xfractint.

[Dodame]
Witryna projektu: https://fractint.org/
,,Myślenie nie jest łatwe, ale można się do niego przyzwyczaić" - Alan Alexander Milne: Kubuś Puchatek

PeterB314
Posty: 8
Rejestracja: środa 20 mar 2019, 08:08

Re: [AVR][ASM] Mandelbrot bez float

Postautor: PeterB314 » czwartek 02 maja 2019, 21:01

Wersja przyspieszona:
- przyporządkowanie rejestrów takie aby całkowicie wyeliminować operacje na stosie,
- rezygnacja z wywoływania procedury mnożenia,
- ponieważ do obliczeń brane jest tylko młodsze słowo wyniku mnożenia, liczymy tylko to co potrzebne
Czas wykonania spadł z 7,5s do 2,5s. :D

Kod: Zaznacz cały

Mandelbrot_Fast:
;Ze względu na działanie instrukcji Mulsu tylko w zakresie rejestrów 16-23
;zmienne ułożone są jak widać poniżej:

.def reL=R18 .def reH=R19 .def imL=R20 .def imH=R21 .def timL=R22 .def timH=R23

   .equ max_Mandel_Iter=32
   
   Clr R30         ;Y loop
Next_YL_Mandel_F:      ;sword R29:R28 = (yy - 64)
   Ldi YH,0   Mov YL,R30
   Ldi A,64   Sub R28,A
   Ldi A,0   Sbc R29,A
   
   Clr R31         ;X loop
Next_XL_Mandel_F:      ;sword R27:R26 = (xx - 128)
   Ldi XH,0   Mov XL,R31
   Ldi A,128   Sub R26,A
   Ldi A,0   Sbc R27,A
   
Ldi A,max_Mandel_Iter

Movw reL,R26    Movw imL,R28      ; Z(0)=Z(1)=(xx,yy)    

LooP_Mandel_Iter_F:

Movw timL,imL                     ;MOV BP SI      tim im


Mul   reL,imL   Movw R2,R0       ;MUL SI BX      im  re
Mulsu reH,imL   Add  R3,R0      
Mulsu imH,reL   Add  R3,R0      
Movw  imL,R2
                                 ;SAR SI 5      im  5
Asr imH Ror imL   Asr imH Ror imL   Asr imH Ror imL   
Asr imH Ror imL   Asr imH Ror imL   ;Asr imH Ror reH
                  
Add imL,R28    Adc imH,R29            ;ADD SI AX      im  yy
                     
Mul reL,reL    Movw  R2,R0          ;MUL BX BX      re  re
Mulsu reH,reL   Add R3,R0   
Add R3,R0      Movw reL,R2
                     

Mul timL,timL   Movw  R2,R0          ;MUL BP BP      tim tim
Mulsu timH,timL   Add R3,R0      
Add R3,R0   Movw timL,R2
                     
Add   reL,timL   Adc  reH,timH         ;ADD BX BP      re  tim
                  
Brlo Mandel_Break_F                  ;JO Break
                     
Sub   reL,timL   Sbc  reH,timH         ;SUB BX BP      re  tim
                     
Sub   reL,timL   Sbc  reH,timH         ;SUB BX BP      re  tim

                                       ;SAR BX 6      re   6
Asr reH Ror reL      Asr reH Ror reL      Asr reH Ror reL   
Asr reH Ror reL      Asr reH Ror reL      Asr reH Ror reL
   
Add reL,R26   Adc reH,R27         ;ADD BX DX      re  xx

   Dec A Tst A
      Breq Mandel_Break_F
         Rjmp LooP_Mandel_Iter_F
Mandel_Break_F:
   Lsr A Lsr A
   Sts Pixel_put_color,A   
   mov XL,R31
Push YL
   mov YL,R30
   SET                   ;zaświeć punkt, CLT 'gasi'
   Call Set_Point_XY
Pop YL
                                    
   Lds A,Mt_X   Inc R31   
      Cp R31,A   Brsh Next_Mandel_line_F
         Rjmp Next_XL_Mandel_F
         
Next_Mandel_line_F:
   Lds A,Mt_Y   Inc R30   
      Cp R30,A   Brsh Exit_Mandel_F      
         Rjmp Next_YL_Mandel_F
         
Exit_Mandel_F:   Store Pixel_put_color,7

RET   ;   Mandel_Fast   

Edytowany: drobne poprawki tabulatorskie.
Głównie AVR8 ASM, Próbowałem PIC32 ale C mi jakoś nie leży...

PeterB314
Posty: 8
Rejestracja: środa 20 mar 2019, 08:08

Re: [AVR][ASM] Mandelbrot bez float

Postautor: PeterB314 » niedziela 26 maja 2019, 11:01

Dopisałem trochę kodu i teraz mam wytwornice serwetek ...

https://youtu.be/gbHt2Z4YkqE
Wyświetlacz po lewej : 192 x 128 pix, 6 modułów 64x64/32Scan line, 2xHUB75E, odświeżanie 87Hz, Atmega 1284@20MHz
Wyświetlacz po prawej: 96 x 96 pix, 9 modułów 32x32/ 8 Scan line , 3 x HUB75C, odświeżanie 112Hz, Atmega 1284@ 8MHz
Intensywność świecenia około 20-25%. Pobór prądu przy tym wypełnieniu, około 0,8A na 1 moduł przy wszystkich punktach na biało.

https://youtu.be/JSB0lNVCKb8
Tu lewy pionowo

Powoli szykuję się do zwiększenia formatu i zacznę się uczyć STM32, chyba, że polecicie inną rodzinę ..?
Rpi ma za mało pinów, można wprawdzie multipleksować, ale wolę więcej gpio.

Jeszcze eksperyment z rekurencją i stos jedzie w dół:
https://youtu.be/hbGnyKvSC8w
Głównie AVR8 ASM, Próbowałem PIC32 ale C mi jakoś nie leży...

PeterB314
Posty: 8
Rejestracja: środa 20 mar 2019, 08:08

Re: [AVR][ASM] Mandelbrot bez float

Postautor: PeterB314 » sobota 08 cze 2019, 10:12

Nihil novi sub sole, tak mógłbym zamknąć ten wątek po zapoznaniu się z przywołanym przez kol. Mokrowski tematem fractint, którego wcześniej nie poznałem. Problematyka liczenia na maszynie bez liczb rzeczywistych została obszernie tam wyjaśniona.
Niby wyważanie otwartych drzwi a jednak jakieś wyzwanie do zakodowania. Zgadzając się z opinią kol. Piotrek, dopowiem, że podstawowym zamiarem było tylko wyświetlenie całości, podobnie jak w przywołanym przykładzie tekstowym.

Obrazek

A wyszło jak zwykle co innego i z tego się cieszę.

Mrówka Langtona, zwłaszcza z możliwością zmieniania reguł to dobre wyzwanie :)
Głównie AVR8 ASM, Próbowałem PIC32 ale C mi jakoś nie leży...

PeterB314
Posty: 8
Rejestracja: środa 20 mar 2019, 08:08

Re: [AVR][ASM] Mandelbrot bez float

Postautor: PeterB314 » poniedziałek 22 cze 2020, 20:34

Witam, ostatnio czasy sprzyjały siedzeniu przy kompie, a więc pomajstrowałem przy Mandelbrocie na wyświetlaczu sterowanym Atmegą. Postanowiłem przyjrzeć się szczegółom i wyszło jak na filmie poniżej. Tym razem obliczenie jest wykonywane na liczbach stałoprzecinkowych 8.16 tak więc widok powiększenia na wyświetlaczu to 2^16.

https://youtu.be/o9BOHS9KPIQ

Kod: Zaznacz cały

;Mand_FDE24B_Test: experyment z powiększaniem 2^16
   mov R13,A   Clr A clr B ;ser A ser B;[A:reH:reL] [B:imH:imL],R13=iter count
;inny przydział rejestrów, wszystkie zajęte.
LooP_Mandel_Iter_FB:
   Rcall Sqr_Complex_24_48
   Cpi M,64      Brsh Mandel_Break_FB   ;<<< 64
   Clr M ;Ser M
      Add reL,R26      Adc reH,R27    Adc A,M;New reZ=(re^2-im^2)>>Normbits + reC(wsp X)
      Add imL,R28    Adc imH,R29      Adc B,M;New imZ=(2*Im*Re)  >>Normbits + imC(wsp Y)

   dec R13 Tst R13   Brne LooP_Mandel_Iter_FB ; Breq Mandel_Break_FB Rjmp
Mandel_Break_FB:
   Mov A,R13   
   RET
   
   Sqr_Complex_24_48:Clr R12   
;   R7: R6: R5: R4: R3: R2 = [B:imH:imL]^2
;   kwadrat liczby, mnożenia cząstkowe się powtarzają, można będzie optymalizować
   muls B,B   movw r6,r0      mul imH,imH   movw r4,r0  mul   imL,imL   movw r2,r0 
   mul   imH,imL   add r3,r0      adc r4,r1   adc r5,r12   adc r6,r12   adc r7,r12
   mul imH,imL   add r3,r0      adc r4,r1   adc r5,r12   adc r6,r12   adc r7,r12
   mulsu B,imL               sbc r6,r12   sbc r7,r12   
   add r4,r0   adc r5,r1      adc r6,r12   adc r7,r12
   mulsu B,imH               sbc r7,r12   
   add r5,r0   adc r6,r1      adc r7,r12
   mulsu B,imL               sbc r6,r12   sbc r7,r12   
   add r4,r0   adc r5,r1      adc r6,r12   adc r7,r12
   mulsu B,imH               sbc r7,r12   
   add r5,r0   adc r6,r1      adc r7,r12
   Movw timL,R2   ;[R7:R6:R5:R4:timH:timL] = [B:imH:imL]^2

;   R11:R10:R9: R8: R3: R2  = [A:reH:reL] * [B:imH:imL]   
;   wszystkie mnożenia cząstkowe są indywidualne
   muls A,B   movw r10,r0      mul reH,imH   movw r8,r0  mul reL,imL   movw r2,r0   
   mul   reH,imL   add  r3,r0      adc r8,r1   adc r9,r12   adc r10,r12   adc r11,r12
   mul imH,reL   add  r3,r0      adc r8,r1   adc r9,r12   adc r10,r12   adc r11,r12
   mulsu A,imL               sbc r10,r12   sbc r11,r12   
   add  r8,r0   adc r9,r1      adc r10,r12   adc r11,r12
   mulsu A,imH               sbc r11,r12   
   add  r9,r0   adc r10,r1      adc r11,r12
   mulsu B,reL               sbc r10,r12   sbc r11,r12   
   add  r8,r0   adc r9,r1      adc r10,r12   adc r11,r12
   mulsu B,reH               sbc r11,r12   
   add  r9,r0   adc r10,r1      adc r11,r12
   Movw imL,R2      ;[R11:R10:R9:R8:imH:imL] = [A:reH:reL] * [B:imH:imL]
                        
      Lsl imL Rol imH rol R8    rol R9  Rol R10 Rol R11;łącznie 15 bitów w prawo
      mov imL,r8 mov imH,R9   mov B,R10 ;Im = (2 Im Re) >> Normbits-1 => B:ImH:imL

;   R11:R10:R9: R8: R3: R2  = [A:reH:reL]^2
;   kwadrat liczby, mnożenia cząstkowe się powtarzają, można będzie optymalizować               
   muls A,A   movw r10,r0      mul reH,reH   movw r8,r0  mul reL,reL   movw r2,r0     
   mul   reH,reL   add r3,r0      adc r8,r1   adc r9,r12   adc r10,r12   adc r11,r12
   mul reH,reL   add r3,r0      adc r8,r1   adc r9,r12   adc r10,r12   adc r11,r12
   mulsu A,reL               sbc r10,r12   sbc r11,r12   
   add r8,r0   adc r9,r1      adc r10,r12   adc r11,r12
   mulsu A,reH               sbc r11,r12   
   add r9,r0   adc r10,r1      adc r11,r12
   mulsu A,reL               sbc r10,r12   sbc r11,r12   
   add r8,r0   adc r9,r1      adc r10,r12   adc r11,r12
   mulsu A,reH               sbc r11,r12   
   add r9,r0   adc r10,r1      adc r11,r12
   Movw reL,R2      ;[R11:R10:R9:R8:reH:reL] = [A:reH:reL]^2

   Movw R0,reL MovW R2,R8 Mov R12,R10 Mov M,R11   ;suma badanie magnitude
   Add R0,timL Adc R1,timH Adc R2,R4   Adc R3,R5 Adc R12,R6 Adc M,R7

   Sub reL,timL  Sbc reH,timH   Sbc R8,R4    Sbc R9,R5 Sbc R10,R6 Sbc R11,R7
   mov reL,r8       mov reH,R9   mov A,R10 ;Re = (re^2 - im^2) >> Normbits (tutaj 16) ;*/

      RET   
Głównie AVR8 ASM, Próbowałem PIC32 ale C mi jakoś nie leży...


Wróć do „Pisanie programów w Assembler”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość