Autor Wątek: Problem ze stosem  (Przeczytany 10970 razy)

Abrimaal

  • *****
  • Wiadomości: 965
  • Miejsce pobytu:
    Lemmingrad
  • Zamulator
    • Games for ULA plus
Problem ze stosem
« dnia: 2015.06.09, 03:49:49 »
Zimą obiecałem znajomemu dołożyć muzykę do pisanej przez niego gry w AGD. Jest czerwiec.
W grze jest kilka utworów na beeper, tytułowy jest zapętlony. Pozostałe są przerywane na końcu skokiem do procedury odtwarzania perkusji.
Fikcyjny DRUM06 umieszczony jako ostatni dźwięk wykonuje JP do wyjścia z muzyki, udawając wciśnięcie dowolnego klawisza.
W pozostałych bębnach procedurę kończy RET, wracając z przerwania do grania muzyki.

Ten DRUM06 powoduje problem na stosie, co w grze objawia się lataniem spritów po całym ekranie, zamiast po wyznaczonej planszy. Jak się dowiedziałem, rejestr IX w AGD odpowiada za pozycjonowanie spritów.

Dodawałem POPy przed JP, żeby wyrównać stos i nic z tego. Przy assemblacji gry bez muzyki, sprity chodzą dobrze.
Dołączam player muzyki, niech ktoś się zlituje.

Dodam jeszcze, że tytułowy zapętlony utwór nie używa DRUM06 i wraca prawidłowo, czyli w tym tkwi problem.
Dla ścisłości dołączam też DR_SAMPLER, do którego player skacze, ale w nim jest wszystko w porządku.

« Ostatnia zmiana: 2015.06.09, 04:02:04 wysłana przez Abrimaal »
AY Music, ULA plus.

Tygrys

  • Administrator
  • *****
  • Wiadomości: 4540
  • Miejsce pobytu:
    Warszawa
  • mistrz ceremonii
Odp: Problem ze stosem
« Odpowiedź #1 dnia: 2015.06.09, 09:18:16 »
Jeżeli musisz zachowac IX to robisz:

   PUSH IX
   CALL procedura
   POP IX

Nie używasz JP bo on nie odkłada na stosie adresu powrotu.

Dr Piotr

  • ***
  • Wiadomości: 196
Odp: Problem ze stosem
« Odpowiedź #2 dnia: 2015.06.09, 09:47:05 »
Czy utwor bez drum6 nie powoduje problemow w grze? Ktorej funkcji uzywasz do odgrywania -  start czy play_music?
Jesli podejrzewasz ze to problem z IX, to zaczalbym do usuniecia go z kodu. Jest uzywany tylko w  dr_sample.asm. Sprobuj cos takiego:
; adres sampla w hl, dlugosc w de
DR_SAMPLER:
   LD    b, 8   
   LD    c, (hl)      
DR_L_FE22:
   rr    c
   ld   a, 16
   jp    c, dr_play
   xor    a
dr_play:
   out    (254), a      
   ld    a,20
DR_L_FE2E:
   dec    a
   jp    nz, DR_L_FE2E      
   djnz    DR_L_FE22      
   inc    hl         
   dec    de
   ld    a,e         
   or    d      
   jp    nz, DR_SAMPLER      
   ret         
« Ostatnia zmiana: 2015.06.09, 10:29:51 wysłana przez Dr Piotr »

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Problem ze stosem
« Odpowiedź #3 dnia: 2015.06.09, 11:30:42 »
A ile dodawałeś tych instrukcji POP dla wyrównania stosu?

Sugestia

- uruchom program w emulatorze
- wejdź w debugger
- ustaw breakpoint  przed wejściem w procedurę i zobacz ile wynosi SP
- zobaczy ile wynosi SP po wyjściu z procedury, powinno być tyle samo

Mogą być te inne przyczyny - zniszczenie wartości jakiegoś rejestru (też do sprawdzenia w debuggerze), przepełnienie obszaru stosu itp.

