kategoria: Asembler
[#1] Funkcja do wypełniania danymi
Napisałem sobie krótką prostą funkcję w asemblerze do wypełniania danymi zaalokowanej wczeniej części pamięci. Często to wykorzystywałem do szybkiego wyczyszczenia danych, bądź poustawiania sobie kolejno tych samych wartości. Ostatnio jednak zauważyłem, że funkcja ta ma ograniczenie co do offsetu.

Oto ona:
#DLUGOSC = 1000000

D.l = AllocMem_(#DLUGOSC,0)


      GetReg A0,D             ; A0 - poczatek bloku danych

      MOVE.l #DLUGOSC,D7
      ASR.l #2,D7
      SUBQ.l #1,D7            ; D7 - licznik petli

loop: MOVE.l #$ffffffff,(A0)+ ; probuje zapisac caly bank danych
      DBF D7,loop             ; wartosciami $ff



; SPRAWDZAM POPRAWNOSC DANYCH
                                                  ; Przy sprawdzaniu calego
For i.l = 0 To #DLUGOSC-1                         ; bloku danych wypisuje
                                                  ; pierwszy offset w ktorym
  If Peek.b(D+i)<>-1 Then NPrint i : i=#DLUGOSC   ; wartosc bajtu jest rozna
                                                  ; od -1 ($FF)
Next

FreeMem_ D,#DLUGOSC

Stop
End


Niby duży rozmiar banku pamięci, ale ogólnie to niecały 1 MB, więc nie powinno być z tym problemu. Wbudowana funkcja Fill działa bardzo dobrze w Blitz Basicu, natomiast dziwi mnie, dlaczego ta ręcznie napisana pętla przestaje zapisywać dane na bajcie około 219 000 / 220 000 - różnie to bywa.

Czy to jest związane z jakimś stosem pętli i użyciem DBxx, czy może odniesienie do (A0)+ ma jakieś ograniczenie offsetu?
[#2] Re: Funkcja do wypełniania danymi

@tukinem, post #1

Licznik w poleceniu DBcc ma rozmiar 16-bitowego słowa. Można tam wpisać wartości od $0 do $FFFF. Pętla zmniejsza licznik o 1 i kończy się, kiedy wartość licznika osiągnie -1, czyli $FFFF.

Jeżeli chcesz licznik 32-bitowy (długie słowo) należy użyć np.:

SUBQ.L #1,D7
BGE.B .loop

Nota: możesz zoptymalizować procedurę jeżeli zamieścisz stałą w rejestrze danych, np. tak:

MOVEQ #-1,D0

.loop: MOVE.L D0,(A0)+

Czas wykonania tej procedury będzie zdecydowanie krótszy.

Ostatnia aktualizacja: 09.12.2024 22:13:53 przez Hexmage960
4
[#3] Re: Funkcja do wypełniania danymi

@Hexmage960, post #2

To wszystko wyjaśnia. Dziękuję bardzo za szybką i konkretną odpowiedź.
[#4] Re: Funkcja do wypełniania danymi

@tukinem, post #3

A, i lepiej nie uzywaj asr tylko lsr jak robisz licznik petli, bo kiedys mozesz sie przejechac.

Ostatnia aktualizacja: 09.12.2024 23:02:45 przez Don_Adan
1
[#5] Re: Funkcja do wypełniania danymi

@Don_Adan, post #4

Któryś unika ujemnych liczb, tylko nigdy nie pamiętam który. Chyba ASR/ASL. Raz w czymś używałem LSR, czy LSL i mi ciągle robił pod górę przez ujemne liczby, a wtedy z pomocą przyszedł ASR/ASL. Ale co to było, to nie pamiętam. Jeśli przy pętlach należy używać LSR to sobie to zmienię od razu żeby nie zapomnieć
[#6] Re: Funkcja do wypełniania danymi

@tukinem, post #5

ASL/ASR to przesuwanie "Arytmetyczne", a LSR/LSL to przesuwanie "Logiczne".

Arytmetyczne służy do przesuwania liczb ze znakiem. Najstarszy bit wtedy nie ulega przesuwowi, więc znak liczby (dodatnia/ujemna) jest zachowany.

Logiczne służy do przesuwania liczb bez znaku (lub wartości logicznych). Tutaj bit znaku również jest przesuwany.

Polecam Ci uruchomić sobie Debugger programu Asm-One (makroasembler z GUI). Jest tam wgląd w wyniki operacji. Można śledzić krok po kroku jak zmieniają się stany rejestrów po poszczególnych poleceniach.

Ostatnia aktualizacja: 09.12.2024 23:40:32 przez Hexmage960
[#7] Re: Funkcja do wypełniania danymi

@Hexmage960, post #6

Popróbuję, chociaż dłubanie w debuggerach nie idzie mi za dobrze. Nawet w BB2.

Porównałem szybkość tej funkcji z funkcją FillMem wbudowaną w Blitz Basic 2. Wyniki są ciekawe.

Procesor 68000 7MHz z jedynie dostępną 2MB pamięcią Chip RAM i kickstartem 3.1 wypluł mi takie wyniki czasowe w trybie PAL:
funkcja w ASM: 60 ramek
funkcja w BB2: 207 ramek
1
[#8] Re: Funkcja do wypełniania danymi

@tukinem, post #5

Akurat odwrotnie jest.
ASR gdy interesuje Ciebie znak liczby.
Pozostale przesuniecia czyli LSR, LSL, ASL sa bez znakowe.
[#9] Re: Funkcja do wypełniania danymi

@tukinem, post #7

Ja tam nie uzywalem debugerow.
Ale w ASM-onie mozna np. napisac

? -2
i wyswietli sie rezultat
[#10] Re: Funkcja do wypełniania danymi

@tukinem, post #7

Akurat Debugger Asm-One jest mega prosty i wygodny w użyciu. Po prostu klikasz kursor w dół i wykonuje Ci kolejne polecenia z kodu źródłowego. Można użyć do sprawdzania zachowania się instrukcji - dość często korzystam.

Wtedy na przykład zobaczysz co DBF robi z licznikiem itp.

@Don Adan

W sumie ten ASR duplikuje bit znaku, czego nie byłem do końca świadomy. W sumie normalne, bo mając liczbę -2, czyli $FE (-128 + 126) to ASR o jeden bit, powinien dać w wyniku $FF (-128 + 127), czyli -1.

Natomiast co do ASL to - z tego co widzę - różni się tym, że daje przepełnienie (Overflow) kiedy znak liczby się zmieni przez przesunięcie.
1
[#11] Re: Funkcja do wypełniania danymi

@tukinem, post #7

A jak chcesz szybsze wersje to mozesz uzyc:

GetReg A0,D             ; A0 - poczatek bloku danych

      move.l      #DLUGOSC,D7
      lsr.l        #2,D7
      subq.l #1,D7            ; D7 - licznik petli
      moveq #-1,D0
loop: 
      move.l D0,(A0)+ ; probuje zapisac caly bank danych
      dbf D7,loop             ; wartosciami $ff


GetReg A0,D             ; A0 - poczatek bloku danych

      move.l      #DLUGOSC,D7
      lsr.l        #3,D7  ; musi byc podzielne przez 8
      subq.l #1,D7            ; D7 - licznik petli
      moveq #-1,D0
loop: 
      move.l D0,(A0)+ ; probuje zapisac caly bank danych
      move.l D0,(A0)+
      dbf D7,loop             ; wartosciami $ff
[#12] Re: Funkcja do wypełniania danymi

@Hexmage960, post #10

ASL jest w zasadzie zbedna instrukcja, moze w jakis przypadkach szczegolnych sie przydaje do czegos.
Mi nic takiego do glowy nie przychodzi.
[#13] Re: Funkcja do wypełniania danymi

@Don_Adan, post #12

Według mnie wybór między ASL i LSL zależy po prostu od obranej arytmetyki liczb ze znakiem lub bez znaku.

W języku C mamy typy signed i unsigned.

Oczywiście istnieją takie operacje jak np. DBT (Decrement and Branch if True), które powstały po prostu jako naturalne dopełnienie zestawu instrukcji z rodziny DBcc, ale nie pełnią istotnej roli.

Ostatnia aktualizacja: 10.12.2024 00:45:50 przez Hexmage960
[#14] Re: Funkcja do wypełniania danymi

@Hexmage960, post #13

Szukałem i nie mogę znaleźć, w czym używałem ASR/ASL, ale podejrzewam, że to było do takich działań, aby uniknąć ujemnych znaków przy wynikach.

Sprawdziłem sobie różnice pomiędzy ASL i LSL:
MOVEQ #1,D0
MOVE.l D0,D1

LSL.l #31,D0
ASL.l #31,D1


oba wyniki to ujemne liczby, a przynajmniej BB2 je wyczytuje jako ujemne. Zarówno w D0 jak i w D1 mamy wynik %1000000000000000000000000000000. Teraz różnica pomiędzy ASR i LSR:

LSR.l #31,D0
ASR.l #31,D1


W D0 mamy %1, a w D1 będziemy mieć %10000000000000000000000000000001, ponieważ ASR nie ruszy najstarszego bitu.
[#15] Re: Funkcja do wypełniania danymi

@tukinem, post #14

W pierwszym przypadku bedziesz mial D0 i D1 rowne $80000000.
A to juz jest liczba ujemna.
W drugim przypadku bedziesz mial D0 =1 i D1= -1 ($ffffffff).
Nie bedzie zadnego D1= %10000000000000000000000000000001
[#16] Re: Funkcja do wypełniania danymi

@tukinem, post #14

Jeszcze ważna nota: Dana natychmiastowa we wszystkich instrukcjach przesuwania może przyjmować wartości od 1 do 8.

Jeżeli chcesz przesuwać o więcej bitów, należy umieścić liczbę bitów w rejestrze danych, np.:

MOVEQ #31,D0
LSL.L D0,D1

Ale asembler powinien zgłosić błąd.

P.S. Tutaj jest fajny przewodnik po procesorach serii MC680xx (po angielsku):

https://www.nxp.com/docs/en/reference-manual/M68000PRM.pdf

Ja polecam książkę Wojciecha Czyża "Rodzina MC680xx", ale teraz trudna do dostania.

Ostatnia aktualizacja: 10.12.2024 15:59:27 przez Hexmage960
[#17] Re: Funkcja do wypełniania danymi

@Hexmage960, post #16

Jaki blad ma zglosic asembler?
Przesuwa o 31 bitow w lewo, czyli w D1 bedzie albo 0 albo $80000000.
[#18] Re: Funkcja do wypełniania danymi

@Don_Adan, post #17

Asembler powinien zgłosić błąd przy asemblacji, co do parametru ASL, ASR, LSL, LSR. Sprawdziłem w Asm-One.

Odnosiłem się tylko do kwestii parametru, czyli liczby bitów o które chcemy przesunąć liczbę. Nie odnosiłem się co do wyniku operacji.

Ostatnia aktualizacja: 10.12.2024 16:05:36 przez Hexmage960
[#19] Re: Funkcja do wypełniania danymi

@Don_Adan, post #15

[quote]Nie bedzie zadnego D1= %10000000000000000000000000000001


Faktycznie zostawia ujemną liczbę, a każde przesunięcie w prawo zostawia po sobie zapalony bit.

@Hexmage960: Masz rację. Nie mogę użyć LSL.l #31,D0, natomiast BB ma swoje przesuwanie bitów o takiej samej nazwie i tu mogę, co mnie zmyliło. Ten kod jest poprawny, bo tu przesuwanie bitów jest z poziomu BB:
NPrint zmienna LSL 31 LSR 31


Wklepałem taki kod:


i otrzymałem zgodne wyniki:
[#20] Re: Funkcja do wypełniania danymi

@tukinem, post #19

I teraz jest ok.
A wracajac do tematu.
To jak chcesz uniwersalna (dziala z longwordem i dbf) i szybka funkcje wypelniajaca to mozesz uzyc takiej:

GetReg A0,D             ; A0 - poczatek bloku danych

      move.l      #DLUGOSC,D7
      lsr.l       #2,D7
      move.l #xxxxxxxx,D0 ; xxxxxxxx to wartosc jaka wypelniasz buffor
      bra.b skip
loopfull:
      swap D7
loop: 
      move.l D0,(A0)+
skip:
      dbf D7,loop 
      swap D7
      dbf D7,loopfull
      rts
[#21] Re: Funkcja do wypełniania danymi

@Don_Adan, post #20

Pomysłowe :) nie wpadłbym na to nigdy :)
[#22] Re: Funkcja do wypełniania danymi

@tukinem, post #21

Nie moje, podpatrzone.
Teraz pewnie tez pare procedur bym zmodyfikowal do uzywania dbf dla longworda, zamiast uzywac subq.l #1,Dx.
Na stronie www.PPA.pl, podobnie jak na wielu innych stronach internetowych, wykorzystywane są tzw. cookies (ciasteczka). Służą ona m.in. do tego, aby zalogować się na swoje konto, czy brać udział w ankietach. Ze względu na nowe regulacje prawne jesteśmy zobowiązani do poinformowania Cię o tym w wyraźniejszy niż dotychczas sposób. Dalsze korzystanie z naszej strony bez zmiany ustawień przeglądarki internetowej będzie oznaczać, że zgadzasz się na ich wykorzystywanie.
OK, rozumiem