[Z80] Kultowy procek

Pozostałe układy mikrokontrolerów, układy peryferyjne i inne, nie mieszczące się w powyższych kategoriach.
Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

[Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 12:18

Ponieważ temat o procku 8051 zaczął skręcać a stronę Z80, to... fajnie trochę powspominać dawne dzieje.

Architektura mikroprocesorów Z80 zagadnienia sprzętowe

z80_ilu00.jpg


Układ Z80-CPU jest jednostką centralną (od ang. Central Processor Unit). Zadaniem tego układu jest realizacja ciągu rozkazów zapisanych w formie programu. Początkowo te układy były produkowane w formie wydzielonych układów scalonych w obudowie DIP40.
z80_ilu01.jpg
Z czasem w ofercie Ziloga pojawiły się bardziej zintegrowane układy zawierające więcej niż tylko samą jednostkę centralną. Przykładem może być układ Z84C15 (Z80-EIPC). Zawiera on w jednym układzie scalonym między innymi takie podzespoły jak:
  • Z80-CPU – jednostka centralna,
  • Z80-SIO – kontroler transmisji szeregowej,
  • Z80-CTC – kontroler licznikowo-zegarowy,
  • Z80-PIO – uniwersalny port równoległy (zespół WE/WY).
Gdyby do tego układu jeszcze dołożyć trochę pamięci stałej na program (FLASH) i trochę pamięci statycznej RAM, to być może mógłby stanowić poważną konkurencję dla mikrokontrolerów z rodziny C51.
z80_ilu02.png
Rysunek przedstawia topologię układu. Wybrane wyprowadzenia układu mają w opisie użyty znak “/”, który ma symbolizować kreskę nad nazwą (w trybie tekstowym nie jest możliwe uzyskanie kreski nad nazwą, a jakoś trzeba sobie radzić, więc wymyślono znak “/” przed nazwą sygnału). Takie oznaczenie jest używane do wskazania, że ten sygnał jest w tzw. logice ujemnej. To oznacza, że stanem aktywnym dla danego sygnału jest stan logicznego zera. Tu warto zauważyć, że rodzina mikroprocesorów Z80 wprowadza i konsekwentnie realizuje (chyba nawet jako pierwsza na świecie) jednolite podejście do sygnałów sterujących. Wszystkie sygnały sterujące, zarówno wejściowe jak i wyjściowe, maję przyjęty jako stan aktywny logiczne zero. W innych mikroprocesorach (innych producentów) niektóre sygnały są aktywne dla stanu logicznej jedynki, niektóre dla stanu logicznego zera. Pomijając pewien bałagan, bo należy pamiętać co jest jakie, wprowadza to trochę utrudnień dla konstruktora.
Odnóżna procka (chyba tu nie da się zrobić tabelki):
D0-D7 we/wy trójstanowe dwukierunkowa, 8-bitowa magistrala danych. D0 oznacza najmniej znaczący bit, D7 najbardziej znaczący bit. To poprzez te druty przepływa cała mądrość.
A0-A15 wyjścia trójstanowe jednokierunkowa, 16-bitowa magistrala adresowa. A0 oznacza najmniej znaczący bit. Przez te druty, mikroprocesor informuje otoczenie gdzie lub skąd chce dane.
/RESET wejście Wejście zerowania, aktywne stanem niskim. To taki drucik do mikroprocesora, który mówi: “no koleś procek, zaczynamy od początku”.
CLK wejście Sygnał zegarowy taktujący pracę mikroprocesora, to taki drucik, który mówi jak szybko trzeba pracować (jak “ekonom z batem”).
/BUSREQ wejście Sygnał żądania zwolnienia przez CPU magistrali danych, adresowej i sterującej, stan aktywny-niski. To taki drucik, który żąda od CPU wprowadzanie linii danych, adresów i linii sterujących (/MREQ,/IORQ, /RD i /WR) w stan wysokiej impedancji i zawieszenia swojej pracy, czyli “ej ... koleś procek, może miałbyś ochotę na drzemkę, a ja ci pogrzebię w twoich zapiskach”.
/BUSACK wejście Sygnał odpowiedzi na żądanie /BUSREQ. Pojawienie się stanu niskiego jest potwierdzeniem zwolnienia magistrali systemowych (magistrala danych, adresowa i sterująca znajdują się w stanie wysokiej impedancji), czyli “idę się zdrzemnąć, a wy możecie w tym czasie poszperać w mojej pamięci”.
/HALT wyjście Sygnał stanu zatrzymania mikroprocesora. Stan niski na wyjściu /HALT oznacza, że Z80 CPU jest w trakcie wykonywania rozkazu HALT. Podczas zatrzymania mikroprocesor wykonuje rozkaz NOP, dzięki czemu nadal odświeżane są pamięci dynamiczne, czyli “finito z robotą”.
/INT wejście Sygnał zgłoszenia przerwania maskowalnego (stan aktywny niski). Stan na tym druciku wymuszany jest przez zewnętrzne układy we-wy, czyli “uwaga, ktoś puka do naszych drzwi i chce zburzyć nasz błogi spokój”.
/NMI wejście Sygnał zgłoszenia przerwania niemaskowalnego (aktywny-niski). Przerwanie NMI ma wyższy priorytet niż przerwanie maskowalne. Cechą charakterystyczną tego przerwania jest to, że jak zostanie zgłoszone , to ZAWSZE wejdzie, czyli “ktoś puka do drzwi i jak nie otworzymy mu, to se sam je otworzy ... łomikiem”
/M1 wyjście Stan aktywny-niski. Ten drucik informuje o rozpoczęciu wykonania pierwszego cyklu maszynowego (pobranie kodu instrukcji do wykonania). Stany niskie na wyjściach /M1 i /MREQ oznaczają, że mikroprocesor jest w trakcie pobierania kodu rozkazu z pamięci, czyli “uwaga ... przyjmuję zleconko na małą robótkę”
/IORQ wyjście trójstanowe Stan aktywny-niski. Drucik informujący, że magistralą adresową przesyłany jest ważny adres układów we-wy, czyli “uwaga, będę grzebać po portach”. Stan niski sygnału /IORQ i /M1 [niejako pobranie instrukcji z portu a nie z pamięci] oznacza potwierdzenie przyjęcia przerwania, czyli “uwaga, kto do mnie pukał i czego chce?”
/MREQ wyjście trójstanowe Stan aktywny-niski. Sygnał informujący, że na magistrali adresowej jest wystawiony adres komórki w pamięci, czyli “uwaga, będę grzebać w pamięci ... swojej”.
/RD wyjście trójstanowe Stan aktywny-niski. Sygnał odczytu z pamięci lub urządzeń we-wy. Pojawienie się stanu niskiego na tym druciku oznacza wysłanie na magistralę danych zawartości komórki pamięci lub rejestru układu we-wy, czyli “uwaga ... słucham was”.
/WR wyjście trójstanowe Stan aktywny-niski. Sygnał zapisu danych do pamięci lub układów we-wy. Stan niski na tym druciku sygnalizuje, że na magistrali danych znajduje się bajt, które powinno być zapisane do pamięci lub układu we-wy adresowanego liniami A0-A15 magistrali adresowej, czyli “uwaga, mówię do was”.
/WAIT wejście Stan aktywny-niski. Stan niski na tym wejściu oznacza, że pamięć lub układy we-wy nie są gotowe do przesłania danych. Mikroprocesor przedłuża cykl odczytu lub zapisu nie zmieniając stanu sygnałów na wyjściach do czasu, gdy stan sygnału /WAIT zmieni się na wysoki, czyli drucik, poprzez który świat zewnętrzny informuje mikroprocesor “ej koleś procek, poczekaj, ja nie nadążam ... bo mam coś wspólnego ... z żółwiem”.
/RFSH wyjście Stan aktywny-niski. Taki drucik, który oznacza odświeżenie pamięci dynamicznych RAM, czyli “uwaga, ćwiczyć pamięć, bo niećwiczona pamięć to, ... co to ja miałem ... a pamięć miałem, to się chyba nazywa ... skleroza”.
Budowa mikrokomputera w oparcie o mikroprocesor Z80 praktycznie zawsze wygląda podobnie. Jako mikrokomputer należy tu rozumieć szeroko pojęte urządzenie zawierające mikroprocesor: zarówno coś w stylu “ZX SPECTRUM” (popularny swego czasu mikrokomputer generalnie używany do gier) jak i zwykły zegarek z wyświetlaczem sterowanym przez Z80. Budowa obu urządzeń podlegają tym samym zasadom. Całość można podzielić na dwie części: “procesor” (mikroprocesor) oraz “reszta świata”. Również jest to prawdziwe w przypadku mikrokontrolerów, tylko, że “reszta świata” również znajduje się fizycznie w tym samym układzie scalonym.
z80_ilu03.png
Obie te części współpracują ze sobą i komunikują się poprzez grupy sygnałów sterujących, które generalnie można podzielić na trzy rodzaje:
  • szyna danych,
  • szyna adresowa,
  • szyna sterująca.
z80_ilu04.png

W przypadku szyny adresowej (czyli zbioru pojedynczych drucików), to intuicyjnie można określić, co wchodzi w jej skład. Podobnie w przypadku szyny danych. Obie te szyny służą do przesyłania określonych informacji: szyna adresowa podaje adresy do pamięci lub urządzeń, z którymi mikroprocesor aktualnie ma potrzebę komunikacji, oraz szyna danych, przez którą mikroprocesor nakazuje pamięci lub urządzeniom zewnętrznych (porty) zapamiętanie informacji lub przez którą mikroprocesor pobiera informacje z pamięci lub z urządzeń zewnętrznych (portów).
Zawartość szyny sterującej, to właściwie zbiór wszelkiego rodzaju drucików, za pomocą których mikroprocesor określa dla reszty świata szczegóły swoich zachcianek. Również reszta świata może przekazywać sygnały do mikroprocesora. Generalnie, szyna sterująca zawiera wszelkiego rodzaju sygnały, które niosą określoną informacją zarówno dla mikroprocesora jak i od mikroprocesora.
Posługując się dokumentacją mikroprocesora Z80 można zaobserwować co i w jaki sposób jest wykonywane. Właściwie to należy uwierzyć dokumentacji, bo te przebiegi trudno jest zaobserwować w rzeczywistości. Jeżeli sygnał CLK ma częstotliwość 1MHz (na poniższym rysunku), to czas trwania T1 (T2, T3 ...) wynosi 1 mikrosekundę (1/1000000 s), a to raczej jest za szybko by dostrzec to nieuzbrojonym okiem.
z80_ilu05.png
Tłumacząc powyższy rysunek przedstawiający pobranie z pamięci kodu instrukcji do wykonania na język ludzi, to mamy (w chronologii czasowej pokazanej na rysunku):
  • uwaga, na drucikach A0 do A15 jest zawarty adres (drucików jest 16 i za ich pomocą można wyprodukować ponad 65 tys różnych kombinacji),
  • uwaga, ... przyjmuję zleconko na małą robótkę (w pewnym momencie M1=0),
  • uwaga, będę grzebać w pamięci (w pewnym MREQ =0),
  • uwaga, ... słucham was (w pewnym RD =0).
Na tak określone przez mikroprocesor zachcianki (czyli w czasie wystawienia sterowań), reszta świata musi po pierwsze zgadnąć o co mu chodzi i to zrealizować. Sprowadza się to do dokładnego określenia za pomocą różnych rozwiązań na bazie układów logicznych. W tym wypadku układy powinny wypracować sygnał wyboru do określonej pamięci, ponieważ mikroprocesor sięga do pamięci (MREQ=0) i konkretnie chodzi o odczyt (RD=0) oraz cała ta zadyma dotyczy pobrania rozkazu do wykonania (M1=0). Pamięć musi wystawić przechowywane dane na szynę adresową i musi z tym wszystkim zdążyć na czas (czyli do końca cyklu).Po wycofaniu sygnałów sterujących ze stanu aktywnego (co należy rozumieć jako koniec zadymy), mikroprocesor wykonuje działania antysklerotyczne, czyli poleca układom pamięci dynamicznych wykonanie odświeżenia pamięci. Jeżeli w systemie nie są używane pamięci dynamiczne, to te sterowanie można zignorować.
W czasie trwania cyklu odświeżania, mikroprocesor, by nie tracić czasu, wykonuje to co nakazuje mu pobrany rozkaz. Czasami zajmie mu to trochę więcej czasu, czasami dodatkowo trzeba będzie zrobić zapis do pamięci, czasami do portu, ewentualnie zamiast zapisu będzie odczyt. To wszystko zależy od kodu pobranego rozkazu. Istnieje bardzo wiele instrukcji, które nie będą wymagały dodatkowych akcji związanych z szynami danych, adresowych oraz sterowań.
Jak to wszystko, czego wymagał pobrany rozkaz zostanie zakończone, to mikroprocesor ponownie pobierze rozkaz do wykonania, czyli koło się zamyka.
Jak zostało wspomniane wcześniej, wykonywany rozkaz może być poleceniem odczytu lub zapisu danych do pamięci.
z80_ilu06.png
Powyższy diagram pokazuje w szczegółach, co jest realizowane w tych operacjach.
W przypadku odczytu jest podobnie jak przy pobraniu kodu rozkazu (w końcu pobranie rozkazu do wykonania sprowadza się do odczytania tego kodu z pamięci). Jedyną występującą różnicą jest brak stanu aktywnego sygnału M1 (również nie występuje cykl odświeżania pamięci, który wchodzi w skład operacji pobrania rozkazu).
W przypadku zapisu do pamięci, również mikroprocesor na szynie adresowej wystawia adres, na szynie danych zapisywane informacje i wystawia sygnał żądania dostępu do pamięci, czyli: uwaga, będę grzebać w pamięci (w pewnym MREQ =0). W odpowiedzi wszystkie bramki, przerzutniki, rejestry i całe inne towarzystwo reszty świata się sprężyło i w napięciu [chodzi o napięcie emocjonalne a nie elektryczne :-)] czeka ... bo nie było informacji, że to odczyt (nie było RD=0), więc ... w pewnym momencie przychodzi: polecenie teraz zapisać (WR=0) i następuje odprężenie.
Przedstawione rysunki opisywały operacje dotyczące pamięci. Na podobnej zasadzie odbywają się sterowania w operacjach dotyczących portów. W tym przypadku zamiast sygnału MREQ występuje IORQ. W operacjach odczytu z portu przebieg sygnałów przedstawia następujący rysunek.
z80_ilu07.png
Informacje występujące na szynie danych należy interpretować następująco:
  • na drucikach A0 do A7 (inaczej niż w operacjach dotyczących pamięci) określony jest adres, możliwych kombinacji jest 256,
  • uwaga, będę grzebać po portach (IORQ=0),
  • uwaga, ... słucham was (w pewnym RD =0).