Abrimaal

  • *****
  • Wiadomości: 965
  • Miejsce pobytu:
    Lemmingrad
  • Zamulator
    • Games for ULA plus
Odp: Problem ze stosem
« Odpowiedź #4 dnia: 2015.06.09, 21:46:36 »
Wypróbuję zalecane poprawki. Niepotrzebne wydaje się też na początku odłożenie na stos HL' i po zakończeniu podniesienie. Gra i tak nie wraca do Basic.

Teoretycznie wszystko powinno być ok, muszę sprawdzić w emulatorze, tak jak Rafal radzi. Dodawałem eksperymentalnie 0, 1 lub 2 razy POP AF.
Przed wywołaniem muzyki kładę wszystkie rejestry na stos (bez primów), tak że tutaj jest prawidłowo.
Generalnie skok do procedury muzyki wygląda tak
MUSIC3: XOR A
LD (KEY_RES),A      ;music stops on keypress 0=no 1=yes
LD HL, MUSICDAT3 ;nr utworu song data
LD (CHANGETUNE),HL
JP PUSHPOP
następnie wszystkie rejestry na stos i wywołanie muzyki
PUSHPOP:
PUSH IY
PUSH IX
PUSH HL
PUSH DE
PUSH BC
PUSH AF
MUSICNO: CALL START    ;music routine
POP AF
POP BC
POP DE
POP HL
POP IX
POP IY
RET     ; powrót do gry

AY Music, ULA plus.

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Problem ze stosem
« Odpowiedź #5 dnia: 2015.06.09, 22:38:33 »
Widzę że nie chronisz rejestrów alternatywnych mimo że w kodzie muzyki jest kilka razy instrukcja EXX więc ich używasz.

Sprawdź więc czy to nie jest przyczyną problemu i  czy po wyjściu z procedury masz włączony właściwy zestaw rejestrów.

Abrimaal

  • *****
  • Wiadomości: 965
  • Miejsce pobytu:
    Lemmingrad
  • Zamulator
    • Games for ULA plus
Odp: Problem ze stosem
« Odpowiedź #6 dnia: 2015.06.09, 23:02:19 »
Przyznam się, że nigdy tego nie robiłem, żeby nie pomieszać kolejności. Czy jest ona taka?
   
PUSH IY, IX, HL, DE, BC, AF
EXX
EX AF,AF'
PUSH IY, IX, HL, DE, BC, AF
CALL START
POP AF, BC, DE, HL, IX, IY
EX AF,AF'
EXX
POP AF, BC, DE, HL, IX, IY
AY Music, ULA plus.

RafalM

  • *****
  • Wiadomości: 1133
  • Miejsce pobytu:
    Sulejówek
Odp: Problem ze stosem
« Odpowiedź #7 dnia: 2015.06.09, 23:47:06 »
Nie ma alternatywnych IX i IY. Nie trzeba zapisywać 2 razy
I tak jak zrobiłeś to wywołasz procedurę z drugą parą rejestrów, nie z pierwszą  Nie wiem czy to ma znaczenie


Ja robię tak:
PUSH HL
PUSH DE
PUSH BC
EXX
PUSH HL
PUSH DE
PUSH BC
EXX
PUSH IX
PUSH IY
PUSH AF
EX AF,AF'
PUSH AF
EX AF,AF'
CALL PROG
EX AF,AF'
POP AF
EX AF,AF'
POP AF
POP IY
POP IX
EXX
POP BC
POP DE
POP HL
EXX
POP BC
POP DE
POP HL
   


matofesi

  • *****
  • Wiadomości: 2049
  • Miejsce pobytu:
    Toruń/Poland
Odp: Problem ze stosem
« Odpowiedź #8 dnia: 2015.06.10, 09:15:05 »
No dobra... Tak sobie oglądam ten player i mam jedno pytanie... Jak dokładnie wywołujesz ten kod? Bo tak jak na to patrzę to wygląda to tak, że wchodząc do START player zrzuca na stos HL' woła AY_SETUP a potem wskakuje do PLAY_MUSIC, gdzie ustawia przerwania, zapamiętuje SP w zmiennej SAVED_SP i jedzie dalej z odtwarzaniem.

