Autor Wątek: Proste i przyjemne procedurki asemblerowe dla początkujących  (Przeczytany 36122 razy)

sect0r

  • *****
  • Wiadomości: 698
  • Miejsce pobytu:
    Oltedal/NO
  • speccyholic
Chciałbym umieścić często używane i przydatne procedury w jednym miejscu.
W większości będą przepisane z książek, znalezione gdzieś na forach, w gazetach itp.
Oczywiście nie muszę wspominać, że chętnie ujrzymy zoptymalizowane, szybsze odpowiedniki tych procedurek.
Osoby uczące się, lub chcące nauczyć się asemblera prosi się o komentowanie i zadawanie pytań  ;)

Zacznę od prostego czyszczenia ekranu przy pomocy LDIR
Niszczone: A
Wyjście: BC=0, DE=5800h, HL=57FFh (lub inne wartości DE, HL użyte przez nas)

LD   HL,4000h
LD   BC,17FFh
LD   (HL),L
LD   D,H
LD   E,1
LDIR
RET

Użycie LD (HL),L (dopóki L=0) jest szybsze i zajmuje mniej pamięci niż LD (HL),0
Procedurkę można dostosować do czyszczenia jednej, dwóch części , czy całego ekranu.
Poniżej odpowiednie przydatne wartości HL i BC
Adres w HL
Góra4000h
Środek    4800h
Dół5000h

Wartość dla BC
1 część część    07FFh
1 i 2 część ekranu0FFFh
cały ekran17FFh

Dla przykładu, jeśli chcemy wyczyścić dwie dolne tercje użyjemy
LD   HL,4800h
LD   BC,0FFFh

PS. Jeśli posiadamy jakieś ważne warości w rejestrach A, B, C, D, E, H, L możemy odłożyć je na stosie poprzez użycie PUSH xx (gdzie xx to para rejestrów np. BC),
a następnie po powrocie z procedurki ściągamy je komendą POP xx
« Ostatnia zmiana: 2014.03.02, 21:01:20 wysłana przez sect0r »
Szarak # DivIDE+ # MasakratorFM DeluXe by Zaxon

sect0r

  • *****
  • Wiadomości: 698
  • Miejsce pobytu:
    Oltedal/NO
  • speccyholic
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #1 dnia: 2014.03.02, 21:23:46 »
Kolejne procedurki

Dla podanego w HL adresu ekranu (bajtu), otrzymamy w BC adres odpowiadającej mu komórki w pamięci atrybutów (przypominam że atrybuty w ZX Spectrum odnoszą się do pola 8x8 pixeli)

Wejście: HL=adres komórki pamięci ekranu
Niszczone: HL,BC,DE,A
Wyjście: DE=adres komórki atrybutów

LD   A,H
RRCA
RRCA
RRCA
AND   3
OR   58h
LD   D,A
LD   E,L
RET

I jej odwrotność, znajdująca adres pierwszego bajtu (pierwsze 8x1 pikseli) w pamięci ekranu odpowiadającego danej komórce pamięci atrybutów

Wejście: HL=Adres atrybutów
Niszczone: HL,BC,DE,A
Wyjście: DE=adres pamięci ekranu, A=D
LD   A,H
AND 3
RLCA
RLCA
RLCA
OR   40h
LD   D,A
LD   E,L
RET
Szarak # DivIDE+ # MasakratorFM DeluXe by Zaxon

sect0r

  • *****
  • Wiadomości: 698
  • Miejsce pobytu:
    Oltedal/NO
  • speccyholic
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #2 dnia: 2014.03.03, 12:07:21 »
Odnośnie pierwszego listingu, powinno być
Wartość dla BC:
1 część ekranu      07FFh
2 części ekranu   0FFFh
cały ekran      17FFh
Szarak # DivIDE+ # MasakratorFM DeluXe by Zaxon

matofesi

  • *****
  • Wiadomości: 2049
  • Miejsce pobytu:
    Toruń/Poland
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #3 dnia: 2014.03.03, 12:37:53 »
To ja tylko powiem, że kasowanie pamięci LDIRem jest fajne pod warunkiem, że nam się nie spieszy ;) Wykonanie w odpowiednio wyliczonej pętli sekwencji LDI zajmie więcej miejsca ale zaoszczędzi sporo czasu traconego przy LDIR na wewnętrzną obsługę pętli.

A z procedurami liczącymi różne adresy ekranu to też radzę uważać - jeśli potrzebujemy ich często to warto się zastanowić czy da się takie informacje stablicować i wyjmować dane z tablicy zamiast liczyć :)