W operacjach dotyczących portów występuje jeszcze jeden szczegół, który nie występował w operacjach dotyczących dostępu do pamięci. Mikroprocesor w każdym odwołaniu do portu wstawia jeden cykl oczekiwania, czyli przedłuża o jeden impuls zegarowy czas trwania aktywnego stanu sterowań. Wynika to z tego, że porty z założenia traktowane są jako elementy powolne. Po określeniu poprzez sygnały sterujące czego chce mikroprocesor, elektronika reszty świata jak zwykle się spręża by wszystko było na czas a port, jak leniwa istota ... zanim się namyśli ... zanim poda swoje informacje na szynie danych... , więc tu mikroprocesor wykazuje się dużą dozą cierpliwości, troszkę poczeka (i robi to zawsze).
z80_ilu08.png
Identycznie jak przy odczycie, w operacjach zapisu danych do portu również występuje jeden takt oczekiwania na gotowość portu na przyjęcie danych.
Z istotnych cykli wykonywanych przez mikroprocesor pozostało jeszcze przyjęcie i realizacja obsługi przerwania. Sama realizacja obsługi przerwania niczym nie różni się od normalnych cykli M1 (związanych z pobieraniem instrukcji do wykonania), natomiast cechy charakterystyczne występują w momencie rozpoczęcia obsługi przerwania. Przedstawia po poniższy rysunek.
z80_ilu09.png
Z racji, że przerwanie w swej istocie zawsze jest związane z urządzeniami zewnętrznymi (portami), to rozpoczęcie obsługi przerwania jest sygnalizowane dla reszty świata pewnym charakterystycznym szczegółem: wykonany jest cykl M1 dla urządzenia (portu). Można to rozumieć jako pobranie kodu rozkazu do wykonania nie z pamięci, tylko z portu. Nie jest to rzeczywiste pobranie kodu rozkazy (nawet nie występuje sygnalizacja operacji odczytu, sygnał RD ciągle jest jedynką). Ta trochę dziwna sekwencja sterująca służy do sygnalizacji przez procesor faktu rozpoczęcia obsługi przerwania. Zgłaszające przerwanie urządzenia mają obowiązek rozpoznania tego stanu i w takim momencie “porozumieć się” z mikroprocesorem celem ustalenia wszystkich szczegółów związanych z rzeczywistym rozpoczęciem obsługi przerwania. Takie możliwości mają wszystkie układy wchodzące w skład rodziny mikroprocesorowej Z80.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony poniedziałek 15 maja 2017, 14:41 przez gaweł, łącznie zmieniany 2 razy.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

SuperGość
Uber Geek
Uber Geek
Posty: 2346
Rejestracja: piątek 04 wrz 2015, 09:03

Re: [Z80] Kultowy procek

Postautor: SuperGość » poniedziałek 15 maja 2017, 12:21

Na ostatnim roku studiów jak chodziłem na seminarium z techniki cyfrowej, to wtedy wykładowca, jak największa świętość pokazał z daleka tyle co pozyskany układ Z80 :D

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 12:46

Architektura mikroprocesorów Z80 :arrow: cóś o sofcie

Wręcz kultowy mikroprocesor Z80 jest mikroprocesorem 8-bitowym zbudowanym w oparciu o architekturę Von Neumanna. Główną cechą charakterystyczną procesorów w architekturze Von Neumanna jest wspólna pamięć danych i kodu programu. Łatwo z tego wysnuć wniosek, że wczytanie kodu programu z dowolnego źródła, umieszczenie go w pamięci (oczywiście jedynie w przypadku, gdy technicznie możliwy jest zapis do pamięci) i uruchomienie jest czynnością jak najbardziej naturalną. Do innych procesorów o tym samym typie architektury można zaliczyć procesory MC6800 (firmy Motorola), I8080 z późniejszą mutacją w postaci procesora I8085 (firmy Intel) i obecnie najbardziej rozpowszechniony I8086 wraz z wszystkimi mutacjami aż do Pentium włącznie.
z80s-i01.jpg
Mikroprocesor Z80 jest mocno ulepszoną wersją procesora I8080 (kompatybilność z procesorem Intela na poziomie kodów instrukcji). Patrząc na historię rozwoju niektórych mikroprocesorów, nie da się ukryć, że współczesne komputery zbudowane w oparciu o procesory pentium zawierają w sobie pewne cechy odziedziczone po procesorze I8080. Niejako metodą indukcji można wnioskować, że w żyłach procesorów pentium (a może należałoby powiedzieć w szynach systemowych) znajdziemy geny zawarte w Z80.
Program binarny stworzony dla procesora I8080 miał być bez problemów akceptowalny przez procesor Z80. Jednak wybrane instrukcje arytmetyczne dawały inny rezultat w rejestrze wskaźników, toteż istnieje metoda programowego wykrycia, czy program jest uruchomiony w systemie zbudowanym w oparciu o mikroprocesor Zilog'a czy Inte'a. Oprócz wprowadzenia wielu użytecznych instrukcji, procesor Z80 odróżniał się od procesora Intel'a wprowadzeniem rejestrów indeksowych pozwalających na rozbudowane sposoby adresowania. Nie bez znaczenia pozostaje fakt, że Z80 jako pierwszy procesor miał zrealizowane sprzętowe odświeżanie pamięci dynamicznych. Po wykonaniu każdej instrukcji następowała realizacja sprzętowego cyklu odświeżenia kolejnego wiersza w pamięciach dynamicznych (numery odświeżanych wierszy są zliczane w specjalnym rejestrze R). Rozwiązywało to wiele problemów konstrukcyjnych w przypadku stosowania pamięci dynamicznych. Obecnie to z pewnością traci na znaczeniu, ponieważ pojemności pamięci statycznych są znacznie większe niż przed wielu laty. W czasach, gdy ten procesor zdobywał rynek dostępne były pamięci statyczne o pojemności do kilku kilobitów (przykładowo rozpowszechnioną pamięcią była 2114, pamięć statyczna 1 kilo x 4 bity), natomiast pamięci dynamiczne 16 kilo x 1 bit nie były niczym niezwykłym.
Zasoby mikroprocesora Z80 (czyli, co ten procek miał do dyspozycji) są następujące:
z80s-i02.png
  • akumulator do 8-bitowych operacji arytmetycznych i logicznych [A],
  • rejestr wskaźników [F],
  • 8-bitowy rejestr B ogólnego przeznaczenia,
  • 8-bitowy rejestr C ogólnego przeznaczenia,
  • 8-bitowy rejestr D ogólnego przeznaczenia,
  • 8-bitowy rejestr E ogólnego przeznaczenia,
  • 8-bitowy rejestr H ogólnego przeznaczenia,
  • 8-bitowy rejestr L ogólnego przeznaczenia,
  • 8-bitowy rejestr I związany z obsługą przerwań maskowalnych,
  • 8-bitowy rejestr R związany z odświeżaniem pamięci dynamicznych,
  • 16-bitowy rejestr indeksowy IX,
  • 16-bitowy rejestr indeksowy IY,
  • 16-bitowy rejestr wskaźnika stosu SP,
  • 16-bitowy rejestr licznika rozkazów PC (ten rejestr jest rejestrem ukrytym i niedostępnym do używania w programie).