DRUM06 skacze do ISR_KEY_PRESSED a tam odtwarzany jest stos na wartość zapamiętaną w PLAY_MUSIC a następnie robione jest EI/RETI co powinno wrócić do MUS_EXIT niezależnie od tego, co nadmiarowego leży na stosie. Jeśli więc coś ci się po drodze kaszani  to zdecydowanie ma to związek z używanymi w playerze rejestrami i poprawne ich zapamiętanie i odtworzenie po powrocie powinno rozwiązać sprawę.

Sam player używa kompletu rejestrów podstawowych IX oraz BC', którego nie zapisuje na stosie w procedurze obsługi przerwania tylko używa jako jakiegoś licznika. Tyle, że startując ze START kod tak na prawdę używa rejestrów primowanych (bez AF'), IX i BC.  No i oczywiście dochodzi to, czego używa DR_SAMPLER, do którego nie zaglądałem. ;) Najbezpieczniej więc przed wywołaniem START zrzucić a potem odtworzyć wszystko tak jak pokazał RafalM :)

Zauważyłem jeszcze jeden drobiazg w samym kodzie wywołującym kolejne DRUMxx w okolicach PERC_PATT. Kod ten najpierw do A ładuje numer DRUM do wywołania a potem w JUMP_PERC_ADDR pobiera adres robiąc to w "niepełny" sposób:
JUMP_PERC_ADDR:
               POP   HL
               ADD   A,A
               ADD   A,L
               LD    L,A
               LD    A,(HL)
               INC   HL
               LD    H,(HL)
               LD    L,A
               JP    (HL)

Sekwencja ADD A,A/ADD A,L/LD L,A może w ekstremalnym wypadku puścić kod "w kartofle" - stanie się tak wtedy gdy kod się zassembluje pod taki adres, że tablica kolejnych DEFW trafi na przejście stron pamięci. Wtedy przeliczenie A*2+L zmieni młodszy bajt adresu nie ruszając starszego i w efekcie pobierze adres skoku z adresu o 256 bajtów wcześniejszego niż powinno, co oczywiście prawie na pewno zakończy się crashem. Żeby temu zapobiec trzeba albo upewnić się, że assemblujemy kod we właściwe miejsce albo poprawić JUMP_PERC_ADDR dodając na przykład coś takiego:
...
               POP   HL
               ADD   A,A
               ADD   A,L
               LD    L,A

               adc a,h
               sub l
               ld h,a

               LD    A,(HL)
...

Abrimaal

  • *****
  • Wiadomości: 965
  • Miejsce pobytu:
    Lemmingrad
  • Zamulator
    • Games for ULA plus
Odp: Problem ze stosem
« Odpowiedź #9 dnia: 2015.06.11, 02:49:45 »
Zamieniłem wszystkie PUSH i POP przed wywołaniem muzyki na sekwencję, którą podał Rafal.
Adres SP jest ten sam przy wejściu do playera (DI) i przy wyjściu (RET). Zmienia się w trakcie grania muzyki, ale przy wyjściu ma ten sam adres.

DR_SAMPLER, czyli Drum Sampler jest skopiowany z istniejącego playera Voice Manipulator 2,
używa rejestrów IX= adres sampla, DE= długość sampla, B= licznik bitów dla RR C , C= pobrany bajt sampla, A=wartość OUT dla beepera (0 lub 16), L= tempo odtwarzania. Tylko H jest wolny.
To chyba nie ma znaczenia, kiedy sampler uruchamiany jest wielokrotnie w trakcie muzyki i przed jego wywołaniem też jest PUSH a na końcu POP wszystkich rejestrów wg podanej receptury.

