[Z80] Emulator procesora Z80
[Z80] Emulator procesora Z80
Z80 – chyba najbardziej kultowy procek jakikolwiek
był wymyślony. Był produkowany prawie przez 50 lat,
ten rekord będzie trudno pobić.
Taka długowieczność, to jak nie patrzeć, jest jakimś wyznacznikiem.
Do chwili obecnej na fanów ma całym świecie.
Jednak by sprawnie się nim posługiwać, niezbędne są
pewne narzędzia. Jednym z takich jest prezentowany
emulator procesora, który ma zastąpić wcześniej używany AVSIMZ80
(jest to program DOS’owy i słabo przystaje do obecnych realiów).
Poza tym rosną apetyty na większą funkcjonalność.
Emulator procesora Z80
No więc stworzyłem sobie program do śledzenia wykonania programu dla procka Z80. Jest w dużej mierze podobny do wcześniejszego programu służącego do emulacji procesora i8085 <tutaj>.
Po "odpaleniu" programu mamy:
Moim celem jest stworzenie narzędzia pozwalającego na diagnostykę w szerokim zakresie. Wymaga to określenia dla programu wielu informacji, gdyż program wyłapuje przykładowo zapis do pamięci EPROM, odczyt/zapis z pamięci nieistniejącej (gdyż nie ma obowiązku, by do procka była przypięta pamięć wypełniająca całą przestrzeń adresową). Podobnie są monitorowane użycia portów we/wy. Należy wcześniej określić jakie adresy portów są używane i symulacja wykonania programu dla procka z80 się zatrzyma, jeżeli nie zostaną wyspecyfikowane „legalne” adresy portów. By nie wklepywać tego za każdym razem, jest plik opisujący projekt (symulacji). Oczywiście, wszystkie szczegóły można w dowolnej chwili zmodyfikować.
Po otwarciu projektu jest:
Przykładowy system prockowy składa się z pamięci EPROM (lub innej nieulotnej) lokowanej w przestrzeni od 0000 hex do 7FFF hex oraz pamięć RAM lokowana od 8000 hex do FFFF hex. W sumie obie pamięci wypełniają całą przestrzeń. Dodatkowo występują porty wyjścia/wejścia (jak przykładowo i8255) lokowane na adresach C0..C3 hex. Program prowadzi kontrolę w sensie: dopuszcza zapis tylko do portów wyjściowych lub wejściowo-wyjściowych (jakiekolwiek instrukcje realizujące operacje IN) oraz odczyt dla portów wejściowych oraz wejściowo-wyjściowych (jakiekolwiek operacje realizujące OUT). Również program emulatora wspiera obsługę przerwań. no i oczywiście przerwanie niemaskowalne NMI. Te przerwania (niemaskowalne oraz maskowalne) mogą być nieużywane w systemie (ze stałym sygnałem wymuszonym przez odpowiednie przyłączenie wejścia do VCC), toteż istnieje możliwość, że klikanie na przycisk do zgłaszania przerwania pozostanie bez reakcji.
Aktualny stan programu:
był wymyślony. Był produkowany prawie przez 50 lat,
ten rekord będzie trudno pobić.
Taka długowieczność, to jak nie patrzeć, jest jakimś wyznacznikiem.
Do chwili obecnej na fanów ma całym świecie.
Jednak by sprawnie się nim posługiwać, niezbędne są
pewne narzędzia. Jednym z takich jest prezentowany
emulator procesora, który ma zastąpić wcześniej używany AVSIMZ80
(jest to program DOS’owy i słabo przystaje do obecnych realiów).
Poza tym rosną apetyty na większą funkcjonalność.
Emulator procesora Z80
No więc stworzyłem sobie program do śledzenia wykonania programu dla procka Z80. Jest w dużej mierze podobny do wcześniejszego programu służącego do emulacji procesora i8085 <tutaj>.
Po "odpaleniu" programu mamy:
Moim celem jest stworzenie narzędzia pozwalającego na diagnostykę w szerokim zakresie. Wymaga to określenia dla programu wielu informacji, gdyż program wyłapuje przykładowo zapis do pamięci EPROM, odczyt/zapis z pamięci nieistniejącej (gdyż nie ma obowiązku, by do procka była przypięta pamięć wypełniająca całą przestrzeń adresową). Podobnie są monitorowane użycia portów we/wy. Należy wcześniej określić jakie adresy portów są używane i symulacja wykonania programu dla procka z80 się zatrzyma, jeżeli nie zostaną wyspecyfikowane „legalne” adresy portów. By nie wklepywać tego za każdym razem, jest plik opisujący projekt (symulacji). Oczywiście, wszystkie szczegóły można w dowolnej chwili zmodyfikować.
Po otwarciu projektu jest:
Przykładowy system prockowy składa się z pamięci EPROM (lub innej nieulotnej) lokowanej w przestrzeni od 0000 hex do 7FFF hex oraz pamięć RAM lokowana od 8000 hex do FFFF hex. W sumie obie pamięci wypełniają całą przestrzeń. Dodatkowo występują porty wyjścia/wejścia (jak przykładowo i8255) lokowane na adresach C0..C3 hex. Program prowadzi kontrolę w sensie: dopuszcza zapis tylko do portów wyjściowych lub wejściowo-wyjściowych (jakiekolwiek instrukcje realizujące operacje IN) oraz odczyt dla portów wejściowych oraz wejściowo-wyjściowych (jakiekolwiek operacje realizujące OUT). Również program emulatora wspiera obsługę przerwań. no i oczywiście przerwanie niemaskowalne NMI. Te przerwania (niemaskowalne oraz maskowalne) mogą być nieużywane w systemie (ze stałym sygnałem wymuszonym przez odpowiednie przyłączenie wejścia do VCC), toteż istnieje możliwość, że klikanie na przycisk do zgłaszania przerwania pozostanie bez reakcji.
Aktualny stan programu:
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Zapowiada się super, możesz dołaczyć jakiś przykładowy plik projektu aby można było zobaczyć jak samemu ustawiać parametry symulacji.
Re: [Z80] Emulator procesora Z80
Tworzenie projektu
Po uruchomieniu programu należy kliknąć na „Nowy projekt”.
W reakcji, program poprosi o wszystkie niezbędne informacje dotyczące minimalnej konfiguracji projektu:
Klikając na „Dodaj El” można wprowadzoną konfigurację rozszerzyć o specyfikację przyłączonych do systemu prockowego portów. Po kliknięciu na „Dodaj…” istnieje możliwość wskazania na konkret. Mogą to być:
Po wybraniu wariantu, kliknąć na „Wybierz” oraz dalej należy określić adresacją od
oraz adresację do
W ten sposób można określić pełne środowisko sprzętowe systemu prockowego.
By zmodyfikować lub usunąć należy w okienku „Projekt” klikając na odpowiednią pozycję wskazać element, który jest do usunięcia „Usuń El” lub modyfikacji „Zmień El”. Po wprowadzeniu zmian, aktualny stan można zapisać na dysku po kliknięciu na „Zapis Proj”. Po zmianach opis środowiska może wyglądać następująco:
Przy każdym (późniejszym) uruchomieniu programu, można poprzez „Otwórz Proj” mieć te dane „wklepane”. Istnieje możliwość „upuszczeniu” na formę programu nazwy pliku z rozszerzeniem .mem, jest to równoznaczne z otwarciem pliku projektu.
Ten plik projektu jest plikiem tekstowym i można go sobie pooglądać (i nawet zmodyfikować w windozowym notatniku). Jego syntaktyka jest prosta i łatwo jest skojarzyć co jest co: przykładowo
Klikając na przycisk „Ładuj hex”, program wczyta wskazany w opisie projektu plik, dokona deasemblacji oraz wynik pokaże w okienku „Pamięć (program)”.
Jeżeli w trakcie symulacji zostaną „namierzone” pomyłki, można dokonać zmian w sofcie i skompilować go na nowo. Nie ma konieczności wychodzenia z programu emulatora, każdorazowe kliknięcie na „Ładuj hex” ponownie wczytuje plik kodu z dysku i dokonuje jego deasemblacji.
Po korekcie dostrzeżonych literówek w programie, aktualna wersja:
Po uruchomieniu programu należy kliknąć na „Nowy projekt”.
W reakcji, program poprosi o wszystkie niezbędne informacje dotyczące minimalnej konfiguracji projektu:
- nazwa projektu: podać nazwę nadaną projektowi (program sam doda rozszerzenie .mem)
- nazwa pliku hex: podać pełną nazwę pliku hex z kodem programu
- lokalizacja pamięci EPROM od: program domyślnie dzieli przestrzeń adresową po 32 kB na EPROM (od 0000h do 7FFFh) oraz RAM (od 8000h do FFFFh), ale można podać inne adresy
- lokalizacja pamięci EPROM do
- lokalizacja pamięci RAM od
- lokalizacja pamięci RAM do
Klikając na „Dodaj El” można wprowadzoną konfigurację rozszerzyć o specyfikację przyłączonych do systemu prockowego portów. Po kliknięciu na „Dodaj…” istnieje możliwość wskazania na konkret. Mogą to być:
- pamięć RAM: nie ma obowiązku wykorzystania układów typu 62256 a przestrzeń może być wykorzystana przez pamięci o mniejszej pojemności tworzące nie koniecznie ciągłą adresację (mogą być dziury),
- pamięć ROM (EPROM), identycznie jak z pamięcią RAM,
- port wejściowy: pozwala dodać do projektu lokalizację w przestrzeni adresowej dla operacji IN/OUT przedziału adresowego (od .. do) komórek, dla których legalna jest operacja IN,
- port wyjściowy: podobnie jak do ‘port wejściowy’, z tym, że tu będą dopuszczalne tylko instrukcje OUT,
- port dwukierunkowy: podobnie jak do ‘port wejściowy’, z tym, że tu są dopuszczalne operacje zarówno IN jak i OUT.
Po wybraniu wariantu, kliknąć na „Wybierz” oraz dalej należy określić adresacją od
oraz adresację do
W ten sposób można określić pełne środowisko sprzętowe systemu prockowego.
By zmodyfikować lub usunąć należy w okienku „Projekt” klikając na odpowiednią pozycję wskazać element, który jest do usunięcia „Usuń El” lub modyfikacji „Zmień El”. Po wprowadzeniu zmian, aktualny stan można zapisać na dysku po kliknięciu na „Zapis Proj”. Po zmianach opis środowiska może wyglądać następująco:
Przy każdym (późniejszym) uruchomieniu programu, można poprzez „Otwórz Proj” mieć te dane „wklepane”. Istnieje możliwość „upuszczeniu” na formę programu nazwy pliku z rozszerzeniem .mem, jest to równoznaczne z otwarciem pliku projektu.
Ten plik projektu jest plikiem tekstowym i można go sobie pooglądać (i nawet zmodyfikować w windozowym notatniku). Jego syntaktyka jest prosta i łatwo jest skojarzyć co jest co: przykładowo
Kod: Zaznacz cały
HEX:example1.hex
ROM:0000:7FFF
RAM:8000:FFFF
IN:C0:C3
IO:F0:F3
END
Klikając na przycisk „Ładuj hex”, program wczyta wskazany w opisie projektu plik, dokona deasemblacji oraz wynik pokaże w okienku „Pamięć (program)”.
Jeżeli w trakcie symulacji zostaną „namierzone” pomyłki, można dokonać zmian w sofcie i skompilować go na nowo. Nie ma konieczności wychodzenia z programu emulatora, każdorazowe kliknięcie na „Ładuj hex” ponownie wczytuje plik kodu z dysku i dokonuje jego deasemblacji.
Po korekcie dostrzeżonych literówek w programie, aktualna wersja:
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Zacny emulator. "Widzę" oczami wyobraźni ileż to było roboty w kodzie... Oczywiście dokumentacja dokumentacją, ale parsowanie komend, interpretacja wykonania i realizm symulacji to zupełnie inna bajka.. Jestem pełen podziwu..
Można powiedzieć, że wykonałeś takiego wirtualnego Altair (lub podobny komputer tamtej klasy). Nieźle, naprawdę nieźle.
Można powiedzieć, że wykonałeś takiego wirtualnego Altair (lub podobny komputer tamtej klasy). Nieźle, naprawdę nieźle.
Internet łączy ludzi, którzy dzielą się swoimi zainteresowaniami, pomysłami i potrzebami, bez względu na geograficzne (przeciwności).
BOB TAYLOR, PARC
BOB TAYLOR, PARC
Re: [Z80] Emulator procesora Z80
phill2k pisze:Zapowiada się super, możesz dołaczyć jakiś przykładowy plik projektu aby można było zobaczyć jak samemu ustawiać parametry symulacji.
Mówisz, masz...
Program ćwiczy zabawy ze stosem (tworzenie lokalnych zmiennych na stosie). Masz tam listing z kompilacji (by widzieć oryginał), program w hex do symulacji no i opis projektu.
i zaktualizowaną wersję (jeszcze zdarzają się niedoróbki, które usuwam).
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Deasemblacja
Dysponując programem binarnym (w zapisie intel-hex), program dokonuje deasemblacji, by na ekranie było widać co się dzieje: co program robi, gdzie jest. Generalnie taka operacja nie jest jednoznaczna, gdyż trudno jest wyrokować o sensie zawartości przykładowo pary rejestrów HL. To może być adres skoku jak w instrukcji JP (HL), to może być adres operandu w instrukcji arytmetycznej lub wręcz może pełnić rolę akumulatora w arytmetyce 16-bitowej. Ładując program zilogowy do pamięci emulator zaczyna proces deasemblacji. Początek jest wiadomo w którym miejscu: adres 0. I tak instrukcja po instrukcji tłumaczony jest kod na prawdopodobną wersję źródłową. Napisałem prawdopodobną, gdyż nie ma gwarancji, że ta czynność będzie zgodna z intencjami autora. Algorytm deasemblacji jest rekurencyjny. Rozpatrywane jest każde rozgałęzienie programu by poznać wszystkie możliwe ścieżki realizacji programu. Jednak nie gwarantuje to deasemblacji całości, gdyż w programie może wystąpić niejawny skok do miejsca, które jest wyliczone [przykładowo JP (HL)].
Jeżeli w projekcie są wskazania na obsługę przerwań, to inicjowana jest deasemblacja na stałe adresy związane z obsługą tych przerwań. Ponieważ nie ma obowiązku, by program obsługiwał przerwania, gdyż to może być trenowany jakiś fragment programu, to nie ma potrzeby deasemblować punktów wejścia do obsługi przerwań. Z tego powodu w opisie projektu deklarowane są używane przerwania.
W trakcie deasemblacji powstają obszary w przestrzeni programu, które nie zostały jawnie użyte jako program (to mogą być obszary danych) lub „martwe procedury” – fragmenty programu zawarte w przestrzeni adresowej, które nigdzie nie są wykorzystane. Program konwertuje te obszary do postaci define byte. Oczywiście w tym wszystkim jest jeden wyjątek: instrukcja JP (HL), JP (IX), JP (IY), które realizują skok, tylko nie wiadomo dokąd (na etapie deaseblacji).
Przykład takiego przypadku:
To może być kawałek martwego kodu lub rzeczywisty kod, do którego zaistnieje skok z wyliczonym adresem. Na wstępnym etapie nie można tego określić. Jeżeli rzeczywiście zaistnieje użycie tego fragmentu jako kodu programu, to emulator natrafiając na takie miejsce zapyta „operatora”, czy wykonać deasemblację. Dla emulatora to nie ma istotnego znaczenia, on i tak „jedzie” po kodzie binarnym, a tutaj chodzi przede wszystkim o „komfort” użytkownika.
Program dysponuje dodatkową możliwością: deasemblacji na żądanie. W tym celu należy kliknięciem wskazać miejsce, od którego należy wykonać deasemblację
i następnie klikając prawym klawiszem myszki wybrać opcję (ta możliwość jest od wersji 1.12)
i program posłusznie robi poleconą czynność.
W oryginale (czyli źródle) ten fragment jest następujący:
Dysponując programem binarnym (w zapisie intel-hex), program dokonuje deasemblacji, by na ekranie było widać co się dzieje: co program robi, gdzie jest. Generalnie taka operacja nie jest jednoznaczna, gdyż trudno jest wyrokować o sensie zawartości przykładowo pary rejestrów HL. To może być adres skoku jak w instrukcji JP (HL), to może być adres operandu w instrukcji arytmetycznej lub wręcz może pełnić rolę akumulatora w arytmetyce 16-bitowej. Ładując program zilogowy do pamięci emulator zaczyna proces deasemblacji. Początek jest wiadomo w którym miejscu: adres 0. I tak instrukcja po instrukcji tłumaczony jest kod na prawdopodobną wersję źródłową. Napisałem prawdopodobną, gdyż nie ma gwarancji, że ta czynność będzie zgodna z intencjami autora. Algorytm deasemblacji jest rekurencyjny. Rozpatrywane jest każde rozgałęzienie programu by poznać wszystkie możliwe ścieżki realizacji programu. Jednak nie gwarantuje to deasemblacji całości, gdyż w programie może wystąpić niejawny skok do miejsca, które jest wyliczone [przykładowo JP (HL)].
Jeżeli w projekcie są wskazania na obsługę przerwań, to inicjowana jest deasemblacja na stałe adresy związane z obsługą tych przerwań. Ponieważ nie ma obowiązku, by program obsługiwał przerwania, gdyż to może być trenowany jakiś fragment programu, to nie ma potrzeby deasemblować punktów wejścia do obsługi przerwań. Z tego powodu w opisie projektu deklarowane są używane przerwania.
W trakcie deasemblacji powstają obszary w przestrzeni programu, które nie zostały jawnie użyte jako program (to mogą być obszary danych) lub „martwe procedury” – fragmenty programu zawarte w przestrzeni adresowej, które nigdzie nie są wykorzystane. Program konwertuje te obszary do postaci define byte. Oczywiście w tym wszystkim jest jeden wyjątek: instrukcja JP (HL), JP (IX), JP (IY), które realizują skok, tylko nie wiadomo dokąd (na etapie deaseblacji).
Przykład takiego przypadku:
To może być kawałek martwego kodu lub rzeczywisty kod, do którego zaistnieje skok z wyliczonym adresem. Na wstępnym etapie nie można tego określić. Jeżeli rzeczywiście zaistnieje użycie tego fragmentu jako kodu programu, to emulator natrafiając na takie miejsce zapyta „operatora”, czy wykonać deasemblację. Dla emulatora to nie ma istotnego znaczenia, on i tak „jedzie” po kodzie binarnym, a tutaj chodzi przede wszystkim o „komfort” użytkownika.
Program dysponuje dodatkową możliwością: deasemblacji na żądanie. W tym celu należy kliknięciem wskazać miejsce, od którego należy wykonać deasemblację
i następnie klikając prawym klawiszem myszki wybrać opcję (ta możliwość jest od wersji 1.12)
i program posłusznie robi poleconą czynność.
W oryginale (czyli źródle) ten fragment jest następujący:
Kod: Zaznacz cały
Ld hl , loop
loop halt
jp (hl)
ld a , '*'
ld b , '*'
ld c , '*'
ld d , '*'
ld e , '*'
ld hl , loop
jp (hl)
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
gaweł pisze:Deasemblacja
Dysponując programem binarnym (w zapisie intel-hex), program dokonuje deasemblacji, by na ekranie było widać co się dzieje: co program robi, gdzie jest. Generalnie taka operacja nie jest jednoznaczna, gdyż trudno jest wyrokować o sensie zawartości przykładowo pary rejestrów HL. To może być adres skoku jak w instrukcji JP (HL), to może być adres operandu w instrukcji arytmetycznej lub wręcz może pełnić rolę akumulatora w arytmetyce 16-bitowej.
Możliwości jest wiele. Sprytny programista może np. przekazywać argumenty przez stos (za rozkazem CALL). W takim przypadku większość deasemblerów się gubi.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
"If A = success, then the formula is A = X + Y + Z.
X is work. Y is play. Z is keep your mouth shut."A. Einstein
X is work. Y is play. Z is keep your mouth shut."A. Einstein
Re: [Z80] Emulator procesora Z80
Zegar pisze:W takim przypadku większość deasemblerów się gubi.
No na takie coś to chyba nie ma siły. W ogólności, jak pisałem wcześniej, operacja deasemblacji nie jest jednoznaczna.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Myślę, że deasemblacja w tym emulatorze jest tylko miłym dodatkiem. Do analizy kodu binarnego są specjalizowane narzędzia np. Ghidra, i podejrzewam, że i one mogą mieć pewne problemy w trakcie automatycznej analizy z przekazywaniem parametrów przez stos lub obliczanych skoków.
Głównym celem emulatorów jest jak najwierniejsze odwzorowanie fizycznego środowiska za pomocą wirtualizacji i przedstawiony tu program spełnia te założenia. Generalnie emulatory umożliwiają z zapoznaniem się z oprogramowaniem bez dostępu do fizycznego sprzętu (emulator speccy lub innego komputera) i/lub do analizy wykonania kodu (programowy debuger). W tym drugim przypadku, bardziej oczekiwaną funkcjonalnością byłaby możliwość importu kodu (np. listing po asemblacji), możliwość ustawienia pułapek i śledzenia kodu, co uławiałoby proces debugowania. Bardziej rozbudowane emulatory umożliwiają dodawanie urządzeń zewnętrznych, ale wiąże się to również z budową emulatora takich peryferii.
Głównym celem emulatorów jest jak najwierniejsze odwzorowanie fizycznego środowiska za pomocą wirtualizacji i przedstawiony tu program spełnia te założenia. Generalnie emulatory umożliwiają z zapoznaniem się z oprogramowaniem bez dostępu do fizycznego sprzętu (emulator speccy lub innego komputera) i/lub do analizy wykonania kodu (programowy debuger). W tym drugim przypadku, bardziej oczekiwaną funkcjonalnością byłaby możliwość importu kodu (np. listing po asemblacji), możliwość ustawienia pułapek i śledzenia kodu, co uławiałoby proces debugowania. Bardziej rozbudowane emulatory umożliwiają dodawanie urządzeń zewnętrznych, ale wiąże się to również z budową emulatora takich peryferii.
Re: [Z80] Emulator procesora Z80
tapy pisze:Myślę, że deasemblacja w tym emulatorze jest tylko miłym dodatkiem.
Oczywiście, deasemblacja jest tylko ułatwieniem. Głównym celem jest emulacja generalnie własnych programów by znaleźć własne pomyłki.
Emulacja programu
Po uruchomieniu programu i otwarciu pliku projektu, mamy (emulowany program nie „maca” żadnych portów i nie zajmuje się przerwaniami, więc ma bardzo minimalistyczne środowisko):
Klikając na „Ładuj hex” (jego nazwa jest już wpisana z plik projektu) można załadować program binarny . Jeżeli w trakcie symulacji zostaną dostrzeżone własne błędy, to można zmodyfikować program źródłowy, skompilować i ponownie kliknąć na „Ładuj hex” (nie ma konieczności zamykania programu emulatora lub ponownego otwierania projektu). Po załadowaniu kodu, realizowana jest operacja „Reset” (a jej istotną cechą jest wypełnienie wszystkich obszarów pamięci RAM wartościami losowymi – taka mała próba zbliżenia się do realizmu, ustawienie IM 0, nadanie wartości początkowych dla rejestrów), program jest deasemblowany i jego postać jest pokazana w okienku.
W tym przykładzie wszystkie skoki i wywołania są „jawne”, więc nie ma „potencjalnych” martwych kodów. Po kliknięciu na „Krok” lub „Uruchom” program staruje i nie ma już możliwości „grzebania” w konfiguracji projektu. By wrócić do tej możliwości program należy zatrzymać klikając na „Zatrzymaj” (to nic, że program „stoi”, gdyż został puszczony krokowo, ale jest w kontekście <uruchomiony>, więc będzie wymagał zatrzymania, by stały się dostępne pewne jego funkcje). Załadowanie wskaźnika stosu powoduje, że zostaje wyświetlony stos – zawartość pamięci wskazana przez rejestr SP. Stos jest pokazany oczywiście „od tyłu” i widać tu dosyć przypadkowe wartości.
Przed wykonaniem wybranych instrukcji, program próbuje w okienku „Pamięć (dane)” pokazać zawartość komórek pamięci (przed wykonaniem instrukcji). W zależności od następnej instrukcji, początek wyświetlanego obszaru jest określony przez
- stan par rejestrów HL dla instrukcji, gdzie (HL) jest operandem,
- stan pary rejestrów BC dla instrukcji: LD A,(BC), LD (BC),A,
- stan pary rejestrów DE dla instrukcji: LD A,(DE), LD (DE),A,
- stan IX+disp dla instrukcji, gdzie (IX+disp) jest operandem,
- stan IY+disp dla instrukcji, gdzie (IY+disp) jest operandem,
- 16-bitowy operand typu direct: przykładowo LD A,(adr16), LD (adr16),HL, LD IX,(adr16), LD (adr16),BC,
- załadowanie pary rejestrów operandem immediate wskazując „potencjalnie ciekawe miejsce w pamięci”.
W przypadku instrukcji z operandem IX+displ lub IY+displ, pokazana jest komórka o docelowym adresie (przed operacją)
Jeżeli instrukcja modyfikuje zawartość pamięci RAM, to lokacja w pamięci jest pokazana przed
i po wykonaniu instrukcji.
Może się tak zdarzyć, że kolejna instrukcja będzie wymagała innego regionu pamięci RAM i wynik poprzedniej operacji „zginie” z okienka. Zawsze istnieje możliwość podglądu, są trzy warianty:
- podać adres docelowy,
- podać samo przesunięcie dla rejestru IX,
- podać samo przesunięcie dla rejestru IY.
podać docelowy adres, przykładowo:
Można skorzystać z adresowania indeksowego wybierając „Wyświetl pamięć od adresu (IX+nn)”,
wtedy należy podać samo przesunięcie (liczbę nn). Może ona być ze znakiem.
Wybierając z rozwijanego menu opcję „Wyświetl pamięć od adresu (IY+nn)” tok postępowania jest identyczny.
W przypadku, gdy interesuje nas obszar pamięci o adresie zawartym w parze rejestrów, można kliknąć na pole związane z wymaganą parą rejestrów.
Analogicznie można wykorzystać pary DE, HL, X i Y.
Przydatną możliwością jest pokazanie ścieżki wywołań. Można ją sobie obejrzeć klikając prawym klawiszem i wybierając „Kolejka wywołań”.
W odpowiedzi dostaniemy: skąd, dokąd i z jakiego powodu.
Tu powodem jest „zwykłe wywołanie” a inną możliwością jest przerwanie lub przerwanie niemaskowalne.
Pokazany tekst można sobie zapisać do pliku, co może być pomocne przy analizie programu.
Usunąłem pomyłkę w programie, nowa wersja:
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Break point’y w programie
W emulatorze nie może zabraknąć funkcji związanych z pułapkami zwanymi break pointy. By to uzyskać to należy mieć załadowany program (binarniak w zilogu).
W okienku z programem „przewinąć się” do punktu, w którym wykonanie programu ma zostać wstrzymane i zrobić tam dwuklik. Miejsce to zostaje oznaczone gwiazdką. Ponowny dwuklik w tym miejscu zdejmuje z tej instrukcji pułapkę. Jeżeli wskazana instrukcja nie była oznaczona flagą pułapki, to zostanie ona ustawiona, jeżeli była oznaczona flagą pułapki, to zostaje zdjęta. Pułapek można w programie ustawić dowolną ilość. Efektem operacji pułapkowej jest przestawienie podświetlenia w okienku programu (co nie zmienia wartości zapisanej w rejestrze PC). By wrócić należy użyć prawego klawisza myszki i wybrać opcję „Skocz do miejsca wskazanego przez PC”. I wszystko wraca do normy.
Uruchomienie programu „na żywioł” (przycisk <Uruchom>) zatrzymuje wykonanie programu we wskazanym miejscu (program jest przed wykonaniem instrukcji). By przejść przez ten punkt należy kliknąć przycisk <Krok>.
Przy pracy krokowej wykonanie zawsze przechodzi przez pułapki bez zatrzymania wykonania.
By usunąć pułapki należy kliknąć prawym klawiszem myszki i wybrać <Usuń wszystkie pułapki>.
W emulatorze nie może zabraknąć funkcji związanych z pułapkami zwanymi break pointy. By to uzyskać to należy mieć załadowany program (binarniak w zilogu).
W okienku z programem „przewinąć się” do punktu, w którym wykonanie programu ma zostać wstrzymane i zrobić tam dwuklik. Miejsce to zostaje oznaczone gwiazdką. Ponowny dwuklik w tym miejscu zdejmuje z tej instrukcji pułapkę. Jeżeli wskazana instrukcja nie była oznaczona flagą pułapki, to zostanie ona ustawiona, jeżeli była oznaczona flagą pułapki, to zostaje zdjęta. Pułapek można w programie ustawić dowolną ilość. Efektem operacji pułapkowej jest przestawienie podświetlenia w okienku programu (co nie zmienia wartości zapisanej w rejestrze PC). By wrócić należy użyć prawego klawisza myszki i wybrać opcję „Skocz do miejsca wskazanego przez PC”. I wszystko wraca do normy.
Uruchomienie programu „na żywioł” (przycisk <Uruchom>) zatrzymuje wykonanie programu we wskazanym miejscu (program jest przed wykonaniem instrukcji). By przejść przez ten punkt należy kliknąć przycisk <Krok>.
Przy pracy krokowej wykonanie zawsze przechodzi przez pułapki bez zatrzymania wykonania.
By usunąć pułapki należy kliknąć prawym klawiszem myszki i wybrać <Usuń wszystkie pułapki>.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Modyfikacja stanów rejestrów
Po załadowaniu kodu programu do pamięci emulatora (po wcześniejszym otwarciu projektu), program można puścić na żywioł. Istotną funkcją emulatora jest „pilnowanie” by wszystko szło właściwie oraz zgłaszanie „nadużyć”.
Przykładowo, zaistniało naruszenie przestrzeni pamięci ROM, gdyż zapis czegokolwiek w ten obszar jest niedopuszczalny.
Wykonanie programu zostało zatrzymane z odpowiednim komunikatem. Problem wygenerowała instrukcja LD (1234h),A, której zadaniem jest zapis bajtu w pamięci o adresie wskazanym jako operand instrukcji (wskazuje on na obszar pamięci ROM). Odczyt z tego obszaru jest możliwy, jednak zapis tam technicznie nie jest możliwy.
Podobna sytuacja wystąpiła nieco później. Przed instrukcją LD (HL),A została załadowana para rejestrów HL, ale w wyniku „własnej pomyłki” to nie jest właściwa wartość w tej parze rejestrów.
Możliwe jest dokonanie modyfikacji bez potrzeby edycji programu źródłowego i jego kompilacji (no chyba, że będzie to zachodzić wielokrotnie, to wtedy jest to bardziej uzasadnione). Można dokonać korekty każdego pokazanego niżej rejestru:
Operacja zmiany zawartości rejestrów jest możliwa w sytuacji zatrzymanego programu lub gdy program jest puszczany krokowo. Należy kliknąć na wybrany rejestr i wprowadzić szesnastkowo nową wartość. Zmiany par rejestrów (BC, DE i HL) są realizowane przez dwie zmiany zawartości pojedynczych rejestrów (starsza część jest z lewej strony, młodsza z prawej strony). Zmiana rejestru BC, DE, HL, IX, IY jednocześnie wyświetla zawartość pamięci danych wskazaną przez modyfikację rejestrów składowych. Również możliwa jest zmiana zawartości wskaźnika stosu, jednak tu trzeba zachować czujność, bo może to doprowadzić, że program się zgubi (po przykładowo wykonaniu instrukcji RET).
W tym przypadku można zmienić zawartość pary rejestrów HL
i cofnąć program o jedną instrukcję wpisując do rejestru PC adres niewykonanej instrukcji.
Tym razem zapis „się udał”.
Pewnym ograniczeniom podlega modyfikacja rejestru PC. Istnieją instrukcje jednobajtowe, dwubajtowe oraz składające się z trzech bajtów i więcej. Wymagane jest by trafić zawsze na pierwszy bajt instrukcji (po deasemblacji wiadomo, gdzie zaczyna się każda instrukcja). W tym miejscu program nie da sobie zrobić krzywdy.
Wpisanie przykładowo do PC wartości 12 (hex) wskazuje na trzeci bajt instrukcji LD IX,3344h (czyli operand tej instrukcji).
Po załadowaniu kodu programu do pamięci emulatora (po wcześniejszym otwarciu projektu), program można puścić na żywioł. Istotną funkcją emulatora jest „pilnowanie” by wszystko szło właściwie oraz zgłaszanie „nadużyć”.
Przykładowo, zaistniało naruszenie przestrzeni pamięci ROM, gdyż zapis czegokolwiek w ten obszar jest niedopuszczalny.
Wykonanie programu zostało zatrzymane z odpowiednim komunikatem. Problem wygenerowała instrukcja LD (1234h),A, której zadaniem jest zapis bajtu w pamięci o adresie wskazanym jako operand instrukcji (wskazuje on na obszar pamięci ROM). Odczyt z tego obszaru jest możliwy, jednak zapis tam technicznie nie jest możliwy.
Podobna sytuacja wystąpiła nieco później. Przed instrukcją LD (HL),A została załadowana para rejestrów HL, ale w wyniku „własnej pomyłki” to nie jest właściwa wartość w tej parze rejestrów.
Możliwe jest dokonanie modyfikacji bez potrzeby edycji programu źródłowego i jego kompilacji (no chyba, że będzie to zachodzić wielokrotnie, to wtedy jest to bardziej uzasadnione). Można dokonać korekty każdego pokazanego niżej rejestru:
Operacja zmiany zawartości rejestrów jest możliwa w sytuacji zatrzymanego programu lub gdy program jest puszczany krokowo. Należy kliknąć na wybrany rejestr i wprowadzić szesnastkowo nową wartość. Zmiany par rejestrów (BC, DE i HL) są realizowane przez dwie zmiany zawartości pojedynczych rejestrów (starsza część jest z lewej strony, młodsza z prawej strony). Zmiana rejestru BC, DE, HL, IX, IY jednocześnie wyświetla zawartość pamięci danych wskazaną przez modyfikację rejestrów składowych. Również możliwa jest zmiana zawartości wskaźnika stosu, jednak tu trzeba zachować czujność, bo może to doprowadzić, że program się zgubi (po przykładowo wykonaniu instrukcji RET).
W tym przypadku można zmienić zawartość pary rejestrów HL
i cofnąć program o jedną instrukcję wpisując do rejestru PC adres niewykonanej instrukcji.
Tym razem zapis „się udał”.
Pewnym ograniczeniom podlega modyfikacja rejestru PC. Istnieją instrukcje jednobajtowe, dwubajtowe oraz składające się z trzech bajtów i więcej. Wymagane jest by trafić zawsze na pierwszy bajt instrukcji (po deasemblacji wiadomo, gdzie zaczyna się każda instrukcja). W tym miejscu program nie da sobie zrobić krzywdy.
Wpisanie przykładowo do PC wartości 12 (hex) wskazuje na trzeci bajt instrukcji LD IX,3344h (czyli operand tej instrukcji).
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Przerwania
W Z80 mamy trzy tryby obsługi przerwań modyfikowane instrukcją IM. W trybie IM 0 przerwania są obsługiwane zgodnie z filozofią intela: gdzie jest kontroler bazujący na układzie 8214 generujący instrukcję RST 0 do RST 7 (w zilogu układ 8259 nie ma sensu). Ten tryb jest obsługiwany przez emulator, gdzie musi być zgłoszona obsługa wymaganych przerwań (przykładowo wszystkich):
To „aktywuje” przyciski do generowania przerwań (aktywowane mają cimnoczerwone podświetlenie).
Symulacja programu prowadzi do ustalenia trybu przerwań
Klikając na przycisk przykładowo RST4 generowane jest odpowiednie przerwanie (zmienia się również kolor podświetlenia przycisku):
Program reaguje przejściem do obsługi przerwania (przyjęcie przerwania „gasi” przycisk):
W trakcie obsługi można sobie jeszcze wygenerować przerwanie NMI (identycznie → kliknąć na przycisk NMI).
I obejrzeć „kolejkę wywołań”:
W trybie obsługi przerwań IM 1, w programie musi być zgłoszona obsługa przerwania RST 7 (no i również w opisie projektu). Po reset, procek obsługuje przerwania w trybie IM 0, toteż startowo wygląda to jak na poniższej ilustracji.
Symulacja programu po wykonaniu instrukcji IM 1, prowadzi do aktywacji jedynie przycisku INT (i dezaktywacji wszystkich pozostałych RSTn).
Kliknięcie na przycisk INT prowadzi do obsługi przerwania jako RST 7.
Najbardziej złożona obsługa przerwań to tryb IM 2. Wymaga to odpowiedniej konfiguracji „środowiska” symulacji. Tu właściwie należałoby rozbudować program emulatora o udawanie całego zestawu zilogowych peryferali lub wymyślić coś nowego. Pamiętając, że w przerywających peryferalach zilogowych jest rejestr do wpisu wektora przerwań oraz to, że wpisywane dane są parzyste (zawsze jest wyzerowany najmłodszy bit wpisywanych danych – tak jest w znanych mi peryferalach), to rozbudowałem program o możliwość wskazania takich portów. Poprzez „Dodaj El.” można dodać port wraz z rejestrem obsługi wektora przerwań. Po kliknięcie na ten przycisk wybrać przykładowo „Port dwukierunkowy z wektorem przerwań” . Możliwość portu wyjściowego z obsługą przerwań jest chyba „abstrakcją” → nie ma układu zilogowego do którego można jedynie pisać mającego obsługę przerwań wektorowych. Port wejściowy z wektorem przerwań jest już nierealizowalny fizycznie.
Po wyborze wariantu portu należy podać zakres adresowy w przestrzeni portów oraz adres rejestru do zaprogramowania wektora przerwań (należącego do przedziału adresowego od .. do).
Nie odzwierciedla to rzeczywistych peryferali, gdyż przykładowo PIO ma dwa wektory przerwań: dla kanału A oraz kanału B. Można to symulować jako dwa peryferale z wektorem przerwań. Przykładowy opis pokazuje ilustracja:
Po zaprogramowaniu wektorów przerwań w peryferalach (jak i również rejestru I w CPU), przełączeniu na tryb obsługi przerwań IM 2 (aktywuje się jedynie przycisk INT).
Można sobie wygenerować przerwanie klikając na przycisk INT. Przyjęcie tego przerwania (w realnym świecie) wymaga uzyskania od przerywającego peryferala części danych, które pozwolą na uzyskanie adresu procedury obsługi przerwania. W symulacji, należy to wskazać samemu, program zgłosi się o szczegóły (bazując na zapisach do portów określonych jako przechowujących wektory przerwań) powstaje menu, z którego należy wybrać peryferal zgłaszający przerwanie i kliknąć: „Wybierz” („Zaniechaj” oznacza brak wskazania na port i symulator zignoruje to przerwanie).
To spowoduje, że z zapisanych w porcie danych i z zawartości rejestru I zostanie złożony adres obsługi przerwania. Przy pierwszym przerwaniu doprowadziło to w emulatorze do konieczności deasemblacji kodu, gdyż brak jawnych w programie skoków do obsługi przerwania prowadzi do uznania fragmentów kodu jako dane lub martwy kod. Należy wyrazić zgodę.
Program przejdzie do obsługi tego przerwania:
Podglądając kolejkę wywołań, można poznać szczegóły związane z jego obsługą.
Bieżąca wersja programu:
W Z80 mamy trzy tryby obsługi przerwań modyfikowane instrukcją IM. W trybie IM 0 przerwania są obsługiwane zgodnie z filozofią intela: gdzie jest kontroler bazujący na układzie 8214 generujący instrukcję RST 0 do RST 7 (w zilogu układ 8259 nie ma sensu). Ten tryb jest obsługiwany przez emulator, gdzie musi być zgłoszona obsługa wymaganych przerwań (przykładowo wszystkich):
To „aktywuje” przyciski do generowania przerwań (aktywowane mają cimnoczerwone podświetlenie).
Symulacja programu prowadzi do ustalenia trybu przerwań
Klikając na przycisk przykładowo RST4 generowane jest odpowiednie przerwanie (zmienia się również kolor podświetlenia przycisku):
Program reaguje przejściem do obsługi przerwania (przyjęcie przerwania „gasi” przycisk):
W trakcie obsługi można sobie jeszcze wygenerować przerwanie NMI (identycznie → kliknąć na przycisk NMI).
I obejrzeć „kolejkę wywołań”:
W trybie obsługi przerwań IM 1, w programie musi być zgłoszona obsługa przerwania RST 7 (no i również w opisie projektu). Po reset, procek obsługuje przerwania w trybie IM 0, toteż startowo wygląda to jak na poniższej ilustracji.
Symulacja programu po wykonaniu instrukcji IM 1, prowadzi do aktywacji jedynie przycisku INT (i dezaktywacji wszystkich pozostałych RSTn).
Kliknięcie na przycisk INT prowadzi do obsługi przerwania jako RST 7.
Najbardziej złożona obsługa przerwań to tryb IM 2. Wymaga to odpowiedniej konfiguracji „środowiska” symulacji. Tu właściwie należałoby rozbudować program emulatora o udawanie całego zestawu zilogowych peryferali lub wymyślić coś nowego. Pamiętając, że w przerywających peryferalach zilogowych jest rejestr do wpisu wektora przerwań oraz to, że wpisywane dane są parzyste (zawsze jest wyzerowany najmłodszy bit wpisywanych danych – tak jest w znanych mi peryferalach), to rozbudowałem program o możliwość wskazania takich portów. Poprzez „Dodaj El.” można dodać port wraz z rejestrem obsługi wektora przerwań. Po kliknięcie na ten przycisk wybrać przykładowo „Port dwukierunkowy z wektorem przerwań” . Możliwość portu wyjściowego z obsługą przerwań jest chyba „abstrakcją” → nie ma układu zilogowego do którego można jedynie pisać mającego obsługę przerwań wektorowych. Port wejściowy z wektorem przerwań jest już nierealizowalny fizycznie.
Po wyborze wariantu portu należy podać zakres adresowy w przestrzeni portów oraz adres rejestru do zaprogramowania wektora przerwań (należącego do przedziału adresowego od .. do).
Nie odzwierciedla to rzeczywistych peryferali, gdyż przykładowo PIO ma dwa wektory przerwań: dla kanału A oraz kanału B. Można to symulować jako dwa peryferale z wektorem przerwań. Przykładowy opis pokazuje ilustracja:
Po zaprogramowaniu wektorów przerwań w peryferalach (jak i również rejestru I w CPU), przełączeniu na tryb obsługi przerwań IM 2 (aktywuje się jedynie przycisk INT).
Można sobie wygenerować przerwanie klikając na przycisk INT. Przyjęcie tego przerwania (w realnym świecie) wymaga uzyskania od przerywającego peryferala części danych, które pozwolą na uzyskanie adresu procedury obsługi przerwania. W symulacji, należy to wskazać samemu, program zgłosi się o szczegóły (bazując na zapisach do portów określonych jako przechowujących wektory przerwań) powstaje menu, z którego należy wybrać peryferal zgłaszający przerwanie i kliknąć: „Wybierz” („Zaniechaj” oznacza brak wskazania na port i symulator zignoruje to przerwanie).
To spowoduje, że z zapisanych w porcie danych i z zawartości rejestru I zostanie złożony adres obsługi przerwania. Przy pierwszym przerwaniu doprowadziło to w emulatorze do konieczności deasemblacji kodu, gdyż brak jawnych w programie skoków do obsługi przerwania prowadzi do uznania fragmentów kodu jako dane lub martwy kod. Należy wyrazić zgodę.
Program przejdzie do obsługi tego przerwania:
Podglądając kolejkę wywołań, można poznać szczegóły związane z jego obsługą.
Bieżąca wersja programu:
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Re: [Z80] Emulator procesora Z80
Do programu wkradł się drobny błąd, który nie ma znaczenie (w sensie symulacji) a jedynie wprowadza lekko w błąd.
W obsłudze przerwania w trybie IM 2, podaje nieprawdziwe informacje, jeżeli w trakcie obsługi przerwania zapytamy o listę wywołań.
Wzięło się to z tego, że na listę wywołań "poszedł" adres wektora przerwań a nie jego wskazanie na adres obsługi.
Zmodyfikowana wersja programu:
W obsłudze przerwania w trybie IM 2, podaje nieprawdziwe informacje, jeżeli w trakcie obsługi przerwania zapytamy o listę wywołań.
Wzięło się to z tego, że na listę wywołań "poszedł" adres wektora przerwań a nie jego wskazanie na adres obsługi.
Zmodyfikowana wersja programu:
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse
Kto jest online
Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 4 gości