Pewną innowacją, która pojawiła się w procesorze Z80 jest zdublowany zespół podstawowych rejestrów (to jest rejestrów A, F, B, C, D, E, H oraz L), mający duże znaczenie w obsłudze przerwań. Procesor posiadał dwa zestawy tych rejestrów, z czego tylko jeden z nich był aktywny. Obsługa przerwania (szczególnie w przypadku gdy nie jest możliwa obsługa przerwań w przerwaniach) używając dwóch instrukcji (EX AF,AF' oraz EXX) mogła przełączyć się na alternatywny zespół rejestrów, dowolnie je używać i przed zakończeniem obsługi przerwania powrócić do poprzedniego, nienaruszonego zestawu rejestrów (bez odkładania rejestrów na stosie).
Wybrane rejestry 8-bitowe mogą być łączone w pary tworząc rejestry 16-bitowe. Możliwe do uzyskania pary rejestrów są następujące:
  • rejestr BC jako połączenie rejestru B i C,
  • rejestr DE jako połączenie rejestru D i E,
  • rejestr HL jako połączenie rejestru H i L.
Tak utworzone pary rejestrów generalnie służą do adresowania pamięci, a w szczególności rejestr HL. Warto tu zauważyć, że mikroprocesor Z80 posiadał instrukcje 16-bitowego dodawania, co jest bardzo pomocne przy obliczaniu adresów w pamięci. Rolę 16-bitowego akumulatora spełniał rejestr HL.
Inną ciekawą cechą procesora Z80 są instrukcje blokowe. Wpisując do odpowiednich rejestrów wymagane dane, można było operować na całym bloku. Jako przykład niech posłuży instrukcja LDIR służąca do przepisania bloku danych z jednego miejsca w drugie. Wymagała ona wpisania do rejestru HL adresu miejsca źródłowego, do rejestru DE adresu miejsca docelowego, do rejestru BC wielkości bloku.

Kod: Zaznacz cały

        LD    HL,<adres z>
        LD    DE,<adres do>
        LD    BC,1000
        LDIR

4 instrukcje zilogowe i mamy przepisane 1000 bajtów z jednego miejsca do drugiego. Na bazie tej instrukcji możne było uzyskać inne wartościowe cechy. Przykładowo poniższy ciąg instrukcji

Kod: Zaznacz cały

        LD    HL,<adres>
        LD    DE,<adres>+1
        LD    BC,1000
        LDIR

powodował replikację zawartości bajtu pamięci o adresie określonym w rejestrze HL w całym obszarze. Taki chwyt powszechnie był używany do zerowania obszarów w pamięci RAM.
Ciekawą cechą mikroprocesora Z80 jest sposób rozwiązania obsługi przerwań. Za pomocą instrukcji IM można było wybrać programowo jeden z trzech możliwych trybów obsługi przerwań. Są to:
  • tryb 0 (po wykonaniu instrukcji IM 0),
  • tryb 1 (po wykonaniu instrukcji IM 1),
  • tryb 2 (po wykonaniu instrukcji IM 2).
Tryb 0
W tym trybie sposób obsługi jest zgodny ze sposobem oferowanym przez procesory I8080. Urządzenie przerywające umieszcza na magistrali danych rozkaz RST <numer>. Przy realizacji tej instrukcji na stosie jest zachowany aktualny stan rejestru licznika instrukcji i następuje skok do odpowiedniego stałego miejsca w pamięci.
Tryb 1
Podobnie jak w dla przerwań niemaskowalnych, procesor odkłada na stosie zawartość licznika rozkazów i realizuje skok do komórki o adresie 38 hex.
Tryb 2
Jest to wektoryzowany i najbardziej efektywny sposób obsługi przerwań. W tym trybie adres procedury obsługi przerwania (jako 16-bitowy adres w pamięci) składa się w części starszej z zawartości rejestru I (związanego z przerwaniami i wcześniej odpowiednio zainicjowanego) oraz w części młodszej z danych dostarczonych poprzez magistralę danych z urządzenia przerywającego (również odpowiednio wcześniej zainicjowanego). Tak ustalony adres jest wskazaniem w pamięci na procedurę obsługi przerwania. Należy tu jednocześnie zauważyć, że w tym trybie obsługi przerwań mikroprocesor mógł współpracować jedynie ze “swoimi” układami (zaprojektowanymi dla Z80). W pewnym sensie obsługa przerwań w tym trybie jest “sprzętowo rozproszona” i sam mikroprocesor musiał umieć “dogadać się” z urządzeniami generującymi przerwanie.
Po sygnale zerowania, mikroprocesor z zablokowanymi przerwaniami maskowalnymi (w trybie IM 0) rozpoczyna pracę od wykonania instrukcji spod adresu 0 w pamięci (co nie jest regułą, bo przykładowo 8086 rusza praktycznie od końca pamięci /dokładniej 16 bajtów przed fizycznym końcem przestrzeni adresowej/). W pierwszej kolejności należy zadbać o właściwie ustawienie wskaźnika stosu SP. Stos ma typową organizację, to znaczy “rośnie w dół”. Każde odłożenie na stos zawartości rejestrów zmniejsza zawartość rejestru SP o 2 (każda instrukcja push i pop dotyczy pary rejestrów [BC, DE, HL, AF – jako złożenie do 16-bitowego rejestru akumulatora A i rejestru wskaźników F]).
Język assemblera Z80 nie odbiega od jakiegokolwiek assemblera innych procesorów. Tak jak wszędzie występują typowe dyrektywy tego języka, jak przykładowo:
  • ORG
  • EQU
  • DEFS
  • DEFB
  • DEFW
Postać wiesza programu źródłowego również ma identyczną postać. Każdy wiersza zawiera zapis instrukcji języka, która może być poprzedzona etykietą, identycznie znak średnika jest używany jako początek komentarza w programie.
Postać instrukcji :arrow: tego tu nie da się wstawić bezpośrednio :(
z80_lista_instrukcji.pdf


Po bliższe i bardziej szczegółowe informacje dotyczące listy instrukcji należy sięgnąć do odpowiedniej literatury.
Na moje półce stoi jeszcze:
z80s-i03.jpg
z80s-i04.jpg
z80s-i05.jpg

a oryginalna cegła zdobi półkę w innym domu :)
z80s-i06.jpg
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony poniedziałek 15 maja 2017, 14:49 przez gaweł, łącznie zmieniany 1 raz.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 12:52

wojtek pisze:Na ostatnim roku studiów jak chodziłem na seminarium z techniki cyfrowej, to wtedy wykładowca, jak największa świętość pokazał z daleka tyle co pozyskany układ Z80 :D

Na podobne zasadzie, gdzieś w połowie studiów, ktoś przemycił z zachodu oryginalny zestaw: I8080, I8224 i I8228. Potem z tego urodziło się ćwiczenie laboratoryjne, gdzie trzeba było z przycisków ustawić adres, dane i zapisać do RAM, bo o EPROMie to przemytnik zapomniał :) . Jak sobie przypomnę, to :lol: masakra. Nie pamiętam, by komuś to ćwiczenie chodziło, bo: skompilować ręcznie kod, wklepać na przyciskach :arrow: nie miało prawa zadziałać, ale zabawy było co niemiara.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » poniedziałek 15 maja 2017, 12:55

Ooo, moje książki masz....

To może taka ciekawostka tylko, bo mnie rysunek z cukierkami cykli maszynowych I/O Read,Write zainspirował...a właściwie podpis szyny adresowej A0..15, a w tekście jest mowa o śmiobitowym adresie ;)

No więc jest taka ciekawostka, że podczas wykonywania instrukcji IN A,(nn) lub OUT (nn), A
procesor powiela adres portu wystawiony via A0...A7 na bitach A8...A15 :)

Podobnie robi dla instrukcji IN rej,(C) oraz OUT (C),rej.

Tu niby adres portu we/wy siedzi w rejestrze C, a tak naprawdę w cyklu maszynowym I/O na szynę adresową wystawiana jest ... zawartość rejestru BC (czy jak kto woli pary B,C). B widać na starszych bitach A8..A15

Jakby się bardzo uprzeć to pewnie można by te starsze bity adresu jakoś użyć - np. do dodatkowego oddziaływania na I/O

źródło: http://www.z80.info/zip/z80-documented.pdf
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 13:10

Narzędzia do tworzenia oprogramowania
Program dla mikroprocesora jest odpowiednim ciągiem bajtów zapisanych w pamięci programu, które są w odpowiedniej kolejności wykonywane. Ciąg tych bajtów, jako kodów instrukcji do wykonania stanowi program w postaci binarnej. Ta forma programu, będąca całkowicie naturalnym rozwiązaniem dla mikroprocesorów jest nieakceptowalna przez ludzi. Może tak się zdarzyć, że ktoś, bardzo uparty, tworzy program od razu w postaci binarnej. Normalna technologia tworzenia oprogramowania sprowadza się do utworzenia pliku tekstowego zawierającego tekst programu zapisany w “języku ludzi”. Pomimo, że tekst programu jest w sformalizowanej formie (język programowania jest takim sformalizowanym językiem), to nadal jednak należy mówić tu o “języku ludzi”. Zapis tekstu programu jest rozumiany przez ludzi, w żadnym wypadku nie jest rozumiany przez mikroprocesory. Z tego powodu powstaje swoista dualność podejścia do tworzenia programów dla mikroprocesorów. Z jednej strony tekst programu jest napisany przez ludzi (w żadnym wypadku nie jest rozumiany przez mikroprocesory) z drugiej strony kod programu rzeczywiście wykonywany przez mikroprocesory nie jest czytelny przez ludzi. Takie podejście do tworzenia programu wymusiło powstanie specjalizowanego oprogramowania, którego zadaniem jest tłumaczenie z jednego zapisu na drugi zapis. Taką funkcję tłumacza właśnie spełniają kompilatory.
Kompilator jest programem, który tłumaczy zapis z określonego języka programowania na ciąg kodów dla danego mikroprocesora. Odpowiednikiem kompilatora w świecie ludzi jest tłumacz z jednego języka na drugi. Nietrudno jest tu zauważyć, że istotnym elementem jest tu wierność tłumaczenia. W przypadku prostych i podstawowych języków programowania wierność tłumaczenia nie jest dużym problemem, w przypadku bardziej złożonych języków nie jest to już zagadnienie trywialne. W obecnych czasach jakość kompilatorów jest na tyle dobra, że należy przyjąć, że tłumaczenie programu z zapisu źródłowego na program binarny jest wierne. Zdarzyło mi się w mojej karierze, że kompilator błędnie przetłumaczył mój zapis na postać binarną. Efektem tego jest to, że program robi co innego, niż ja wymagałem. Obecnie jednak rozbieżność pomiędzy tym, co wykonuje mikroprocesor a zamierzeniami programisty raczej spowodowane jest przez programistów.
Jako ilustracja powyższego niech posłuży następująca instrukcja:
LD A,12h
nakazująca wpisać do rejestru A liczbę o wartości 12h (h – oznacza zapis szesnastkowy). Kompilator tą instrukcję powinien przetłumaczyć na dwa bajty:
00111110 oraz 00010010 (w zapisie binarnym) lub 3E oraz 12 (w zapisie szesnastkowym). W tym przypadku zadanie było wręcz proste. W odpowiedniej dokumentacji można znaleźć kody wszystkich instrukcji mikroprocesora. Instrukcja LD A,... ma kod 00111110 (3E hex) oraz w dalszej części występuje wartość użytego operandu (w tym przykładzie jest to stała o wartości 12 hex). Znacznie bardziej komplikuje się sprawa tłumaczenia przykładowo w przypadku instrukcji skoku.
Instrukcja:
JP etykieta
jest tłumaczona następująco: 11000011 (C3 hex – bo taki jest kod instrukcji JP) i w dalszej kolejności należy podać adres w pamięci miejsca oznaczonego podaną jako parametr etykietą. Drogą uciążliwego odliczania bajtów można określić wymagany adres, jednak w przypadku jakiejkolwiek małej poprawki w programie, miejsce oznaczone wskazaną etykietą może ulec zmianie i należy poprzez uciążliwe obliczenia określić nową wartość adresu, który jest przypisany etykiecie. Ta faza tworzenia oprogramowania nie należy do zbytnio atrakcyjnych.
Człowiek powinien skupić się nad istotą programu a nie zajmować się “tak przyziemnymi problemami”. Do tego właśnie służą kompilatory i trzeba przyznać, że robią to bardzo dobrze. Pomijając fakt, że ręczne tłumaczenie programu na kod binarny nie należy do zajęć zbyt fascynujących, to bardzo duże znaczenie w tej fazie odgrywa wierność tłumaczenia, a człowiek ... wiadomo, istota omylna, źle obliczy adres skoku ... i mikroprocesor to wykona. Trzeba pamiętać, że mikroprocesor nie znudzi się, nie zdenerwuje się tylko z całkowitym spokojem będzie wykonywał polecenia nawet najgłupsze i “nawet powieka mu nie drgnie”. Dlatego istotnym czynnikiem jest wierność tłumaczenia programu źródłowego na postać binarną.
Zaczynając swoją przygodę z mikroprocesorem nie było dostępu do sieci komputerowej. Nie istniała możliwość ściągnięcia sobie z internetu odpowiedniego oprogramowania narzędziowego. Chęć zabawy z mikroprocesorami, a niejako efektem ubocznym tego jest potrzeba tworzenia oprogramowania, była na tyle duża, że doprowadziła do napisania własnego programu spełniającego funkcje kompilatora. Obecnie raczej nikt nie tworzy od podstaw narzędzi służących do produkowania oprogramowania. Mając dostęp do ogromnych zasobów jaki daje internet, nie jest to celowe i uzasadnione, jednak w czasach świetności mikroprocesora Z80 panowały całkowicie odmienne realia.
Trzeba było jakoś sobie radzić. Napisałem własny kompilator asemblera na PC-cie, pod DOS'em (w windozie nikt jeszcze nie słyszał) w TURBO PASCAL'u.
Tekst programu zachował się mi do dzisiaj :) . Jest taki:

Kod: Zaznacz cały

(***************************************************************************
 ***************************************************************************
 **                                                                       **
 **                         BIALYSTOK  1987 r.                            **
 **                         Andrzej Pawluczuk                             **
 **                                                                       **
 **           Kompilator jezyka assembler mikroprocesora Z-80             **
 **                          Wersja : 1.02                                **
 **                                                                       **
 ***************************************************************************
 ***************************************************************************)