Mat, nie rozumiem co dokładnie miałbym zastąpić czym w JUMP_PERC_ADDR - to chyba jakiś szczególny przypadek, o którym piszesz. Player Special FX używany jest w wielu grach, dokładnie tak jak wygenerował go tracker Beepola. Na końcu oryginalnego kodu jest JP (HL) a w Twoim kodzie nie ma.

Teraz odnośnie optymalizacji kodu. Czy da się zrobić w jednym miejscu

PUSH all = wszystkie rejestry wraz z primowanymi
;tutaj dowolne instrukcje
POP all
RET

Powtarzanie kilkanaście razy tej sekwencji przed wywołaniem muzyki i efektów dźwiękowych bardzo wydłuża kod. Myślałem o JP (HL), ale to też wymaga załadowania wartości do HL przed położeniem rejestrów na stos.

Jeśli już wszystko ze stosem jest prawidłowo, a sprity dalej szaleją, to musi być inny problem w playerze. Bez muzyki sprity chodzą dobrze.
Pomyślałem o RAM, czy coś nie zachodzi jedno na drugie, ale nie. Od 24500 do około 29100 są dane sampli i muzyki, dalej wolne miejsce, od około 29900 cała gra, bezpośrednio za nią około 59800 procedury wywołujące poszczególne utwory i efekty, po tym player muzyki, sampler. Później wolne od około 61500 do 65024, czyli tabeli i obsługi przerwania. Nie wygląda żeby coś kolidowało.
« Ostatnia zmiana: 2015.06.11, 02:59:13 wysłana przez Abrimaal »
AY Music, ULA plus.

matofesi

  • *****
  • Wiadomości: 2049
  • Miejsce pobytu:
    Toruń/Poland
Odp: Problem ze stosem
« Odpowiedź #10 dnia: 2015.06.11, 09:07:21 »
Mat, nie rozumiem co dokładnie miałbym zastąpić czym w JUMP_PERC_ADDR - to chyba jakiś szczególny przypadek, o którym piszesz. Player Special FX używany jest w wielu grach, dokładnie tak jak wygenerował go tracker Beepola. Na końcu oryginalnego kodu jest JP (HL) a w Twoim kodzie nie ma.

Ale widziałeś "..." na początku i końcu mojego kodu? Dodałem trzy linijki (te napisane małymi literami), które należałoby wstawić w odpowiednie miejsce istniejącego kodu i przyciąłem fragment, żeby drugi raz nie wklejać całego kawałka. Uściślając - kod powinien wyglądać tak:
JUMP_PERC_ADDR:
               POP   HL
               ADD   A,A
               ADD   A,L
               LD    L,A

               adc a,h
               sub l
               ld h,a

               LD    A,(HL)
               INC   HL
               LD    H,(HL)
               LD    L,A
               JP    (HL)

Cytuj
Teraz odnośnie optymalizacji kodu. Czy da się zrobić w jednym miejscu

PUSH all = wszystkie rejestry wraz z primowanymi
;tutaj dowolne instrukcje
POP all
RET

Powtarzanie kilkanaście razy tej sekwencji przed wywołaniem muzyki i efektów dźwiękowych bardzo wydłuża kod. Myślałem o JP (HL), ale to też wymaga załadowania wartości do HL przed położeniem rejestrów na stos.

Mam wrażenie, że się nie dogadamy jeśli będziemy dyskutować tylko o tym kawałku kodu playera... Jeśli nie pokażesz całego kodu, który uruchamiasz łącznie z danymi itp. to żadna analiza samego playera nie pozwoli na wyciągnięcie innych wniosków ponad te, które już zostały wyciągnięte.

Cytuj
Jeśli już wszystko ze stosem jest prawidłowo, a sprity dalej szaleją, to musi być inny problem w playerze. Bez muzyki sprity chodzą dobrze.