Oczywiście w większości zastosowań nie ma to strategicznego znaczenia, ale jak się dłubie jakieś bardziej zaawansowane efekty graficzne to trzeba się liczyć z każdym taktem ;)

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #4 dnia: 2014.03.03, 12:47:56 »
A jak liczenie się z każdym taktem.. to z pomocą przychodzi stos ;)
Ale to może temat nie na post a bardziej artykuł.

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #5 dnia: 2014.03.03, 13:00:42 »
Trzeba też mieć wyczucie kiedy coś optymalizować pod względem szybkości a kiedy nie.

Jakiś czas temu widziałem na WOS post człowieka który chciał optymilizować czasowo drukowanie tekstu ;) Robił jakieś skalowanie liter do różnych rozmiarów i aby mu się to szybciej drukowało wymyślił jakiś bardzo złożony algorytm, jakieś bufory, mnóstwo tablic z danymi pomocniczymi itp.

Napisałem mu, po co to wszystko? Co za różnica czy strona tekstu wyświetli się przez jedną ramkę czy przez dwie skoro człowiek i tak tego nie zauważy.

Jakoś mnie nie zrozumiał ;) i odpowiedział że skoro można szybciej to trzeba szybciej. A to że pamięc nie jest z gumy to nic, to że przy skomplikowanych algorytmach rośnie ryzyko buga to nic, to że trzeba się znacznie więcej napracować też nic.

W praktyce jest tak jak już napisali przedmówcy - optymalizujemy krytyczne miejsca kodu, resztę piszemy jak szybciej i wygodniej, bo jak będziemy optymalizować każdą duperelę to całe życie będziemy pisać procedurki a nigdy nie ukończymy np pełnej gry.

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #6 dnia: 2014.03.03, 13:21:58 »
Zawsze optymalizuje swoje procedury po ich napisaniu - wtedy kiedy już działają poprawnie. Optymalizacja podczas pisania to zwykła strata czasu.
I tak jak Rafał napisał - przede wszystkim zdrowy rozsądek i ocena, co musi być szybko a co 'w normalnym tempie'.

matofesi

  • *****
  • Wiadomości: 2049
  • Miejsce pobytu:
    Toruń/Poland
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #7 dnia: 2014.03.03, 13:28:30 »
Zawsze optymalizuje swoje procedury po ich napisaniu - wtedy kiedy już działają poprawnie. Optymalizacja podczas pisania to zwykła strata czasu.

I wszystko fajnie, ale są pewne klasy problemów (w wypadku ZXów to głównie zabawy borderemi multicolor), gdzie nie da się pisać nieoptymalizowanego kodu, bo po prostu nie będzie działał ;)

Phonex

  • *****
  • Wiadomości: 1261
  • Miejsce pobytu:
    Warszawa
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #8 dnia: 2014.03.03, 14:28:02 »
To ja tylko powiem, że kasowanie pamięci LDIRem jest fajne pod warunkiem, że nam się nie spieszy ;)

Jak się nie spieszy to można wyczyścić ekran procedurą z ROM: CALL 3435 ;)

sect0r

  • *****
  • Wiadomości: 698
  • Miejsce pobytu:
    Oltedal/NO
  • speccyholic
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #9 dnia: 2014.03.03, 16:55:44 »
Panowie - przypominam, że to temat dla początkujących i "nie od razu Kraków zbudowano".
Także proszę mi nie straszyć gości jakimiś kopiowaniami przez stosy, bufory, tablice.
No chyba, że to będzie poparte przykładami i ładnie opisane, tak aby każdy początkujący zrozumiał o co chodzi.
Jak na razie dla mnie stos służy do przechowywania danych, a o innych jego zastosowaniach chętnie poczytam.
Szarak # DivIDE+ # MasakratorFM DeluXe by Zaxon

ZbyniuR

  • *****
  • Wiadomości: 3333
  • Miejsce pobytu:
    Carlisle w UK
  • CPC AGA PSX
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #10 dnia: 2014.03.03, 17:28:17 »
W nazwie wątku jest "proste dla początkujących" tak? 
Noo to proszę nie wyjeżdżać z pętelkami i efektami, Dżizus please...
Bo mi już i tak czacha dymi od tych przykładów. :D       

I brawo dla Rafała za głos rozsądku. :)

   A tak na marginesie to zmagam się z podobnym problemem na CPC i jeśli jest ktoś chętny pomóc to wyjaśnię na PW. Potrzebny mi spec od Z80 i nie musi się znać na CPC. :)
