Tutorial 2
W tym tutorialu nauczysz się, jak alokować tablicę trójelementową w asemblerze 6502. Dlaczego akurat tak proste zadanie? W językach wysokiego poziomu kod alokacji tablicy mieści się w deklaracji tablicy zajmującej jedną linijkę kodu. W asemblerach jest to bardziej złożona procedura, o czym się zaraz przekonasz.
1. Jeśli wcześniej korzystałeś z 6502 i zatrzymałeś program lub użyłeś rozkazu BRK, to licznik programu miał losową wartość. Miejsce, od którego jest wstawiany jest kod programu rozpoczyna się od licznika programu. Jeśli chcesz, żeby asembler zapisał przetłumaczony kod maszynowy na adresie $0000, to wpisz w polu "Licznik programu" wartość wskazaną na obrazku.
2. Wstaw do pola kodu kod pokazany na obrazku, naciśnij kolejno przyciski: "Załaduj" i dwa razy "Krok". Dobrze też przełączyć na kartę śledzenie.
Asembler 6502 nie ma instrukcji alokujących tablice, dlatego ta operacja musi zostać zrealizowana w sześciu linijkach kodu.
3. Do rejestru X została wczytana wartość $00. Rozkaz LDX #$00 oznacza więc "przypisz argument do rejestru X".
Naciskaj przycisk "Krok", dopóki rozkaz "loop: TXA" nie zostanie wyróżniony na ciemnoczerwono w podglądzie śledzenia kodu, a numer cyklu nie będzie drugi.
4. Akumulator przyjął wartość taką samą, jak rejestr X. To oznacza, że rozkaz TXA wykonuje rozkaz "skopiuj wartość z rejestru X do akumulatora". Ponieważ zasób docelowy jest z góry określony, ten rozkaz nie miał argumentu. Znaczenie słowa "loop" wyjaśnimy później.
Naciskaj przycisk "Krok", dopóki rozkaz: "STA $50,X" nie zostanie wyróżniony na ciemnoczerwono, a numer cyklu nie będzie czwarty.
5. Wartość komórki $0050 przyjęła wartość $00. Zapis "$50, X" oznacza: "Dodaj do adresu $0050 wartość z rejestru X, a następnie zapisz wartość pod adresem wyjściowym". Rejestr X miał wartość $00, dlatego adresem wyjściowym, lub efektywnym jest $0050.
Naciskaj przycisk "Krok", dopóki rozkaz "INX" nie zostanie zaznaczony na karcie "śledzenie", a numer cyklu nie będzie drugi.
6. Rejestr X w tym cyklu zwiększył się o jeden. Rozkaz INX wykonuje bardzo prostą operację - inkrementację rejestru X.
Naciskaj przycisk "Krok", dopóki rozkaz "CPX #$03" nie zostanie zaznaczony na ciemnoczerwono, a numer cyklu nie będzie drugi.
7. Rozkaz CPX zmienił spośród zasobów dostępnych dla programisty jedynie trzy flagi: N, Z i C. Przyjęły one odpowiednio wartości: 1, 0 i 0. To oznacza, że liczba w rejestrze X była mniejsza, niż argument.
Naciskaj przycisk "Krok", dopóki rozkaz "BNE loop" nie zostanie wyróżniony na ciemnoczerwono, a numer cyklu nie będzie drugi.
8. Rozkaz CPX nie odpowiada za skok do innej części programu. Obliczyła jedynie warunek. Skok powinna zrobić instrukcja "BNE loop". W tym cyklu został pobrany argument $F8, który tym razem pełni rolę przesunięcia, gdyż instrukcja BNE obsługuje wyłącznie adresowanie względne.
Naciśnij przycisk "Krok".
9. Instrukcja BNE loop nadal się wykonuje. Licznik programu zmienił wartość z $000A na $0002. Dlaczego? Dlatego, że argument $F8 był w reprezentacji uzupełnienia do dwóch (U2), czyli ma wartość -8. A $000A - 8 = $0002. W naszym kodzie ten sam rozkaz miał etykietę "loop" zamiast liczby. W kodzie etykietą loop została oznaczona instrukcja "TXA", której opkod znajduje się w komórce $0002. Asembler policzył wartość przesunięcia na podstawie nazwy etykiety jako argumentu i instrukcji oznaczonej taką etykietą. Dlatego po rozgałęzieniu powinna się wykonać instrukcja TXA.
Naciśnij przycisk "Krok".
10. Zgodnie z oznaczeniem etykietą, po rozgałęzieniu program znalazł się na instrukcji "loop: TXA". BNE wykonało rozgałęzienie, ponieważ ostatnio porównane liczby nie były równe.
Naciskaj przycisk "Krok", dopóki rozkaz "STA $50,X" nie został wyróżniony na ciemnoczerwono, a numer cyklu nie będzie czwarty.
11. Tym razem zmieniła się komórka $0051, ponieważ rejestr X ma wartość jeden, a $0050 + 1 = $0051.
Naciskaj przycisk "Krok", dopóki w podglądzie "śledzenie" nie zostanie zaznaczony rozkaz "CPX #$03", a numer cyklu nie będzie drugi. Rejestr X ma mieć wartość $03.
12. Tym razem wartości flag N, Z i C po wykonaniu rozkazu CPX są inne. Mają odpowiednio wartość 0, 1 i 1. Stało się tak dlatego, że rejestr X i argument są już równe. Ciekawe, jak się zachowa program po wykonaniu instrukcji BNE...
Naciskaj przycisk "Krok", dopóki na ciemnoczerwono nie wyróżniono rozkazu "BNE loop", a numer cyklu nie będzie trzeci.
13. Co się dzieje? Dlaczego mamy instrukcję podpisaną w szarym polu jako "[NIEZNANY OPKOD]? Dlatego, że warunek rozgałęzienia się nie spełnił i nie wykonał się trzeci cykl, w którym jest zmieniany licznik programu. A dlaczego akurat nieznany rozkaz? Dlatego, że w pamięci komórka po BNE loop zawiera wartość $73, a do tej liczby nie przyporządkowano żadnej operacji. Rzeczywisty procesor 6502 wykonałby bliżej nieokreślone działania, ale nie są one udokumentowane, dlatego w Wizjerze 6502 program będzie się wykonywać w nieskończoność, nie wprowadzając jakichkolwiek zmian i jedynym sposobem na przerwanie programu jest wciśnięcie przycisku "Reset".
Uwaga! U ciebie może zamiast nieznanego opkodu trafić się ten znany, ponieważ wartości w pamięci są generowane losowo.
Zadania domowe
- Powtórz tutoriale bez pomijania cykli i obserwuj części składowe procesora.
- Wypróbuj każdy rozkaz asemblera 6502.
- Napisz program wykonujący mnożenie.
- Napisz program obliczający sumę ciągu arytmetycznego.