ZX Spectrum > PROGRAMOWANIE

Skopiowanie większej ilości danych do RAM

<< < (13/14) > >>

siudym:
Po przerwie znowu wracam do Z80, znowu do prób zastępowania indexowania typowego dla 6502 takim powiedzmy "pseudo-indexowaniem" w Z80.
Mam przykładowy kod, ktory zwiększa dynamicznie prędkość animacji przeciwników używając dwie zmienne na jednego przeciwnika.
Jedna to sam licznik animacji, a drugi to ustawienie prędkości tego licznika (SetTimer).
Chodzi o to, aby nie robić wielu takich osobnych funkcji, ale użyć jednej, która będzie zmieniała kolejność bajtu wg. indexu
(uzywam do tego celu osobnej zmiennej "indexregister1").


Napisalem jedna, indexowana funkcje dla wszystkich przeciwnikow (nie testowane, bo robie to na "brudno"),
kod jest oczywiscie mniejszy rozmiarowo niz wiele osobnych, ale tez zjada wiecej cykli cpu bo i tak musi byc wywolany wiele razy,
ale tu chodzi o sam fakt i przyklad takiego rozwiazania, wiec bede prosil o analize i jakies uwagi :) Bo zapewne da sie to samo zrobic niebo lepiej... ;)




--- Cytuj ---IndexRegister1         DB      ; zmienne w ram

ENEMY00_Animation_Timer      DB
ENEMY01_Animation_Timer      DB
ENEMY02_Animation_Timer      DB
ENEMY03_Animation_Timer      DB
(...)
ENEMY31_Animation_Timer      DB
(...)

ENEMY00_Animation_SetTimer   DB
ENEMY01_Animation_SetTimer   DB
ENEMY02_Animation_SetTimer   DB
ENEMY03_Animation_SetTimer   DB
(...)
ENEMY31_Animation_SetTimer   DB
(...)

--- Koniec cytatu ---

Przykladowy, prosty kod sterujacy licznikiem animacji, osobny dla kazdego przeciwnika:


--- Cytuj ---
   LD A,(ENEMY00_Animation_Timer)
   LD B,A
   LD A,(ENEMY00_Animation_SetTimer)
   ADD A,B
   LD (ENEMY00_Animation_Timer),A

...

   LD A,(ENEMY01_Animation_Timer)
   LD B,A
   LD A,(ENEMY01_Animation_SetTimer)
   ADD A,B
   LD (ENEMY01_Animation_Timer),A

(...)

--- Koniec cytatu ---


Teraz proba indexowania tych zmiennych o index zawarty w zmiennej IndexRegister1:


--- Cytuj ---
TimerAnimacji:

   LD HL,ENEMY00_Animation_Timer
   LD A,(IndexRegister1)
   LD E,A
   ADD HL,DE
   LD A,(HL)

   LD B,A               ; Teraz w B mam adres ENEMY00_Animation_Timer zwiekszony o IndexRegister1

   LD HL,ENEMY00_Animation_SetTimer   ; Podobnie jak wyzej ale indexuje zmienna SetTimer
   LD A,(IndexRegister1)
   LD E,A
   ADD HL,DE
   LD A,(HL)

   LD C,A               ; Teraz w C mam adres ENEMY00_Animation_SetTimer zwiekszony o IndexRegister1

   ADD C,B               ; Dodaje SetTimer do Timer

   LD HL,ENEMY00_Animation_Timer      ;EDIT: tu moge na poczatku zachowac wynik HL do np. IX/IY i teraz nie wyliczac znowu tylko przeniesc do HL...
   LD A,(IndexRegister1)
   LD E,A
   ADD HL,DE            ; Teraz w B mam 'znowu" bajt ENEMY00_Animation_Timer zwiekszony o IndexRegister1
   LD A,C               ; Wynik dodawania mialem zachowany w C wiec musze go przeniesc do A aby zapisac pod adres wskazany w HL
   LD (HL),A            ; Zapisz wynik pod adres bajtu ENEMY00_Animation_Timer zwiekszonego o adres indexu czyli odpowiedniego Enemy..

   RET


--- Koniec cytatu ---

Teraz wystarczy ustawic index o numer danego przeciwnika i wywolac:


--- Cytuj ---ld d,0   ; oczywiscie d musze miec wyzerowane

   LD A,31               ; wywolaj kod licznika dla ENEMY31
   LD (IndexRegister1),A
   CALL TimerAnimacji

--- Koniec cytatu ---

matofesi:
Tak na szybko... nie ma opcode'u "add c,b" ;) Dodawać można tylko do akumulatora.

Twój przykład zrobiłbym w taki sposób (bez nadmiernej optymalizacji):

--- Kod: ---TimerAnimacji
        ld hl,ENEMY0_Animation_Timer ; adres pierwszego bloku
        add hl,de ; "indeksowanie"
        push hl ; zapamiętujemy na później
        ld b,(hl) ; pobieramy dane
        ld hl,ENEMY00_AnimationSetTimer ; drugi blok
        add hl,de ; "indeksowanie"
        ld a,(hl) ; pobieramy dane
        add a,b ; dodajemy
        pop hl ; odtwarzamy pierwszy adres po "indeksowaniu"
        ld (hl),a ; zapisujemy dane
        ret

--- Koniec kodu ---

I wywołanie:

--- Kod: ---        ld de,31 ; indeks ładujemy do de (albo raz 0 do d a potem indeks do e)
        call TimerAnimacji

--- Koniec kodu ---

siudym:
Racja, mozna wykonywac jedynie ADD A,r...
Teraz widze bez sensu dodawalem IndexRegister 3x do DE skoro jest zawsze taki sam.
Co do uzycia zmiennej zamiast od razu przed CALL ustawic wartosc indexu do DE, to chodzi o to, ze mam do przepisania kod z 6502, w ktorym uzywalem np. 3 rozne indexy (np. zwiekszany o jeden, kolejny co cztery bajty a inny co 16) dlatego nie uzylem od razu DE przed CALL do wspolnej funkcji.

Wracajac do pomyslu, aby zachowac zawartosc HL w rejestracy IX/IY to widze, ze nie da sie wykonac LD IX,HL, ale mozna by zrobic backup uzywajac stosu aby w pozniejszym kodzie uzyc, np.:

   PUSH HL        ; przenies HL do IX za pomoca stosu
   POP IX

(...)

   PUSH IX           ; odczytaj zachowany HL "w IX" znowu do HL za pomoca stosu..
   POP HL

Tez powinno byc ok?

matofesi:
Tak - PUSH/POP będzie OK poza faktem, że przerzuca dane przez stos.
Poza tym wszystkie rozkazy i IX/IY są dłuższe o bajt prefiksu (oraz ewentualny indeks) oraz wolniejsze o 4-12 taktów zależnie od rozkazu więc jeśli koniecznie nie jest ci potrzebne to lepiej jest jednak nie używać rejestrów indeksowych.

trojacek:
Dokładnie.
Czasami bardziej się opłaca korzystać z drugiego zestawu rejestrów (EXX).

Nawigacja

[0] Indeks wiadomości

[#] Następna strona

[*] Poprzednia strona

Idź do wersji pełnej