program Z80_Compiler ;
        (*
            Program kompilatora jezyka Z-80 dziala zasadniczo w nastepujacy
            sposob :
              *** wczytuje od uzytkownika nazwy plikow
              *** wczytuje plik programu zrodlowego budujac w pamieci
                  liste wskaznikowa zawierajaca kolejne wiersze programu
              *** kompiluje program poslugujac sie wczytana lista
                  wierszy programu zrodlowego
              *** generuje raport kompilatora
              *** zapisuje wygenerowany kod do zbioru

            Generowany kod umieszczany jest w odpowiedniej tablicy wskaznikowej
            zawierajacej jako elementy tablice po 256 bajtow wygenerowanego
            kodu. Z tablicami kodu zwiazana jest tablica zawierajaca tzw.
            przelaczniki kodu (informacje o tym, czy kod jest wygenerowany
            przez kompilator, czy tez stanowi puste miejsce powstale poprzez
            odpowiednie manipulowanie dyrektywa ORG.
            Podczas analizy zbioru zrodlowego (w zaleznosci od zawartosci
            zmiennej CrossSwitch) tworzona jest lista typu CROSS REFERENCE.
            Jest to lista zawierajaca nazwy indentyfikatorow zdefiniowanych
            przez uzytkownika wraz z numerami wierszy programu zrodlowego,
            w ktorych wystapily te identyfikatory.
        *)

  uses dos , crt ;

  const
    Space               = ' ' ;     (* stala o wartosci spacji *)
    KeyLength           = 16 ;      (* dopuszczalna dlugosc identyfikatorow *)
    RecordLength        = 80 ;      (* dopuszczalna dlugosc wiersza programu
                                       zrodlowego *)
    MaxErrors           = 6 ;       (* dopuszczalna liczba bledow zglaszanych
                                       w jednym wierszu programu zrodlowego *)
    BytesInLine         = 5 ;       (* liczba bajtow kodu drukowanych w jednym
                                       wierszu w raporcie kompilatora *)


  type
    Ident               = string [ KeyLength ] ;
                                    (* typ identyfikatora *)
    SymbolType          = ( Nosy           ,IntConstSy     ,StringSy       ,
                            IdentSy        ,ColonSy        ,SemicolonSy    ,
                            CommaSy        ,LeftParSy      ,RightParSy     ,
                            AphostrSy      ,SubOpSy        ,AddOpSy        ,
                            EndLineSy      ,
                            ASy            ,BSy            ,CSy            ,
                            DSy            ,ESy            ,HSy            ,
                            LSy            ,ISy            ,RSy            ,
                            AFSy           ,BCSy           ,DESy           ,
                            HLSy           ,SPSy           ,IXSy           ,
                            IYSy           ,
                            ZSy            ,NZSy           ,NCSy           ,
                            POSy           ,PESy           ,PSy            ,
                            MSy            ,PCSy           ,
                            ORGSy          ,EQUSy          ,DEFLSy         ,
                            DEFMSy         ,DEFSSy         ,DEFBSy         ,
                            DEFWSy         ,ENDSy          ,GLOBALSy       ,
                            NAMESy         ,PSECTSy        ,MACRSy         ,
                            ENDMSy         ,LDSy           ,PUSHSy         ,
                            POPSy          ,EXSy           ,EXXSy          ,
                            LDISy          ,LDIRSy         ,LDDSy          ,
                            LDDRSy         ,CPISy          ,CPIRSy         ,
                            CPDSy          ,CPDRSy         ,ADDSy          ,
                            ADCSy          ,SUBSy          ,SBCSy          ,
                            ANDSy          ,ORSy           ,XORSy          ,
                            CPSy           ,INCSy          ,DECSy          ,
                            DAASy          ,CPLSy          ,NEGSy          ,
                            CCFSy          ,SCFSy          ,NOPSy          ,
                            HALTSy         ,DISy           ,EISy           ,
                            IMSy           ,RLCASy         ,RLASy          ,
                            RRCASy         ,RRASy          ,RLCSy          ,
                            RLSy           ,RRCSy          ,RRSy           ,
                            SLASy          ,SRASy          ,SRLSy          ,
                            RLDSy          ,RRDSy          ,BITSy          ,
                            SETSy          ,RESSy          ,JPSy           ,
                            JRSy           ,DJNZSy         ,CALLSy         ,
                            RETSy          ,RETISy         ,RETNSy         ,
                            RSTSy          ,INSy           ,INIRSy         ,
                            INISy          ,INDRSy         ,INDSy          ,
                            OUTSy          ,OUTISy         ,OTIRSy         ,
                            OUTDSy         ,OTDRSy         ,EndDictSy      ) ;
                                    (* typ wyliczeniowy symboli jezyka *)
    Address             = record
                            HighByte       : byte ;
                            LowByte        : byte ;
                          end (* record *) ;
                                    (* typ reprezentujacy adresy
                                       (np. etykiet,kodu) *)
    LineRecordType      = string [ RecordLength ] ;
                                    (* typ reprezentujacy tresc rekordu
                                       programu zrodlowego *)
    IdentifiersPointer  = ^ IdentifierRecord ;
                                    (* typ reprezentujacy liste identyfikatorow *)
    LineRecordPointer   = ^ LineRecord ;
                                    (* typ reprezentujacy liste rekordow
                                       programu zrodlowego *)
    LineRecord          = record    (* typ reprezentujacy rekod programu zrodlowego *)
                            LineNumber      : integer ; (* numer linii wiersza
                                                           programu zrodlowego *)
                            MyAddress       : Address ; (* adres w kompilowanym
                                                           programie zwiazany z
                                                           biezacym wierszem
                                                           zrodlowym *)
                            MySize          : byte ;    (* liczba bajtow
                                                           zwiazanych z rekordem
                                                           zrodlowym *)
                            PrintAddessOnly : boolean ; (* czy dla biezacego
                                                           wiersza w raporcie
                                                           drukowac adres *)
                            SourceLine      : LineRecordType ;
                                                        (* tekst wiersza programu *)
                            ErrorCounter    : byte ;    (* liczba zgloszonych
                                                           bledow dla wiersza *)
                            Errors          : array [ 1 .. MaxErrors ] of byte ;
                                                        (* tablica kodow bledow
                                                           zgloszonych dla wiersza *)
                            NextLine        : LineRecordPointer ;
                                                        (* wskaznik do nastepnego
                                                           wiersza programu
                                                           zrodlowego *)
                          end (* record *) ;
    MissingsPointer     = ^ MissingPointerRecord ;
                                    (* typ reprezentujacy liste brakujacych
                                       etykiet (jeszcze nienapotkanych) *)
    MissingPointerRecord= record    (* typ elementu listy brakujacych etykiet *)
                            MissingAddress : Address ;
                                              (* adres w kodzie, w ktorym nalezy
                                                 wstawic adres etykiety *)
                            LinePointer    : LineRecordPointer ;
                                              (* dowiazanie do rekordu zrodlowego
                                                 wystapienia brakujacej etykiety *)
                            Relative       : boolean ;
                                              (* czy odwolanie do etykiety jest
                                                 relatywne *)
                            Displacement   : integer ;
                                              (* przesuniecie etykiety *)
                            NextMissing    : MissingsPointer ;
                                              (* wskaznik do nastepnego elementu
                                                 listy *)
                          end (* record *) ;
    ClassType           = ( ConstClass , LabelClass ) ;
                                    (* typ reprezentujacy klase identyfikatora *)
    ReferencePointer    = ^ ReferenceRecord ;
                                    (* typ reprezentujacy liste wystapien
                                       okreslonego identyfikatora
                                       dla potrzeb CROSS REFERENCE *)
    ReferenceRecord     = record    (* typ elementu listy CROSS REFERENCE *)
                            LineNo         : integer ;
                                                (* numer wiersza wystapienia
                                                   identyfikatora *)
                            NextReference  : ReferencePointer ;
                                                (* wskaznik do nastepnego
                                                   elementu *)
                          end (* record *) ;
    CrossRecordPointer  = ^ CrossRecord ;
                                    (* typ reprezentujacy liste identyfikatorow
                                       dla potrzeb CROSS REFERENCE *)
    CrossRecord         = record    (* element listy CROSS REFERENCE w ukladzie
                                       drzewa binarnego *)
                            KeyName        : Ident ;
                                                (* nazwa identyfikatora *)
                            First          : ReferencePointer ;
                                                (* lista wystapien idedentyfikatora *)
                            Left           : CrossRecordPointer ;
                                                (* wskaznik do nastepnych elementow *)
                            Right          : CrossRecordPointer ;
                                                (* wskaznik do nastepnych elementow *)
                          end (* record *) ;
    IdentifierRecord    = record    (* typ reprezentujacy opis identyfikatora *)
                            IdentName      : Ident ;  (* nazwa identyfikatora *)
                            NextIdent      : IdentifiersPointer ;
                                                      (* wskaznik do nastepnego
                                                         elementu listy
                                                         identyfikatorow *)
                            case Class     : ClassType of
                                                      (* rodzaj identyfikatora *)
                              ConstClass :            (* STALA *)
                                ( ConstValue   : integer ) ;
                                                      (* wartosc stalej *)
                              LabelClass :            (* ETYKIETA *)
                                ( LabelAddress : Address ;
                                                      (* adres etykiety *)
                                  Defined      : boolean ;
                                                      (* czy etykieta jest
                                                         zdefiniowana *)
                                  MissingLink  : MissingsPointer )
                                                      (* lista brakujacych
                                                         odwolan do etykiety *)
                          end (* record *) ;
    CodeArray           = array [ byte ] of byte ;
                                    (* typ reprezentujacy tablice na generowany kod *)
    CodeArrayPointer    = ^ CodeArray ;
    PointerToCodeArray  = array [ byte ] of CodeArrayPointer ;
    CodeSwitchArray     = array [ byte ] of boolean ;
                                    (* typ reprezentujacy tablica na wskazniki,
                                       czy kod jest wygenerowany przez kompilator,
                                       czy stanowi przeskok w kodzie poprzez
                                       dyrektywe ORG *)
    CodeSwitchArrayPointer
                        = ^ CodeSwitchArray ;
    PointerToCodeSwitchArray
                        = array [ byte ] of CodeSwitchArrayPointer ;
    KeysType            = array [ ASy .. EndDictSy ] of Ident ;
                                    (* typ reprezentujacy tablice slow
                                       kluczowych jezyka *)
    CharSymbolType      = array [ #0 .. #127 ] of SymbolType ;
                                    (* typ reprezentujacy tablice symboli
                                       jezyka *)
    FileName            = string [ 32 ] ;
                                    (* typ reprezentujacy nazwy plikow *)
    DateString          = string [ 10 ] ;
                                    (* typ reprezentujacy date /znakowo/ *)
    TimeString          = string [ 8 ] ;
                                    (* typ reprezentujacy czas /znakowo/ *)
    String2             = string [ 2 ] ;

  var
    TopSourceLineEntry  : LineRecordPointer ;
                                    (* zmienna zawierajaca szczyt listy wierszy
                                       zrodlowych programu *)
    TopIdentifiers      : IdentifiersPointer ;
                                    (* zmienna zawierajaca szczyt listy identy-
                                       fikatorow napotkanych w programie
                                       zrodlowym *)
    TopCross            : CrossRecordPointer ;
                                    (* zmienna zawierajaca szczyt listy typu
                                       CROSS REFERENCE *)
    CodeMatrix          : PointerToCodeArray ;
                                    (* zmienna zawierajaca szczyt listy
                                       tablic kodu *)
    CodeSwitch          : PointerToCodeSwitchArray ;
                                    (* zmienna zawierajaca szczyt listy
                                       tablic przelacznikow kodu *)
    SourceFile          : text ;    (* zmienna plikowa pliku programu zrodlowego *)
    CompilationOutput   : text ;    (* zmienna plikowa pliku raportu kompilatora *)
    CodeOutput          : file of byte ;
                                    (* zmienna plikowa pliku generowanego kodu *)
    CrossSwitch         : boolean ; (* zmienna okreslajaca zadanie tworzenia
                                       listy typu CROSS REFERENCE *)
    AddressPointer      : Address ; (* zmienna zawierajaca biezacy adres
                                       generowanego kodu *)
    LineCounterOnPage   : integer ; (* zmienna zawierajaca licznik wierszy
                                       wyprowadzanych do pliku raportu kompilatora *)
    PageCounter         : integer ; (* zmienna zawierajaca licznik stron
                                       raportu kompilatora *)
    NormalCursor        : integer ; (* zmienna zawierajaca informacje dla
                                       BIOS o postaci normalnego kursora na
                                       ekranie *)
    GlobalErrorCounter  : integer ; (* zmienna zawierajaca licznik wszystkich
                                       bledow zgloszonych przez kompilator *)
    InPutFileName       : FileName ;(* zmienna zawierajaca nazwe pliku z
                                       programem zrodlowym *)
    CompilationOutputFileName
                        : FileName ;(* zmienna zawierajaca nazwe pliku na
                                       raport kompilatora z procesu kompilacji *)
    CodeOutputFileName  : FileName ;(* zmienna zawierajaca nazwe pliku na
                                       generowany kod *)
    Date                : DateString ;
                                    (* zmienna zawierajaca biezaca date *)
    Time                : TimeString ;
                                    (* zmienna zawierajaca biezaca godzine *)

  const
    Keys : KeysType = (
                            'A'            ,'B'            ,'C'            ,
                            'D'            ,'E'            ,'H'            ,
                            'L'            ,'I'            ,'R'            ,
                            'AF'           ,'BC'           ,'DE'           ,
                            'HL'           ,'SP'           ,'IX'           ,
                            'IY'           ,'Z'            ,'NZ'           ,
                            'NC'           ,'PO'           ,'PE'           ,
                            'P'            ,'M'            ,'$'            ,
                            'ORG'          ,'EQU'          ,'DEFL'         ,
                            'DEFM'         ,'DEFS'         ,'DEFB'         ,
                            'DEFW'         ,'END'          ,'GLOBAL'       ,
                            'NAME'         ,'PSECT'        ,'MACR'         ,
                            'ENDM'         ,'LD'           ,'PUSH'         ,
                            'POP'          ,'EX'           ,'EXX'          ,
                            'LDI'          ,'LDIR'         ,'LDD'          ,
                            'LDDR'         ,'CPI'          ,'CPIR'         ,
                            'CPD'          ,'CPDR'         ,'ADD'          ,
                            'ADC'          ,'SUB'          ,'SBC'          ,
                            'AND'          ,'OR'           ,'XOR'          ,
                            'CP'           ,'INC'          ,'DEC'          ,
                            'DAA'          ,'CPL'          ,'NEG'          ,
                            'CCF'          ,'SCF'          ,'NOP'          ,
                            'HALT'         ,'DI'           ,'EI'           ,
                            'IM'           ,'RLCA'         ,'RLA'          ,
                            'RRCA'         ,'RRA'          ,'RLC'          ,
                            'RL'           ,'RRC'          ,'RR'           ,
                            'SLA'          ,'SRA'          ,'SRL'          ,
                            'RLD'          ,'RRD'          ,'BIT'          ,
                            'SET'          ,'RES'          ,'JP'           ,
                            'JR'           ,'DJNZ'         ,'CALL'         ,
                            'RET'          ,'RETI'         ,'RETN'         ,
                            'RST'          ,'IN'           ,'INIR'         ,
                            'INI'          ,'INDR'         ,'IND'          ,
                            'OUT'          ,'OUTI'         ,'OTIR'         ,
                            'OUTD'         ,'OTDR'         ,'**************' ) ;
                                    (* zmienna zawierajaca tablica slow
                                       kluczowych jezyka *)
    CharSymbol : CharSymbolType = (
               NoSy           , (* Ctrl-@ *) NoSy           , (* Ctrl-A *)
               NoSy           , (* Ctrl-B *) NoSy           , (* Ctrl-C *)
               NoSy           , (* Ctrl-D *) NoSy           , (* Ctrl-E *)
               NoSy           , (* Ctrl-F *) NoSy           , (* Ctrl-G *)
               NoSy           , (* Ctrl-H *) NoSy           , (* Ctrl-I *)
               NoSy           , (* Ctrl-J *) NoSy           , (* Ctrl-K *)
               NoSy           , (* Ctrl-L *) NoSy           , (* Ctrl-M *)
               NoSy           , (* Ctrl-N *) NoSy           , (* Ctrl-O *)
               NoSy           , (* Ctrl-P *) NoSy           , (* Ctrl-Q *)
               NoSy           , (* Ctrl-R *) NoSy           , (* Ctrl-S *)
               NoSy           , (* Ctrl-T *) NoSy           , (* Ctrl-U *)
               NoSy           , (* Ctrl-V *) NoSy           , (* Ctrl-W *)
               NoSy           , (* Ctrl-X *) NoSy           , (* Ctrl-Y *)
               NoSy           , (* Ctrl-Z *) NoSy           , (* Ctrl-[ *)
               NoSy           , (* Ctrl-\ *) NoSy           , (* Ctrl-] *)
               NoSy           , (* Ctrl-^ *) NoSy           , (* Ctrl-_ *)
               SemicolonSy    , (* Space  *) NoSy           , (* !      *)
               NoSy           , (* "      *) NoSy           , (* #      *)
               PCSy           , (* $      *) NoSy           , (* %      *)
               NoSy           , (* &      *) AphostrSy      , (* '      *)
               LeftParSy      , (* (      *) RightParSy     , (* )      *)
               NoSy           , (* *      *) AddOpSy        , (* +      *)
               CommaSy        , (* ,      *) SubOpSy        , (* -      *)
               NoSy           , (* .      *) NoSy           , (* /      *)
               IntConstSy     , (* 0      *) IntConstSy     , (* 1      *)
               IntConstSy     , (* 2      *) IntConstSy     , (* 3      *)
               IntConstSy     , (* 4      *) IntConstSy     , (* 5      *)
               IntConstSy     , (* 6      *) IntConstSy     , (* 7      *)
               IntConstSy     , (* 8      *) IntConstSy     , (* 9      *)
               ColonSy        , (* :      *) SemicolonSy    , (* ;      *)
               NoSy           , (* <      *) NoSy           , (* =      *)
               NoSy           , (* >      *) NoSy           , (* ?      *)
               NoSy           , (* @      *) IdentSy        , (* A      *)
               IdentSy        , (* B      *) IdentSy        , (* C      *)
               IdentSy        , (* D      *) IdentSy        , (* E      *)
               IdentSy        , (* F      *) IdentSy        , (* G      *)
               IdentSy        , (* H      *) IdentSy        , (* I      *)
               IdentSy        , (* J      *) IdentSy        , (* K      *)
               IdentSy        , (* L      *) IdentSy        , (* M      *)
               IdentSy        , (* N      *) IdentSy        , (* O      *)
               IdentSy        , (* P      *) IdentSy        , (* Q      *)
               IdentSy        , (* R      *) IdentSy        , (* S      *)
               IdentSy        , (* T      *) IdentSy        , (* U      *)
               IdentSy        , (* V      *) IdentSy        , (* W      *)
               IdentSy        , (* X      *) IdentSy        , (* Y      *)
               IdentSy        , (* Z      *) NoSy           , (* [      *)
               NoSy           , (* \      *) NoSy           , (* ]      *)
               NoSy           , (* ^      *) NoSy           , (* _      *)
               NoSy           , (* `      *) IdentSy        , (* a      *)
               IdentSy        , (* b      *) IdentSy        , (* c      *)
               IdentSy        , (* d      *) IdentSy        , (* e      *)
               IdentSy        , (* f      *) IdentSy        , (* g      *)
               IdentSy        , (* h      *) IdentSy        , (* i      *)
               IdentSy        , (* j      *) IdentSy        , (* k      *)
               IdentSy        , (* l      *) IdentSy        , (* m      *)
               IdentSy        , (* n      *) IdentSy        , (* o      *)
               IdentSy        , (* p      *) IdentSy        , (* q      *)
               IdentSy        , (* r      *) IdentSy        , (* s      *)
               IdentSy        , (* t      *) IdentSy        , (* u      *)
               IdentSy        , (* v      *) IdentSy        , (* w      *)
               IdentSy        , (* x      *) IdentSy        , (* y      *)
               IdentSy        , (* z      *) NoSy           , (* {      *)
               NoSy           , (* |      *) NoSy           , (* }      *)
               NoSy           , (* ~      *) NoSy             (* DEL    *) ) ;
                                    (* zmienna zawierajaca tablice symboli
                                       jezyka *)


  const
    MPType  : string [ 4 ] = 'Z-80' ;
    Version : string [ 4 ] = '1.03' ;

procedure Check ( var Checkedstring : String2 ) ;

  begin (* Check *)
    if length ( Checkedstring ) < 2 then
      insert ( '0' , Checkedstring , 1 ) ;
  end (* Check *) ;


procedure GiveDateStr ( var OutDateString : DateString ) ;

          (* procedura pobiera od DOS aktualna date i przekazuja ja w
             postaci znakowej *)
  var
    recpack                 : Registers ;
    month                   : String2 ;
    day                     : String2 ;
    year                    : string[4] ;

 begin (* GiveDateStr *)
   recpack . ax := $2a shl 8 ;
   msdos ( recpack ) ;
   with recpack do
     begin (* 1 *)
       str ( cx , year ) ;
       str ( dx mod 256 , day ) ;
       str ( dx shr 8 , month ) ;
     end (* 1 *) ;
   Check ( month ) ;
   Check ( day ) ;
   OutDateString := concat ( year , '.' , month , '.' , day ) ;
 end (* GiveDateStr *) ;


procedure GiveTimeStr ( var OutTimeString : TimeString ) ;

          (* procedura pobiera od DOS aktualna godzina i przekazuja ja w
             postaci znakowej *)
  var
    recpack                 : Registers ;
    hour                    : String2 ;
    minute                  : String2 ;
    second                  : String2 ;

  begin (* GiveTimeStr *)
    recpack . ax := $2c00 ;
    intr ( $21 , recpack ) ;
    with recpack do
      begin (* 1 *)
        str ( hi ( cx ) , hour ) ;
        str ( lo ( cx ) , minute ) ;
        str ( hi ( dx ) , second ) ;
      end (* 1 *) ;
    Check ( hour ) ; Check ( minute ) ; Check ( second ) ;
    OutTimeString := concat ( hour , ':' , minute , ':' , second ) ;
  end (* GiveTimeStr *) ;


procedure SetCursorOff ;

          (* procedura wylacza korsor na ekranie *)
  var
    RegistersArea       : Registers ;

  begin (* SetCursorOff *)
    with RegistersArea do
      begin (* 1 *)
        ax := $0100 ;
        cx := $f000 ;
      end (* 1 *) ;
    intr ( $10 , RegistersArea ) ;
  end (* SetCursorOff *) ;


procedure SetNormalCursor ;

          (* procedura wlacza normalny kursor na ekranie *)
  var
    RegistersArea       : Registers ;

  begin (* SetNormalCursor *)
    with RegistersArea do
      begin (* 1 *)
        ax := $0100 ;
        cx := NormalCursor ;
      end (* 1 *) ;
    intr ( $10 , RegistersArea ) ;
  end (* SetNormalCursor *) ;


procedure InitListing ;

          (* procedura inicjuje zawartosc ekranu na poczatku programu *)
  var
    Reg                 : Registers ;

  begin (* InitListing *)
    GiveDateStr ( Date ) ;
    GiveTimeStr ( Time ) ;
    clrscr ;
    writeln ( '╔═════════════════════════════════════════════════════════════════════════════╗' ) ;
    write   ( '║     Kompilator jezyka assembler dla mikroprocesora ' ) ;
    write ( MPType ) ;
    writeln ( '       ver.:1.02     ║' ) ;
    write   ( '║     Copyright (C) Gawel  Bialystok 1988  Data : ' ) ;
    writeln ( Date , '  godz. ' , Time , '  ║' ) ;
    writeln ( '╚═════════════════════════════════════════════════════════════════════════════╝' ) ;
    window ( 1 , 6 , 80 , 25 ) ;
    intr ( $11 , Reg ) ;
    if ( Reg . ax and 48 ) = 48 then
      NormalCursor := $0C0D
    else
      NormalCursor := $0607 ;
    clrscr ;
  end (* InitListing *) ;


procedure StartData ;

          (* procedura inicjuje zawartosci zmiennych programu *)
  var
    Index               : integer ;

  begin (* StartData *)
    for Index := 0 to 255 do
      CodeMatrix [ Index ] := nil ;
    for Index := 0 to 255 do
      CodeSwitch [ Index ] := nil ;
    CrossSwitch := true ;
    TopSourceLineEntry := nil ;
    TopCross := nil ;
    TopIdentifiers := nil ;
    AddressPointer . HighByte := 0 ;
    AddressPointer . LowByte := 0 ;
    LineCounterOnPage := 200 ;
    PageCounter := 0 ;
    InputFileName := '' ;
    CompilationOutputFileName := '' ;
    CodeOutputFileName := '' ;
    GlobalErrorCounter := 0 ;
  end (* StartData *) ;


procedure ReadFileNames ;

          (* procedura wczytuje od uzytkownika nazwy plikow *)
  const
    OptionNumber        = 5 ;
    OptionLength        = 56 ;
    Displacement        = 4 ;

  type
    OneOptionName       = string [ OptionLength ] ;
    OptionName          = array [ 1 .. OptionNumber ] of OneOptionName ;

  var
    OptionCounter       : integer ;
    Arrow               : char ;
    StartOption         : integer ;
    NameKern            : FileName ;

  const
    Option : OptionName =
                ( ' okreslenie zbioru wejsciowego (program zrodlowy)   ' ,
                  ' okreslenie zbioru wyjsciowego (raport kompilatora) ' ,
                  ' okreslenie zbioru wyjsciowego (generowany kod)     ' ,
                  ' rozpoczecie kompilacji programu                    ' ,
                  ' wyjscie do DOS                                     ' ) ;

  procedure ReadArrow ( var Character : char ) ;

    begin (* ReadArrow *)
      Character := ReadKey ;
      if Character = #0 then
        Character := ReadKey
      else
        if Character = ^M then
          Character := 'O'
        else
          Character := ' ' ;
    end (* ReadArrow *) ;

  procedure PrintNormalText ( Option   : OneOptionName ;
                              OptionNo : integer ) ;

    begin (* PrintNormalText *)
      normvideo ;
      gotoxy ( 2 , OptionNo + Displacement ) ;
      write ( Option ) ;
    end (* PrintNormalText *) ;

  procedure PrintInvertText ( Option   : OneOptionName ;
                              OptionNo : integer ) ;

    begin (* PrintInvertText *)
      textcolor ( black ) ;
      textBackground ( white ) ;
      gotoxy ( 2 , OptionNo + Displacement ) ;
      write ( Option ) ;
    end (* PrintInvertText *) ;

  procedure OptionQuestion ( OptionNo : integer ) ;

    var
      Answer            : char ;

    begin (* OptionQuestion *)
      OptionCounter := OptionNo ;
      PrintInvertText ( Option [ OptionCounter ] , OptionCounter ) ;
      StartOption := OptionNo ;
      gotoxy ( 2 , 18 ) ;
      normvideo ;
      write ( 'Nazwa zbioru jest pusta.  Czy konczyc prace (t/n) ? :' ) ;
      SetNormalCursor ;
      repeat
        Answer := ReadKey ;
        Answer := UpCase ( Answer ) ;
      until ( Answer = 'T' ) or ( Answer = 'N' ) ;
      SetCursorOff ;
      if Answer = 'T' then
        begin (* 1 *)
          SetNormalCursor ;
          window ( 1 , 1 , 80 , 25 ) ;
          clrscr ;
          halt ;
        end (* 1 *) ;
      gotoxy ( 2 , 18 ) ;
      clreol ;
    end (* OptionQuestion *) ;

  procedure PrintFileNames ;

    procedure Print ( Name : FileName ; Position : integer ) ;

      begin (* Print *)
        gotoxy ( 60 , Position + Displacement ) ;
        clreol ;
        write ( '"' , Name , '"' ) ;
      end (* Print *) ;

    begin (* PrintFileNames *)
      normvideo ;
      Print ( InputFileName , 1 ) ;
      Print ( CompilationOutputFileName , 2 ) ;
      Print ( CodeOutputFileName , 3 ) ;
    end (* PrintFileNames *) ;

  procedure ReadFileName ( var Name : FileName ) ;

    var
      WorkName          : FileName ;
      Index             : integer ;

    begin (* ReadFileName *)
      gotoxy ( 1 , 15 ) ;
      write ( 'Podaj nazwe zbioru : ' ) ;
      SetNormalCursor ;
      repeat
        gotoxy ( 21 , 15 ) ;
        readln ( Name ) ;
        WorkName := '' ;
        for Index := 1 to length ( Name ) do
          if Name [ Index ] <> ' ' then
            WorkName := concat ( WorkName , UpCase ( Name [ Index ] ) ) ;
      until WorkName <> 'CON' ;
      gotoxy ( 1 , 15 ) ;
      clreol ;
      SetCursorOff ;
    end (* ReadFileName *) ;

  procedure ReadInputFileName ;

    var
      Index             : integer ;
      WorkName          : FileName ;
      InputFile         : text ;

    procedure NormalyseFileName ;

      var
        Index           : integer ;
        NameSize        : integer  ;
        Ch              : char ;
        Name            : FileName ;
        NotComplete     : boolean ;

      begin (* NormalyseFileName *)
        NameSize := length ( InputFileName ) ;
        NameKern := '' ;
        if NameSize > 0 then
          begin (* 1 *)
            Name := '' ;
            for Index := 1 to NameSize do
              begin (* 2 *)
                Ch := InputFileName [ Index ] ;
                if Ch <> ' ' then
                  Name := concat ( Name , Ch ) ;
              end (* 2 *) ;
            InputFileName := Name ;
            NameSize := length ( InputFileName ) ;
            Name := '' ;
            NotComplete := true ;
            for Index := 1 to NameSize do
              begin (* 2 *)
                Ch := InputFileName [ Index ] ;
                if Ch = '.' then
                  NotComplete := false
                else
                  if NotComplete then
                    Name := concat ( Name , Ch ) ;
              end (* 2 *) ;
            NameKern := Name ;
          end (* 1 *) ;
      end (* NormalyseInputFileName *) ;

    begin (* ReadInputFileName *)
      ReadFileName ( InputFileName ) ;
      NormalyseFileName ;
      WorkName := '' ;
      for Index := 1 to length ( InputFileName ) do
        WorkName := concat ( WorkName , UpCase ( InputFileName [ Index ] ) ) ;
      Assign ( InputFile , InputFileName ) ;
      (*$I-*)
      reset ( InputFile ) ;
      if ioresult <> 0 then
        begin (* 2 *)
          gotoxy ( 1 , 16 ) ;
          write ( 'Podany zbior nie istnieje...nacisnij ENTER' ) ;
          readln ;
          gotoxy ( 1 , 16 ) ;
          clreol ;
          InputFileName := '' ;
          NameKern := '' ;
        end (* 1 *)
      else
        close ( InputFile ) ;
      (*$I+*)
      if NameKern <> '' then
        begin (* 1 *)
          StartOption := 4 ;
          CompilationOutputFileName := concat ( NameKern , '.LST' ) ;
          CodeOutputFileName := concat ( NameKern , '.COD' ) ;
        end (* 1 *) ;
    end (* ReadInputFileName *) ;

  begin (* ReadFileNames *)
    clrscr ;
    StartOption := 1 ;
    repeat
      SetCursorOff ;
      for OptionCounter := 1 to OptionNumber do
        PrintNormalText ( Option [ OptionCounter ] , OptionCounter ) ;
      OptionCounter := StartOption ;
      PrintInvertText ( Option [ OptionCounter ] , optionCounter ) ;
      PrintFileNames ;
      repeat
        ReadArrow ( Arrow ) ;
        if Arrow = 'P' then
          begin (* 1 *)
            PrintNormalText ( Option [ OptionCounter ] , OptionCounter ) ;
            OptionCounter := succ ( OptionCounter ) ;
            if OptionCounter > OptionNumber then
              OptionCounter := 1 ;
            PrintInvertText ( Option [ OptionCounter ] , OptionCounter ) ;
          end (* 1 *) ;
        if Arrow = 'H' then
          begin (* 1 *)
            PrintNormalText ( Option [ OptionCounter ] , OptionCounter ) ;
            OptionCounter := pred ( OptionCounter ) ;
            if OptionCounter < 1 then
              OptionCounter := OptionNumber ;
            PrintInvertText ( Option [ OptionCounter ] , OptionCounter ) ;
          end (* 1 *) ;
      until Arrow = 'O' ;
      normvideo ;
      case OptionCounter of
        1 : ReadInputFileName ;
        2 : ReadFileName ( CompilationOutputFileName ) ;
        3 : ReadFileName ( CodeOutputFileName ) ;
        4 : begin (* 1 *)
              PrintNormalText ( Option [ OptionCounter ] , OptionCounter ) ;
              if InputFileName = '' then
                OptionQuestion ( 1 )
               else
                if CompilationOutputFileName = '' then
                  OptionQuestion ( 2 )
                else
                  if CodeOutputFileName = '' then
                    OptionQuestion ( 3 ) ;
            end (* 1 *) ;
        5 : begin (* 1 *)
              SetNormalCursor ;
              window ( 1 , 1 , 80 , 25 ) ;
              clrscr ;
              halt ;
            end (* 1 *) ;
      end (* case *) ;
    until OptionCounter = 4 ;
  end (* ReadFileName *) ;


procedure ReadSourceFile ;

          (* procedura wczytuje zbior z kompilowanym programem zrodlowym
             i buduje odpowiednia liste tych wierszy *)
  var
    CreateLine          : LineRecordPointer ;
    LastLine            : LineRecordPointer ;
    GlobalLineCounter   : integer ;

  begin (* ReadSourceFile *)
    LastLine := nil ;
    GlobalLineCounter := 0 ;
    while not eof ( SourceFile ) do
      begin (* 1 *)
        new ( CreateLine ) ;
        GlobalLineCounter := succ ( GlobalLineCounter ) ;
        with CreateLine ^ do
          begin (* 2 *)
            LineNumber := GlobalLineCounter ;
            MyAddress . HighByte := 0 ;
            MyAddress . LowByte := 0 ;
            MySize := 0 ;
            readln ( SourceFile , SourceLine ) ;
            ErrorCounter := 0 ;
            PrintAddessOnly := false ;
            NextLine := nil ;
          end (* 2 *) ;
        if LastLine = nil then
          TopSourceLineEntry := CreateLine
        else
          LastLine ^ . NextLine := CreateLine ;
        LastLine := CreateLine ;
      end (* 1 *) ;
    if TopSourceLineEntry = nil then
      begin (* 1 *)
        close ( SourceFile ) ;
        write ( 'zbior wejsciowy jest pusty' ) ;
        halt ;
      end (* 1 *) ;
    writeln ;
    writeln;
    writeln ;
    writeln ( 'Kompilacja programu' ) ;
  end (* ReadSourceFile *) ;


procedure IncrementAddress ( var AddressValue : Address ) ;

          (* procedura zwieksza zawartosc zmiennej reprezentujacej
             adres o 1 *)
  begin (* IncrementAddress *)
    with AddressValue do
      begin (* 1 *)
        if LowByte = 255 then
          begin (* 2 *)
            LowByte := 0 ;
            HighByte := succ ( HighByte ) ;
          end (* 2 *)
        else
          begin (* 2 *)
            LowByte := succ ( LowByte ) ;
          end (* 2 *) ;
      end (* 1 *) ;
  end (* IncrementAddress *) ;


(...)

begin      (* Z-80 Assembler Compiler *)
  InitListing ;
  StartData ;
  ReadFileNames ;
  OpenFiles ;
  SetNormalCursor;
  ReadSourceFile ;
  Compiler ;
  TestOnMissing ;
  EndListing ;
  PrintCross ;
  OutCode ;
  CloseFiles ;
  GoToXY ( 1 , 24 ) ;
end.       (* Z-80 Assembler Compiler *)


Okazuje się, że jest limit na wstawkę kodu →
z80.zip
.
Trochę go używałem do czasów, gdy przesiadłem się na "doskonałe" narzędzie: AVSIMZ80.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
Ostatnio zmieniony poniedziałek 15 maja 2017, 13:21 przez gaweł, łącznie zmieniany 1 raz.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 13:12

tasza pisze:No więc jest taka ciekawostka, że podczas wykonywania instrukcji IN A,(nn) lub OUT (nn), A
procesor powiela adres portu wystawiony via A0...A7 na bitach A8...A15 :)

Podobnie robi dla instrukcji IN rej,(C) oraz OUT (C),rej.

Prawda. Nawet kiedyś zastanawiałem się, czy nie wykorzystać tego do... jakiegoś żartu.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 13:59

Narzędzia do tworzenia oprogramowania: AVSIMZ80

Z dostępnych i dobrych pakietów programów narzędziowych dla mikroprocesora Z80 jest oprogramowanie AVSIMZ80 zawierające kompilator języka asembler oraz symulator działania samego mikroprocesora (popularne oprogramowanie AVSIM51 dotyczące mikrokontrolera C51 ma wręcz identyczne cechy użytkowe z oprogramowaniem dla mikroprocesora Z80). Istnieje możliwość sprawdzenia w programowym symulatorze mikroprocesora w sposób krokowy działania naszego programu. Symulator ten stanowi nieocenioną pomoc w przypadku poszukiwania błędów w tworzonym oprogramowaniu. Można w ten sposób sprawdzić działanie wybranych fragmentów, procedur, przerwań w najdrobniejszych szczegółach. Często tak się zdarza, że mikroprocesor robi coś inaczej niż nam się wydaje, że powinien ... no i taki symulator często brutalnie sprowadza nas z obłoków na ziemię.
W przypadku pakietu programów AVSIMZ80 dostępne są następujące składniki:
  • kompilator asemblera,
  • program linkera,
  • symulator programowy procesora.
Kompilator (jak wcześniej wspomniano) jest programem tłumaczącym program z postaci źródłowej (zawierającej zapisy instrukcji w formie czytelnej dla człowieka) na postać półskompilowaną (zawierającej ekwiwalentne zapisy w formacie binarnym). Omawiany kompilator tworzy postać półskompilowaną jako moduły relokowalne, która musi być jeszcze przetworzona przez specjalny program łączący (linker). Zdarzają się kompilatory, które spełniają jednocześnie funkcje linkera. Relokowalność oznacza, że w momencie tłumaczenia programu źródłowego nie jest określone miejsce w przestrzeni adresowej mikroprocesora, w którym będzie umieszczony aktualnie tłumaczony kod (może on być przemieszczony – relokowany w inne miejsce bez konieczności ponownej kompilacji).
Linker jest programem łączącym wszystkie fragmenty półskompilowane w jedną całość. Przyjmując, że każdy fragment półskompilowany jest produktem tłumaczenia programu źródłowego, których może być kilka, można wysnuć wniosek, że program źródłowy może być zawarty w kilku zbiorach. Wynikiem działania linkera jest program do umieszczenia w pamięci programu (EPROM).
Program źródłowy jest umieszczany w zbiorach z rozszerzeniem S01. W wyniku kompilacji powstaje postać półskompilowana (z rozszerzeniem R01) i ewentualnie może powstać dokument będący raportem kompilatora z procesu tłumaczenia (wydruk kompilacji). Powstałe zbiory półskompilowane podlegają fazie łączenie (program linkera). Informacje o częściach składowych wraz z innymi niezbędnymi danymi można zawrzeć w zbiorze dla linkera (typowe rozszerzenie tego zbioru jest XCL [eXtended Command Line]) lub być podane w parametrach wywołania. Jeżeli w zbiorze określającym fazę linkowania nie jest powiedziane inaczej, to wynik przetwarzania linkera (gotowy program do wykonania) umieszczony jest w zbiorze AOUT.A01.
Podstawowe pojęcia
W języku assemblera występują następujące elementy:
  • identyfikatory (nazwy)
  • stałe liczbowe
  • stałe tekstowe
  • komentarze
  • operatory
  • instrukcje
  • dyrektywy
  • funkcje.
Komentarz jest dowolnych tekstem rozpoczynającym się od znaku średnika (;) i może wystąpić w dowolnym miejscu (obowiązuje od znaku komentarza do końca wiersza).
Stałą liczbową jest liczba zapisana w postaci jawnej lub identyfikator będący stałą. Liczby mogą być zapisane w różnych systemach liczbowych (dokładnie w systemie binarnym, ósemkowym, szesnastkowym lub dziesiętnym). Liczba jest binarna (dwójkowa) jeżeli jest zakończona znakiem ‘B’, ósemkowa jeżeli jest zakończona znakiem ‘O’, szesnastkowym jeżeli jest zakończona znakiem ‘H’, dziesiętna jeżeli jest zakończona znakiem ‘D’ lub nie jest zakończona żadnym znakiem określającym podstawę systemu liczbowego. Należy pamiętać, że w każdym systemie liczbowym dopuszczalne są określone cyfry, oraz w przypadku liczb szesnastkowych litery od ‘A’ do ‘F’ na określenie dodatkowych cyfr szesnastkowych. Dla uniknięcie niejednoznaczności (pomiędzy liczbą a identyfikatorem) dla liczb szesnastkowych zaczynających się od cyfr ‘A’..’F’ należy pisać liczbę ze znakiem ‘0’ na początku.
Przykłady:
0100110B - liczba binarna
0215562O - liczba ósemkowa
2345235D - liczba dziesiętna
02A6BH - liczba szesnastkowa
0AAH - liczba szesnastkowa
AAH - identyfikator o nazwie AAH (nie liczba).
Stałą tekstową jest dowolny ciąg znaków ujęty w apostrofy.
Identyfikatorem jest dowolny ciąg liter, cyfr i znaku ‘_’ zaczynający się literą lub znakiem ‘_’ i nie będący słowem kluczowym (nazwą dyrektywy, instrukcji itp.). Identyfikatorów używa się do oznaczania procedur (funkcji) zmiennych, etykiet itp. Dyrektywą jest zapis sterujący pracą kompilatora, zapis definiujący identyfikator, zapis nakazujący umieścić w kodzie określony ciąg bajtów (w szczególności jeden bajt).
Do najważniejszych dyrektyw należą:
  • ASEG
  • RSEG
  • ORG
  • EQU
  • DEFB
  • DEFW
  • DEFS
  • DEFM
  • $
  • NAME
  • EXTERN
  • PUBLIC
  • END
Dyrektywa NAME
Dyrektywa ta określa nazwę kompilowanego modułu. Postać syntaktyczna jest następująca:
NAME <nazwa>
Dyrektywa ASEG
Dyrektywa ta określa, że poniższy segment jest segmentem absolutnym, to jest kod jest umieszczany w segmencie nierelokowalnym. Używa się jej do umieszczenia w programie elementów, które mają ściśle określone miejsce położenia, przykładowo procedury obsługi przerwań, miejsce początkowe programu uruchamiane sygnałem reset. Dyrektywa jest bezparametrowa.
Dyrektywa RSEG
Dyrektywa ta określa, że kompilowany segment jest segmentem relokowalnym oraz nazywa ten segment. Oznacza to, że dopiero linker określi rzeczywiste położenie kompilowanych instrukcji w wynikowym programie. W przypadku wystąpienia w różnych częściach (różnych zbiorach) półskompilowanych segmentów o identycznej nazwie, linker połączy je w jedną całość. Dyrektywy tej używa się do późniejszego określenia położenia obiektów występujących w segmencie w określonych miejscach programu wynikowego oraz do określenia położenia zmiennych w przestrzenie adresowej (w szczególności zmiennych w pamięci zewnętrznej). Postać syntaktyczna dyrektywy jest następująca:
RSEG <nazwa>
Dyrektywa ORG
Dyrektywa określa miejsce (adres), w którym należy umieścić kod tłumaczonego programu. Postać syntaktyczna jest następująca:
ORG <liczba>
Jako liczba rozumiana jest wartość zapisana w postaci cyfrowej lub identyfikator stałej będącej liczbą. Dyrektywy ORG nie należy umieszczać w obrębie segmentów relokowalnych (po RSEG) ponieważ może to doprowadzić do błędnego wylinkowania finalnego programu.
Dyrektywa EQU
Dyrektywa EQU nadaje identyfikatorowi określoną wartość. Postać syntaktyczna jest następująca:
<identyfikator> EQU <wartość>
Jako wartość może wystąpić stała w sposób jawny, identyfikator stałej lub wyrażenie proste składające się ze znanych już innych obiektów (identyfikatorów stałych) lub stałych jawnych. W ogólnym przypadku wyrażenie musi być policzalne w momencie kompilacji.
Dyrektywa DEFB
Dyrektywa umieszcza w kodzie bajty określone w dyrektywie. Postać syntaktyczna jest następująca:
<identyfikator> DEFB <lista bajtów>
lub
DEFB <lista bajtów>
Dyrektywa generalnie służy do umieszczania w programie stałych będących napisami, stałych tablic i innych obiektów o gradacji jednego bajta. Jeżeli dyrektywa jest poprzedzona identyfikatorem, to taki obszar jest nazwany.
Dyrektywa DEFW
Dyrektywa umieszcza w kodzie słowa (po dwa bajty) określone w dyrektywie. Postać syntaktyczna jest następująca:
<identyfikator> DEFW <lista słów>
lub
DEFW <lista słów>
Dyrektywa generalnie służy do umieszczania w programie stałych będących wartościami dwubajtowymi. Jeżeli dyrektywa jest poprzedzona identyfikatorem, to taki obszar jest nazwany.
Dyrektywa DEFS
Dyrektywa ta (wyjątkowo) nie generuje żadnego kodu lecz jedynie rezerwuje obszar o określonej wielkości wyrażonej w bajtach. Postać syntaktyczna jest następująca:
<identyfikator> DEFS <wielkość>
lub
DEFS <wielkość>
<wielkość> jest liczbą lub wyrażeniem liczbowym zawierającym identyfikatory stałych.
Dyrektywa generalnie służy do rezerwacji zmiennych w obszarach pamięci zarówno wewnętrznej jak i zewnętrznej. Deklaracja zmiennych (rezerwacja miejsca w pamięci RAM) nie może być realizowana za pomocą dyrektywy DEFB lub DEFW ponieważ te dyrektywy powodują nadanie określonej wartości dla kolejnych bajtów a nie istnieje żaden sposób na poziomie dyrektyw kompilatora nadawania wartości początkowej dla obszarów RAM (inny niż wpisanie określonych wartości za pomocą instrukcji, co jest już realizacją algorytmu programu). Wskaźnik pamięci związany a adresacją przesuwany jest o zadaną w dyrektywie wartość. W przypadku segmentów relokowalnych przyjmuje się umownie (co nie ma właściwie żadnego znaczenia), że początek segmentu adresowany jest od zera (można to zaobserwować przeglądając wydruk kompilacji).
Dyrektywa DEFM
Dyrektywa umieszcza w kodzie bajty odpowiadające kodom znaków występujących w napisie. Postać syntaktyczna jest następująca:
<identyfikator> DEFM <napis ujęty w apostrofy>
lub
DEFM <napis ujęty w apostrofy>
Dyrektywa służy do umieszczania w programie stałego tekstu jako ciągu znaków ASCII. Jeżeli dyrektywa jest poprzedzona identyfikatorem, to taki obszar jest nazwany.
Dyrektywa $
Dyrektywa powoduje otwarcie wskazanego w dyrektywie zbioru i przejście do jego kompilacji. Postać syntaktyczna jest następująca:
$<nazwa zbioru>
Główne zalecenie stosowanie tej dyrektywy jest następujące. W programie zawsze będą występować jakieś stałe, deklaracje i definicje, które w myśl zasad sztuki dobrego programowania powinny być sprowadzone do jednego źródła (zdefiniowane tylko w jednym miejscu) by mieć dostępną w wielu miejscach (w wielu zbiorach) tą samą a nie taką samą definicję. Zaleca się, by utworzyć jeden plik zawierający takie definicje i by ten plik był w każdym zbiorze (fragmencie programu) włączony do kompilacji poprzez dyrektywę $.
Dyrektywa EXTERN
Dyrektywa informuje kompilator o obcych (pochodzących z innych plików) obiektach (procedur, funkcji i zmiennych) użytych w bieżącym pliku. Postać syntaktyczna jest następująca:
EXTERN <lista identyfikatorów>
Użycie etykiety (procedury, zmiennej itp.) w programie spowoduje wygenerowanie błędu kompilacji jeżeli etykieta, do którą jest odwołanie a nie jest ona umieszczona w bieżącym pliku. Umieszczenie identyfikatorów na liście dyrektywy oznacza, że kompilator będzie traktował je jako znane. Dokładnie rzecz ujmując, kompilator nie jest w stanie stwierdzić, czy taka etykieta występuje gdziekolwiek w programie (w innych zbiorach podlegających kompilacji).
Rzeczywistą weryfikację przeprowadzi dopiero linker, który może stwierdzić, że wskazanej etykiety nie ma nigdzie. O zaistniałej ewentualnie takiej sytuacji informuje linker w swoim raporcie a wygenerowany program należy traktować za uszkodzony (użycie w trakcie realizacji programu może spowodować efekt niedefiniowalny). Z praktycznego punktu widzenia warto jest obok zgłaszanego obiektu w dyrektywie EXTERN w komentarzu podać nazwę zbioru, w którym zawarta jest jego implementacja. Ma to pewne znaczenie w przypadku pisania programu składającego się z kilku lub kilkunastu zbiorów kompilowanych niezależnie w przypadku odszukania jej implementacji (choćby w celu sprawdzenia jakiegokolwiek szczegółu).
Dyrektywa PUBLIC
Dyrektywa ta informuje kompilator (a właściwie linker) o tym, że wskazana w dyrektywie etykieta jest dostępna poza kompilowanym zbiorem. Postać syntaktyczna jest następująca:
PUBLIC <lista identyfikatorów>
Użycie tej dyrektywy stanowi parę w stosunku do dyrektywy EXTERN. Dyrektywa PUBLIC uwidacznia etykietę na zewnątrz (w sensie półkompilatu a nie programu).
Dyrektywa END
Dyrektywa oznacza koniec zbioru. Dalsza część zbioru nie podlega kompilacji.
Przykład programu.

Kod: Zaznacz cały

;
; *************************************************
; *************************************************
; ***                                           ***
; ***       Przyklad programu dla Z80           ***
; ***                                           ***
; ***                                           ***
; *************************************************
; *************************************************
;
NAME Z80_PROCESSOR
; *****************************
;
; LSTXRF
;
;------------------------------------------------
ASEG                                            ;
ORG 0                                           ;
;
; RESET & RST 00H SERVICE
; ***********************
                JP RST00_Serv                   ;
;------------------------------------------------
ORG 08H                                                 ;
;
; RST 08H SERVICE
; ***************
;
                JP RST08_Serv                   ;
;------------------------------------------------
ORG 10H                                                 ;
;
; RST 10H SERVICE
; ***************
;
                JP RST10_Serv                   ;
;------------------------------------------------
ORG 18H                                                 ;
;
; RST 18H SERVICE
; ***************
;
                JP RST18_Serv                   ;
;------------------------------------------------
ORG 20H                                                 ;
;
; RST 20H SERVICE
; ***************
;
                JP RST20_Serv                   ;
;------------------------------------------------
ORG 28H                                                 ;
;
; RST 28H SERVICE
; ***************
;
                JP RST28_Serv                   ;
;------------------------------------------------
ORG 30H                                                 ;
;
; RST 30H SERVICE
; ***************
;
                JP RST30_Serv                   ;
;------------------------------------------------
ORG 38H                                                 ;
;
; RST 38H SERVICE
; ***************
;
                JP RST38_Serv                   ;
;------------------------------------------------
ORG 66H                                                 ;
;
; NMI SERVICE
; ***********
;
                JP NMI_Serv                     ;
;------------------------------------------------
RST08_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST10_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST18_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST20_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST28_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST30_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
RST38_Serv :                                    ;
                EI                                      ;
                RETI                            ;
;------------------------------------------------
NMI_Serv :                                      ;
                RETN                            ;
;------------------------------------------------
RST00_Serv :                                    ;
                LD SP , Stack_Top               ;
Main :                                          ;
                LD DE , Obszar_do               ;
                LD HL , Obszar_z                ;
                LD BC , 3FFH                    ;
                LDIR                            ;
Main_0 :                                                ;
                JP Main_0                       ;
;------------------------------------------------
Obszar_z                DEFM    'Jakis staly fragment tekstu, ktory'
                        DEFM    'musi byc przepisny do pamieci RAM'
                        DEFM    '............. '
                        DEFM    '.... i tak dalej w sumie ma byc 1kB'
;
; ***********************************************
; ***********************************************
; ***********************************************
;
RSEG XRAM
;------------------------------------------------
Obszar_do       DEFS    1024
Stack           DEFS    3FEH
Stack_Top       DEFS    2
;------------------------------------------------
END

Jak łatwo można zauważyć, w powyższym programie występuje jeden relokowalny fragment. Na etapie kompilacji nie jest określone, w którym miejscu przestrzeni adresowej pamięci będzie on umieszczony. Ten obszar (o nazwie 'XRAM') stanowi ciągły obszar w pamięci o nieokreślonym (jeszcze) położeniu. W sumie program może składać się z kilku takich fragmentów i obszarów relokowalnych. Utworzenie programu do umieszczenia w pamięci mikroprocesora należy już do innego programu. W prezentowanym pakiecie oprogramowania znajduje się taki program i nazywa się on XLINK. W wywołaniu tego programu należy podać wszystkie szczegóły (przede wszystkim typ mikroprocesora, listę nazw zbiorów zawierających półkompilaty i wskazać miejsce w przestrzeni, gdzie należy umieścić obszary relokowalne).
Zakładając, że program źródłowy znajdował się w zbiorze o nazwie microgeek.s01, to po kompilacji poleceniem:
az80 microgeek.s01 microgeek.lst
powstanie między innymi zbiór microgeek.r01 zawierający postać półskompilowaną. Po wywołaniu linkera z parametrami:
xlink -cz80 microgeek -ZXRAM=A000 -l microgeek.lst
w zbiorze o nazwie aout.a01 będzie znajdował się kod programu do umieszczenia w pamięci mikroprocesora. Obszar relokowalny o nazwie XRAM będzie zaczynał się od adresu A000 hex (opcja -Z). Wszystkie odwołania do elementów z tego obszaru (w tym przypadku będą to zmienne w pamięci) w całym programie zostaną właściwie zaadresowane.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » poniedziałek 15 maja 2017, 14:35

:arrow: http://technical.elektronowolt.net/?page=avsimz80 można sobie pobrać ewentualnie
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 15:03

tasza pisze::arrow: http://technical.elektronowolt.net/?page=avsimz80 można sobie pobrać ewentualnie

Mogę jedynie dodać, że bez problemu działa pod windozą, bez stosowania wynalazków typu DOSBOX.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » poniedziałek 15 maja 2017, 17:26

gaweł pisze:Mogę jedynie dodać, że bez problemu działa pod windozą, bez stosowania wynalazków typu DOSBOX.

Ale pod linux, z Wine nie chce pracować, za to po instalacji dosbox (sudo apt-get install dosbox), bryka radośnie, aż miło:
00_z102-clk-dc-params.png

01_z103-clk-dc-params.png

02_z101-clk-dc-params.png
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 19:56

Gdzieś zapodziała mi się przejściówka z PLCC44 na DIP do programatora, muszę zaprogramować procka C51 do nowego komiksu. Szukałem, szukałem, jeszcze nie znalazłem. Znalazlem coś innego :)
IMG_5536.JPG

Kiedyś naszła mnie ochota na eksperymenty, tylko przylutowałem proca do płytki i ... zapomniałem całkiem o nim. Teraz wypłynął. Przypadek?
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

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » poniedziałek 15 maja 2017, 20:24

łooooo, czyż to kolejne combo od Zilog? bo u mnie podobne czekają na parkingu, ale chyba na lepsze czasy, to kostki Z84C151
a póki co /i na szczęście!/ one przegrywają z chromową rurką do samego nieba, hulajnogą i bieganiem po lesie ;)
skoro światem rządzi rachunek prawdopodobieństwa to nie ma przypadków - są znaki.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 15 maja 2017, 21:49

tasza pisze:skoro światem rządzi rachunek prawdopodobieństwa to nie ma przypadków - są znaki.

Światem nie rządzi rachunek prawdopodobieństwa. Wszystko jest zdeterminowane. A znaki... są tylko wskazówką, to znaki sterujące: Cr, Lf...
Ja ostatnio troszkę zaniedbałem... las i oczywiście rolki.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » wtorek 16 maja 2017, 08:09

duszę mam chaotyczną zatem i przypadkowość i nieporządek bardziej mi odpowiadają i tak postrzegam świat, a determinizm w jakiejkolwiek postaci oznacza dla mnie nudę... no ale nie sądzę, aby kogoś tu jeszcze takie moje przemyślenia obchodziły, więc....

...wróćmy do elektroniki - trochę układów:

IMG_6599.JPG
IMG_6598.JPG
IMG_6597.JPG
IMG_6596.JPG
IMG_6595.JPG
IMG_6594.JPG
IMG_6593.JPG


I kapitalna książka pani Kathe Spracklen `Z-80 and 8080 assembly language programming`, autorka tłumaczy wręcz łopatologicznie podstawowe zagadnienia, a że rękę lekką do pisania ma to i czyta się bardzo przyjemnie. Dla mnie najcenniejsze w tej książce było to, że równolegle pokazywane są te same fragmenty kodu źródłowego ale w zapisie mnemonicznym Intela i Ziloga. Intel jakoś bardzo nieintuicyjnie ponazywał mnemoniki, ta książka bardzo mi pomogła przy pisaniu softu dla dino-85
IMG_6600.JPG

IMG_6601.JPG
IMG_6602.JPG
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » wtorek 16 maja 2017, 10:13

tasza pisze:duszę mam chaotyczną zatem

Moja też jest chyba chaotyczna i nieuporządkowana. Głównie objawia się to tym, że... jeszcze nie znalazłem przejściówki do programatora. Podobnie, miałem (a może jeszcze mam tylko nie wiem gdzie leży) dźwiękowe AY. Są dwie możliwości: albo gdzieś leżą i się śmieją albo wywaliłem je bo nie wiedziałem jak je użyć (brak specyfikacji technicznej).

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
WoodPaker
User
User
Posty: 136
Rejestracja: czwartek 17 wrz 2015, 19:23
Lokalizacja: USA
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: WoodPaker » środa 17 maja 2017, 21:23

Chromowa rurka do nieba? Bosh, czym Ty sie zadowalasz :P
A Z80 to podstawowy składnik mojego pierwszego komputera.
Life is to short to eject USB safely

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1260
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: [Z80] Kultowy procek

Postautor: gaweł » poniedziałek 12 cze 2017, 00:43

gaweł pisze:Moja też jest chyba chaotyczna i nieuporządkowana. Głównie objawia się to tym, że... jeszcze nie znalazłem przejściówki do programatora. Podobnie, miałem (a może jeszcze mam tylko nie wiem gdzie leży) dźwiękowe AY. Są dwie możliwości: albo gdzieś leżą i się śmieją albo wywaliłem je bo nie wiedziałem jak je użyć (brak specyfikacji technicznej).

Znalazłem :lol: :lol: :lol: znalazłem :lol: :lol: :lol:
IMG_5892.JPG
IMG_5893.JPG
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

Awatar użytkownika
tasza
Geek
Geek
Posty: 1082
Rejestracja: czwartek 12 sty 2017, 10:24
Kontaktowanie:

Re: [Z80] Kultowy procek

Postautor: tasza » poniedziałek 12 cze 2017, 02:14

i to w stereo masz, normalnie szczęście podwójne ...
______________________________________________ ____ ___ __ _ _ _ _
Kończysz tworzyć dopiero, gdy umierasz. (Marina Abramović)


Wróć do „Inne mikroklocki, również peryferyjne”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość