ZX Spectrum > PROGRAMOWANIE
Skopiowanie większej ilości danych do RAM
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
[#] Następna strona
Idź do wersji pełnej