Problem jest prawdopodobnie w tym, że robisz coś nie tak jak należy to zrobić. Prawdopodobnie źle robisz integrację i coś ci miesza rejestry tam, gdzie się tego nie spodziewasz. Jeden przykład już podałem - jeśli po odpaleniu playera zostawiasz go grającego na przerwaniach i wracasz gdzieś do kodu gry to całość może ci się kaszanić choćby dlatego, że player używa BC' jako licznika nie zachowując go pomiędzy kolejnymi wywołaniami. Ale to absolutnie nie musi być to - póki nie będzie widać co dokładnie robisz w swoim kodzie i jak masz to wszystko rozmieszczone to możemy sobie tylko gdybać.

Abrimaal

  • *****
  • Wiadomości: 965
  • Miejsce pobytu:
    Lemmingrad
  • Zamulator
    • Games for ULA plus
Odp: Problem ze stosem
« Odpowiedź #11 dnia: 2015.06.11, 21:06:06 »
Przerwania, tu też może djabeł siedzieć. Oryginalna perkusja to takie tuk-tuk na przerwaniach. W ich miejsce dałem samplowane bębny, które z pewnością trwają dłużej niż jedno przerwanie.

Podmienilem kod JUMP_PERC_ADDR na ten co podałeś.

Zrobię eksperyment z oryginalną obsługą perkusji, możliwe że w tym tkwi problem.

Oryginalny kod perkusji wygląda tak. Dane sampli pobierane są z ROM.

DRUM01:        LD    E,$0A
               LD    A,BORDER_CLR
               LD    HL,$0100
DRUM01NOISE:   XOR   $18
               OUT   ($FE),A
               LD    B,(HL)
DRUM01LOOP:    DJNZ  DRUM01LOOP
               INC   HL
               DEC   E
               JR    NZ,DRUM01NOISE
               RET


lub

DRUM02:        LD    HL,$005A
DRUM02LOOP:    LD    A,(HL)
               OR    A
               RET   Z
               AND   $18
               OR    BORDER_CLR
               OUT   ($FE),A
               INC   HL
               JR    DRUM02LOOP

W zmienionym kodzie z samplowaną perkusją wymuszone jest granie całego sampla i wtedy dopiero powrót.
DRUM01:       


PUSH HL
PUSH DE
PUSH BC
EXX
PUSH HL
PUSH DE
PUSH BC
EXX
PUSH IX
PUSH IY
PUSH AF
EX AF,AF'
PUSH AF
EX AF,AF'
     LD HL, AY_DATA1 ;bass  D 1
CALL AY_SETUP ;ustawienie rejestrów AY - stały dźwięk jako dodatkowy bas

LD IX, KIK_SMP ;adres sampla w RAM
LD DE, 16 ;długość w bajtach
CALL DR_SAMPLER

EX AF,AF'
POP AF
EX AF,AF'
POP AF
POP IY
POP IX
EXX
POP BC
POP DE
POP HL
EXX
POP BC
POP DE
POP HL
RET

Ustawienie AY, z tabeli, na wejściu HL= adres tabeli

AY_SETUP:
LD C,253 ;AY register write
LD D,0
AY_SETUP_LOOP LD B, 255
LD A, D
OUT (C),A
LD B, 191
LD A, (HL)
OUT (C),A
INC HL
INC D
LD A,D
CP 14
JR NZ, AY_SETUP_LOOP
RET     

Poniżej przykładowa tabela dla jednego z 4 używanych dźwięków AY i jednocześnie perkusji. Cały subengine jest work in progress, używa 2 sampli perkusji i 4 ustawień AY + wyciszenie. Tak, że tymczasowo odczytywane i zapisywane są wszystkie rejestry AY, choć wystarczy zmiana dwóch lub trzech. Do posłuchania w załączniku.

AY_DATA1 ; bass triangle D
DEFB 0,0,0,0,0,0 ;tone ABC registers 0-5 values
DEFB 0 ;noise freq
DEFB %111111 ;control register CBA-noise-tone 1=off 0=on

DEFB 0,16,0 ;volume/envelope ABC
DEFB 11,0 ;envelope freq
DEFB %1110 ;envelope form

AY Music, ULA plus.