- Jeśli masz w domu światło i wodę, tzn. że masz światłowód. ;)

pear

  • *****
  • Wiadomości: 5511
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #11 dnia: 2014.03.03, 17:35:20 »
Można wykorzystać wskaźnik stosu SP do adresowania pamięci.
Na przykład przy czyszczeniu pamięci obrazu ustawiamy SP na koniec pamięci obrazu. Na koniec, ponieważ stos "rośnie" w dół, czyli każde odłożenie rejestrów na stos zmniejsza wskaźnik stosu o 2 bajty.
W BC ładujemy 0 (dowolną techniką ;) ). A w pętli czyszczącej mamy tylko jeden rozkaz PUSH BC, który zajmuje 1 bajt i wykonuje się w 11 taktach.
Ta sama operacja wykonana przy użyciu, np:
LD (HL),BC
DEC HL
DEC HL
gdzie w HL mamy na początku ten sam adres wskazujący na koniec pamięci obrazu, zajmie 5 bajtów i wykona się w 18 taktach procesora.

Ot cała sztuczka :)
ZX/Enterprise/CPC/Robotron/C128D

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #12 dnia: 2014.03.03, 19:01:34 »
pear, nie wprowadzaj ludzi w błąd z tym odpowiednikiem PUSH BC - bezpośrednio do (HL) nie da się przesłać 16bitowej danej, a jedynie 8bit.
mniej więcej tak:
ld hl,adres
xor a
ld (hl),a
inc hl
ld (hl),a
inc hl

A to powyżej dopiero można rozpętlić wykorzystując 'inc l' zamiast inc hl , troszcząc się o odpowiednią obsługę rejestru H.

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #13 dnia: 2014.03.03, 19:26:47 »
Cytuj
- bezpośrednio do (HL) nie da się przesłać 16bitowej danej, a jedynie 8bit

Potwierdzam, nie da się.

Zetknąłem się natomiast z czymś takim, że niektórzy twórcy kompilatorów (np. Sjasm) zrobili rzecz moim zdaniem bardzo głupią, mianowicie wprowadzili różne pseudoinstrukcje niby skracające pisanie kodu

Czyli np. zamiast pisać

PUSH HL
PUSH DE
PUSH BC


to mamy zapis

PUSH HL,DE,BC

To akurat nie jest żaden problem ale są też tam takie kwiatki jak właśnie jakieś LD (HL),BC
które jest zamieniane na dajmy na to:

LD (HL),C
INC HL
LD (HL),B
DEC HL


Powie ktoś - "nie chcesz, nie używaj". Jednak nikt nie zna wszystkich instrukcji na pamięć i może się nam wydawać że użyliśmy legalnej instrukcji a tak naprawdę wstawiliśmy makro, które dłużej chodzi, zajmuje nie wiadomo ile bajtów, zmienia nie wiadomo jak flagi...

Osobiście jestem dość zawzięty na te pseudoinstrukcje bo kiedyś straciłem przez nie prawie 2 godziny życia :) Zbyt długo zasiedziałem się nad kodem ignorując zmęczenie no i oczywiście był błąd - zamiast SUB B napisałem SUB A,B (w notacji jest niekonsekwencja - piszemy ADD A,B ale SUB B)

Kompilator mi to przyjął ale potraktował jako pseudoinstrukcję i zamienił na 2 instrukcje:
SUB A
SUB B


Co ja się naszukałem dlaczego mi kod nie działa.
Dlatego piszmy porządnie, żadnych skrótów myślowych z nieistniejącymi instrukcjami :)






pear

  • *****
  • Wiadomości: 5511
  • Miejsce pobytu:
    Będzin
  • Z80 only
Odp: Proste i przyjemne procedurki asemblerowe dla początkujących
« Odpowiedź #14 dnia: 2014.03.03, 19:29:41 »
Oj, tam :) Dawno nie korzystałem z assemblera Z80  :P
Chodziło o zasadę wykorzystania stosu do adresowania pamięci.
A to, że się nie da zapisać wprost wartości 16-bitowej do pamięci innym sposobem tylko potwierdza wyższość korzystania ze stosu nad kopiowaniem 8-bitowym.
Oczywiście przy pętlach, a nie pojedynczym przesłaniu (pojedynczo nie ma to zupełnie sensu).
ZX/Enterprise/CPC/Robotron/C128D