Rejestry jednostki zmiennoprzecinkowej
Koprocesor dysponuje ośmioma 80-bitowymi rejestrami zmiennoprzecinkowymi i trzema 16-bitowymi rejestrami kontrolnymi (control word, status word i tag word). Rejestry zmiennoprzecinkowe połączone są w stos. Możemy wczytywać do nich wartości rozkazami fld
(Fpu LoaD) oraz pobierać z nich wartości – fstp
(FPU STore and Pop). Mamy do nich dostęp poprzez nazwę ST i numer rejestru – ST(n). Wartości zawsze wstawiane są do rejestru ST(0), a wszystkie pozostałe rejestry zmieniają wtedy swoją numerację – 0 przechodzi na 1, 1 na 2 itd. Analogicznie podczas pobierania wartości z tego “stosu”, pobierana jest wartość z rejestru ST(0), a pozostałe zmieniają numerację w przeciwnym kierunku.
Podstawowe rozkazy jednostki zmiennoprzecinkowej
Rozkaz | Opis |
---|---|
fld REJESTR_ST |
Ładuje zawartość innego podanego rejestru ST do ST(0) i przesuwa numerację wszystkich rejestrów, włącznie z tym z którego pobierana jest wartość, w górę. |
fldl ZMIENNA/ADRES |
Podobnie jak poprzednio jednak ładowany jest float lub double z pamięci określonej przez etykietę zmiennej lub adres w rejestrze (wtedy mnemonik rejestru należy umieścić w nawiasie). |
fld1 |
Do ST(0) ładowana jest stała 1.0, a pozostałe rejestry są “przesuwane”. |
fldz |
-||- 0.0 -||- |
fldpi |
-||- liczba PI (3.1415926) -||- |
fst REJESTR_ST |
Wartość z rejestru ST(0) jest umieszczana w innym rejestrze ST. Numeracja rejestrów nie ulega zmianie. |
fstp REJESTR_ST lub nic |
Wartość z rejestru ST(0) jest kopiowana do innego podanego rejestru lub tracona, następnie wszystkie rejestry zmieniają swoją numerację (1->0, 2->1 itd.). |
fstpl ZMIENNA/ADRES |
Wartość z rejestru ST(0) kopiowana jest do zmiennej lub do pamięci pod adres sprecyzowany w innym rejestrze ogólnego przeznaczenia podanym w nawiasie. Numeracja rejestrów zmienia się jak poprzednio. |
fxch REJESTR_ST |
Zawartości rejestru ST(0) i innego podanego jako operand rozkazu są wymieniane. |
fabs |
Oblicza wartość bezwzględną z liczby w ST(0) i zapisuje ją do ST(0). |
fadd CEL, ŹRÓDŁO |
Dodaje zawartość ŹRÓDŁO do CEL i zapisuje wynik do CEL. ŹRÓDŁO i CEL to mnemoniki rejestrów ST. |
faddl ZMIENNA/ADRES |
Dodaje do ST(0), liczbę z pamięci. |
fsub CEL, ŹRÓDŁO |
Odejmuje zawartość ŹRÓDŁO od CEL i zapisuje wynik do CEL. ŹRÓDŁO i CEL to mnemoniki rejestrów ST. |
fsubl ZMIENNA/ADRES |
Odejmuje liczbę z pamięci od ST(0). |
fmul CEL, ŹRÓDŁO |
Mnoży zawartość CEL przez ŹRÓDŁO i zapisuje wynik do CEL. ŹRÓDŁO i CEL to mnemoniki rejestrów ST. |
fmull ZMIENNA/ADRES |
Mnoży zawartość ST(0) przez liczbę z pamięci. |
fdiv CEL, ŹRÓDŁO |
Dzieli zawartość CEL przez ŹRÓDŁO i zapisuje wynik do CEL. ŹRÓDŁO i CEL to mnemoniki rejestrów ST. |
fdivl ZMIENNA/ADRES |
Dzieli zawartość ST(0) przez liczbę z pamięci. |
fsqrt |
Oblicza pierwiastek z liczby zapisanej w ST(0) i zapisuje wynik do ST(0). |
Rejestr kontrolny
W rejestrze kontrolnym (control word) zapisane są ustawienia jednostki FPU. Przy pomocy rozkazu fstcw
można zapisać jego zawartość do pamięci, a następnie instrukcją mov
przenieść do rejestru ogólnego przeznaczenia. Poszczególne bity tego rejestru odpowiadają min. za sposób zaokrąglania wartości, czy dokładność obliczeń. Możemy je zmienić, a następnie zapisać do rejestru w analogiczny sposób, umieszczając jego zawartość w pamięci i rozkazem fldcw
ładując ustawienia. Zostało to dokładniej przedstawione w zadaniu pierwszym i drugim, gdzie odczytywane i zmieniane są parametry pracy jednostki zmiennoprzecinkowej.
Zadanie pierwsze – Wyświetlanie i zmiana precyzji obliczeń
Kod C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
#include <stdio.h> // Deklaracja funkcji które zostaną dołączone // dopiero na etapie linkowania kodu extern int sprawdz(); extern int ustaw(int precyzja); int main(void) { // Wyświetlenie menu, pobranie od użytkownika numeru opcji // i wyświetlenie lub ustawienie precyzji obliczeń korzystając // z funkcji napisanych w Asemblerze int nr_opcji=1, precyzja=1; do { printf("=== Wybierz: ===\n"); printf("1 - aby sprawdzic aktualna precyzje obliczen\n"); printf("2 - aby zmienic aktualna precyzje obliczen:\n"); printf("0 - aby zakonczyc program\n"); scanf("%d", &nr_opcji); switch(nr_opcji) { case 1: printf("\nAktualna precyzja: "); switch(sprawdz()) { case 0: printf("Single Precision\n\n"); break; case 2: printf("Double Precision\n\n"); break; case 3: printf("Double Extended Precison\n\n"); break; } break; case 2: printf("\n1 - Single Precision\n"); printf("2 - Double Precision\n"); printf("3 - Double Extended Precision\n"); scanf("%d", &precyzja); if (precyzja>3 || precyzja<1) printf("Podano zla wartosc\n"); else ustaw(precyzja); printf("\n"); break; } } while(nr_opcji!=0); return 0; } |
Kod Asemblerowy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
.data control_word: .short 0 .text # Zadeklarowane tutaj funkcje będą możliwe do wykorzystania # w języku C po zlinkowaniu plików wynikowych kompilacji obu kodów .global ustaw, sprawdz .type ustaw, @function .type sprawdz, @function ustaw: push %rbp mov %rsp, %rbp # Pierwszy i jedyny parametr funkcji umieszczony zostanie # w rejestrze RDI. Może on zawierać jedną z trzech wartości: # 1 dla single, 2 dla double i 3 dla extended # Pobranie zawartości rejestru kontrolnego do rejestru AX # przez komórkę w pamięci mov $0, %rax fstcw control_word fwait mov control_word, %ax # Wyzerowanie bitów kontroli prezycji (00 - początkowo single) and $0xFCFF, %ax # 1111 1100 1111 1111 # Zamiana na double lub extended w zależności # od przesłnego parametru cmp $2, %rdi jl koniec je double # Zmiania na extended (11) extended: xor $0x300, %ax # 0000 0011 0000 0000 jmp koniec # Aby nie zmienić na double # Zmiana na double (10) double: xor $0x200, %ax # 0000 0010 0000 0000 koniec: # Zapisanie słowa kontrolnego z rejestru AX do rejestru CW mov %ax, control_word fldcw control_word mov %rbp, %rsp pop %rbp ret sprawdz: push %rbp mov %rsp, %rbp # Pobranie słowa kontrolnego FPU so rejestru AX mov $0, %rax fstcw control_word fwait mov control_word, %ax # Wyzerowanie pozostałych bitów poza bitami kontroli precyzji # i przesunięcie wygenerowanych bitów w prawo na koniec and $0x300, %ax # 0000 0011 0000 0000 shr $8, %ax # Wartość zwracana znajduje się już w EAX. Przyjmuje wartości: # 0 dla single, 2 dla double i 3 dla extended mov %rbp, %rsp pop %rbp ret |
Zadanie drugie – Wyświetlanie i zmiana sposobu zaokrąglania
Kod C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#include <stdio.h> // Deklaracja funkcji które zostaną dołączone // dopiero na etapie linkowania kodu extern int sprawdz(); extern int ustaw(int tryb); int main(void) { int nr_opcji=1, tryb=1; do { printf("=== Wybierz: ===\n"); printf("1 - aby sprawdzic aktualny tryb zaokraglania\n"); printf("2 - aby zmienic aktualny tryb zaokraglania:\n"); printf("0 - aby zakonczyc program\n"); scanf("%d", &nr_opcji); switch(nr_opcji) { case 1: printf("\nAktualny tryb zaokraglania: "); switch(sprawdz()) { case 0: printf("Round to nearest\n\n"); break; case 1: printf("Round down\n\n"); break; case 2: printf("Round up\n\n"); break; case 3: printf("Truncate\n\n"); break; } break; case 2: printf("\n0 - Round to nearest\n"); printf("1 - Round down\n"); printf("2 - Round up\n"); printf("3 - Truncate\n"); scanf("%d", &tryb); if (tryb>3 || tryb<0) printf("Podano zla wartosc\n"); else ustaw(tryb); printf("\n"); break; } } while(nr_opcji!=0); return 0; } |
Kod Asemblerowy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
.data control_word: .short 0 .text # Zadeklarowane tutaj funkcje będą możliwe do wykorzystania # w języku C po zlinkowaniu plików wynikowych kompilacji obu kodów .global ustaw, sprawdz .type ustaw, @function .type sprawdz, @function ustaw: push %rbp mov %rsp, %rbp # Pierwszy i jedyny parametr funkcji umieszczony zostanie # w rejestrze RDI. Jego możliwe wartości to: # 0 dla nearest, 1 dla round down, 2 dla round up # i 3 dla truncate # Pobranie zawartości rejestru kontrolnego do rejestru AX # przez komórkę w pamięci mov $0, %rax fstcw control_word fwait mov control_word, %ax # Wyzerowanie bitów kontroli zaokrąglania # (00 - początkowo nearest) and $0xF3FF, %ax # 1111 0011 1111 1111 # Przesunięcie przesłanej jako parametr funkcji # wartości w lewo o 10 bitów shl $10, %rdi # Ustawienie odpowiednich bitów w zawartości # pobranego rejestru CW xor %di, %ax # Zapis zmienionej wartości do rejestru CW mov %ax, control_word fldcw control_word mov %rbp, %rsp pop %rbp ret sprawdz: push %rbp mov %rsp, %rbp # Pobranie słowa kontrolnego FPU do rejestru AX mov $0, %rax fstcw control_word fwait mov control_word, %ax # Wyzerowanie pozostałych bitów poza bitami kontroli # zaokrąglania i przesunięcie wygenerowanych bitów # w prawo na ostatnie pozycje and $0xC00, %ax # 0000 1100 0000 0000 shr $10, %ax # Wartość zwracana znajduje się już w EAX. Przyjmuje wartości: # 0 dla nearest, 1 dla round down, 2 dla round up # i 3 dla truncate mov %rbp, %rsp pop %rbp ret |
Szereg Taylora
Kolejnym zadaniem domowym był program przybliżający wartość funkcji sinus korzystając z rozwinięcia szeregu Taylora. Na zajęciach napisana została modyfikacja tego programu, tak aby przybliżana była wartość cosinusa. Oba programy są niemal identyczne.
Wartość funkcji sinus w zadanym punkcie przybliżana jest ze wzoru x -x3/3! +x6/6! ... +((-1)n * x2n-1)/(2n-1)!
. Program nie liczy w każdym obiegu pętli kolejnych wyrazów ciągu, a jedynie je uzupełnia. Pierwszym wyrazem ciągu jest x
– wartość kąta w radianach podana przez użytkownika. Następnym: poprzednia wartość ciągu * -x2 / (Y+1)(Y+2)
gdzie (Y+1)(Y+2)
to 2 kolejne “wyrazy” silni, przy założeniu że początkowo silnia jest równa 1.0. Dla drugiego wyrazu przyjmie ona wtedy wartość 1.0*2.0*3.0
, co daje 3!
. Przy obliczaniu wartości funkcji cosinus, początkowym wyrazem nie jest kąt podany przez użytkownika, a wartość 1.0. Silnie również zaczynamy liczyć od 0.0, tak aby dla pierwszego wyrazu przyjęła ona wartość 2!
, a nie 3!
(nie mnożymy wartości przez 0.0, pierwszym wyrazem jest (Y+1)(Y+2)
).
Zadanie trzecie – Aproksymacja funkcji Sinus
Kod C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdio.h> // Deklaracja funkcji która zostanie dołączona // dopiero na etapie linkowania kodu extern double taylor(double a, int b); int main(void) { int i; double f; printf("Kat: "); scanf("%lf", &f); printf("Liczba wyrazow ciagu: "); scanf("%d", &i); printf("Twoj wynik to: %lf\n", taylor(f, i)); return 0; } |
Kod Asemblerowy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
.data minus: .double -1.0 silnia: .double 1.0 .text # Zadeklarowana tutaj funkcja będzie możliwa do wykorzystania # w języku C po zlinkowaniu plików wynikowych kompilacji obu kodów .global taylor .type taylor, @function # Funkcja obliczająca przybliżenie wartości sinusa # z szeregu Taylora taylor: push %rbp mov %rsp, %rbp # Przyjmowane przez funkcje argumenty: # RDI - ilość kroków # XMM0 - kąt w radianach # Załadowanie wartości z rejestru XMM0 # do rejestrów ST(0), ST(1) i ST(2) przez stos sub $8, %rsp movsd %xmm0, (%rsp) fldl (%rsp) # ST(0) = przesłany kąt fld %st # ST(1) = ST(0); ST(0) = zawartość ST(0) # z poprzedniej linijki fld %st # -||- # Zawartość rejestrów FPU obecnie, na początku i końcu pętli: # ST(0) - aktualny wyraz ciągu (początkowo równy x) # ST(1) - aktualna suma ciągu (-||-) # ST(2) - przesłany kąt (x) movq $0, %rsi # Licznik do pętli fwait # Oczekiwanie na zakończenie wykonywanych przez # FPU obliczeń petla: # Wyskok z pętli po obliczeniu wszystkich wyrazów cmp %rdi, %rsi je koniec inc %rsi # Zwiększenie licznika wykonań pętli ### ### Obliczenie licznika ### fmul %st(2), %st # Aktualny wyraz ciągu (ST(0)) *= x fmul %st(2), %st # Aktualny wyraz ciągu (ST(0)) *= x fmull minus # Aktualny wyraz ciągu (ST(0)) * (-1) # Po wykonaniu tych instrukcji uzyskamy: # Aktualny wyraz ciągu = poprzedni wyraz ciągu * (-x^2) ### ### Obliczanie mianownika - silni ### fld1 # ST(0) -> ST(1)...; ST(0) = 1.0 fld1 # ST(0) -> ST(1)...; ST(0) = 1.0 fldl silnia # ST(0) -> ST(1)...; # ST(0) = zawartość komórki pamięci - silnia # Aktualne rejestry: # ST(0) - numer wyrazu silni (z "silnia") # ST(1) - wynik silni (bez uwzględnienia # wcześniejszych części), początkowo 1.0 # ST(2) - 1.0 # Obliczenie kolejnych dwóch wyrazów silni: # Jeśli początkowa wartość ze zmiennej "silnia" była równa # Y, to w tej części obliczane są "wyrazy" (Y+1)*(Y+2). # Przez obliczoną wartość dzielny jest poprzedni wyraz # ciągu, po uprzednim pomnożeniu przez -x^2. # Po tym etapie, obecny wyraz ciągu jest równy: # (poprzedni wyraz ciągu * -x^2) / (Y+1)*(Y+2) fadd %st(2), %st fmul %st, %st(1) fadd %st(2), %st fmul %st, %st(1) fstpl silnia # Zapisanie numery ostatniego wyrazu # silni do zmiennej i ściągnięcie go # ze "stosu" FPU # Usunięcie niepotrzebnych wartości fxch %st(1) # Zamiana miejscami ST(0) i ST(1) fstp %st # Ściągnięcie ze "stosu" FPU ostatniej # wartości # Aktualne rejestry: # ST(0) - silnia (obecny dzielnik) # ST(1) - wartość do podzielenia (aktualny wyraz ciągu) # ST(2) - aktualna suma ciągu # ST(3) - przesłany kąt (x) fdivr %st, %st(1) # Dzielenie obecnego wyrazu przez # dzielnik (silnie) - wynik trafi # do ST(1) fstp %st # Usunięcie obecnego dzielnika ze "stosu" FPU # Zawartość rejestrów jak na początku pętli fadd %st, %st(1) # Dodanie wartości obecnego wyrazu # do wyniku globalnego jmp petla # Powrót na początek pętli # Przeniesienie wyniku z rejestru ST(0) (sumy ciągu) # do rejestru XMM0 przez stos i zakończenie funkcji koniec: fstp %st fstpl (%rsp) movsd (%rsp), %xmm0 mov %rbp, %rsp pop %rbp ret |
Zadanie czwarte – Aproksymacja funkcji Cosinus
Kod C:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <stdio.h> // Deklaracja funkcji która zostanie dołączona // dopiero na etapie linkowania kodu extern double taylor(double a, int b); int main(void) { int i; double f; printf("Kat: "); scanf("%lf", &f); printf("Liczba wyrazow ciagu: "); scanf("%d", &i); printf("Twoj wynik to: %lf\n", taylor(f, i)); return 0; } |
Kod Asemblerowy:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
.data minus: .double -1.0 silnia: .double 0.0 .text # Zadeklarowana tutaj funkcja będzie możliwa do wykorzystania # w języku C po zlinkowaniu plików wynikowych kompilacji obu kodów .global taylor .type taylor, @function # Funkcja obliczająca przybliżenie wartości sinusa # z szeregu Taylora taylor: push %rbp mov %rsp, %rbp # Przyjmowane przez funkcje argumenty: # RDI - ilość kroków # XMM0 - kąt w radianach # Załadowanie wartości z rejestru XMM0 # do rejestrów ST(0), ST(1) i ST(2) przez stos sub $8, %rsp movsd %xmm0, (%rsp) fldl (%rsp) # ST(0) = przesłany kąt fl1 # ST(1) = ST(0); ST(0) = 1.0 fl1 # -||- # Zawartość rejestrów FPU obecnie, na początku i końcu pętli: # ST(0) - aktualny wyraz ciągu (początkowo 1.0) # ST(1) - aktualna suma ciągu (początkowo 1.0) # ST(2) - przesłany kąt (x) movq $0, %rsi # Licznik do pętli fwait # Oczekiwanie na zakończenie wykonywanych # przez FPU obliczeń petla: # Wyskok z pętli po obliczeniu wszystkich wyrazów cmp %rdi, %rsi je koniec inc %rsi # Zwiększenie licznika wykonań pętli ### ### Obliczenie licznika ### fmul %st(2), %st # Aktualny wyraz ciągu (ST(0)) *= x fmul %st(2), %st # Aktualny wyraz ciągu (ST(0)) *= x fmull minus # Aktualny wyraz ciągu (ST(0)) * (-1) # Obecny wyraz ciągu = poprzedni wyraz ciągu * (-x^2) ### ### Obliczanie mianownika - silni ### fld1 # ST(0) -> ST(1)...; ST(0) = 1.0 fld1 # ST(0) -> ST(1)...; ST(0) = 1.0 fldl silnia # ST(0) -> ST(1)...; # ST(0) = zawartość komórki pamięci - silnia # Aktualne rejestry: # ST(0) - numer wyrazu silni (z "silnia") # ST(1) - wynik silni (bez uwzględnienia # wcześniejszych części), początkowo 1.0 # ST(2) - 1.0 # Obliczenie kolejnych dwóch wyrazów silni: # Jeśli początkowa wartość ze zmiennej "silnia" była równa # Y, to w tej części obliczane są "wyrazy" (Y+1)*(Y+2). # Przez obliczoną wartość dzielny jest poprzedni wyraz # ciągu, po uprzednim pomnożeniu przez -x^2. # Na tym etapie, obecny wyraz ciągu jest równy: # (poprzedni wyraz ciągu * -x^2) / (Y+1)*(Y+2) fadd %st(2), %st fmul %st, %st(1) fadd %st(2), %st fmul %st, %st(1) fstpl silnia # Zapisanie numery ostatniego wyrazu silni # do zmiennej i ściągnięcie go # ze "stosu" FPU # Usunięcie niepotrzebnych wartości fxch %st(1) # Zamiana miejscami ST(0) i ST(1) fstp %st # Ściągnięcie ze "stosu" FPU # ostatniej wartości # Aktualne rejestry: # ST(0) - silnia (obecny dzielnik) # ST(1) - wartość do podzielenia (aktualny wyraz ciągu) # ST(2) - aktualna suma ciągu # ST(3) - przesłany kąt (x) fdivr %st, %st(1) # Dzielenie obecnego wyrazu przez # dzielnik (silnie) - wynik trafi # do ST(1) fstp %st # Usunięcie obecnego dzielnika ze "stosu" FPU # Zawartość rejestrów jak na początku pętli fadd %st, %st(1) # Dodanie wartości obecnego wyrazu # do wyniku globalnego jmp petla # Powrót na początek pętli # Przeniesienie wyniku z rejestru ST(0) (sumy ciągu) # do rejestru XMM0 przez stos i zakończenie funkcji koniec: fstp %st fstpl (%rsp) movsd (%rsp), %xmm0 mov %rbp, %rsp pop %rbp ret |
Specjalne podziękowania dla Mateusza Gniewkowskiego za pomoc w przygotowaniu tego wpisu :-)
Dobra robota ;)
przepraszam ze tutaj komentuje, ale nie znalazlem innej drogi
czy moglbys na nadajniki.olo.ovh zrobic jakas mozliwosc filtrowania po firmie? filtr pozytywny i negatywny (np. zeby mozna bylo odfiltrowac lokalna energetyke ktora ma wiekszosc infrastruktury w okolicach wiejskich i zostawic wszystko inne)
niestety nie jest to możliwe, ale zapraszam na http://http://uke.kurylowicz.info/, to chyba to czego szukasz. moja mapa jest generowana w google fusion tables, jako warstwa mapy google. wykonałem to w ten sposób, ponieważ punktów jest na prawdę dużo, a chcę wyświetlić je wszystkie. jeśli miały by one być nanoszone na mapę w skrypcie js, co pozwoliło by na ich filtrowanie, załadowanie mapy po wejściu na stronę trwało by wieki.
<3
Jak wyłączyć tę zgode na kopanie kryptowaluty? Telefon ledwo chodzi…
Proszę wyczyścić ciasteczka, tam zapisana jest zgoda. Coś musiało pójść nie tak. Czy mogę prosić o informacje jaki to telefon? Kopanie jest zablokowane na telefonach, a na komputerach nie powinno zużyć więcej jak 25% mocy CPU.