Komputer 8-bitowy
Moderatorzy: gsmok, tszczesn, Romekd, Einherjer, OTLamp
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Schemat aktualnego stanu projektu.
Diody świecące, które służą tylko do debugowania, zostały pominięte w celu zwiększenia czytelności.
Diody świecące, które służą tylko do debugowania, zostały pominięte w celu zwiększenia czytelności.
- tszczesn
- moderator
- Posty: 11212
- Rejestracja: wt, 12 sierpnia 2003, 09:14
- Lokalizacja: Otwock
- Kontakt:
Re: Komputer 8-bitowy
Ja bym jednak odwrócił '573 
Dawno, dawno temu, dostałem w prezencie takie cudo jak CA80. Do tamtej pory nie poważałem elektroniki cyfrowej, wtedy mi się zmieniło. Po poduczeniu się techniki procesorowej, pamięci, cykli dostępu, magistral itp. wynalazków chciałem zrobić coś poważniejszego. Wziłłem 68000 i starałem się zrobić na tym jakieś działające urządzenie. I prawie mi się udało. Prawie, bo robiłem to na płytkach uniwersalnych (bo płytki stykowe kosztowały wtedy majątek, nie miałem tyle kasy) i ciągle się urywał jeden z wielu kabelków. Całość składała się z trzech płytek, i kabelków było dużo
Potem próbowałem zrobić kartę graficzną do CA80 (256x256 pikseli, początkowo czarnobiała, potem maiła mieć 256 odcieni szarości). Na piechotę, na podstawowych TTLach. Działała
Tą już zrobiłem na płytkach drukowanych, własnoręcznie robionych z pomocą kalkomanii Letraset.

Dawno, dawno temu, dostałem w prezencie takie cudo jak CA80. Do tamtej pory nie poważałem elektroniki cyfrowej, wtedy mi się zmieniło. Po poduczeniu się techniki procesorowej, pamięci, cykli dostępu, magistral itp. wynalazków chciałem zrobić coś poważniejszego. Wziłłem 68000 i starałem się zrobić na tym jakieś działające urządzenie. I prawie mi się udało. Prawie, bo robiłem to na płytkach uniwersalnych (bo płytki stykowe kosztowały wtedy majątek, nie miałem tyle kasy) i ciągle się urywał jeden z wielu kabelków. Całość składała się z trzech płytek, i kabelków było dużo

Potem próbowałem zrobić kartę graficzną do CA80 (256x256 pikseli, początkowo czarnobiała, potem maiła mieć 256 odcieni szarości). Na piechotę, na podstawowych TTLach. Działała

- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Ups

Dodałem też obwód resetu.
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Następnym etapem rozwoju projektu jest dodanie wyświetlacza na układzie HD44780 (a nie HD77840 jak mi się wcześniej pokiełbasiło).
Jako że jest to pierwsze prawdziwe urządzenie wejścia/wyjścia uważam że to świetny moment żeby przedyskutowac jak będzie wyglądać adresowanie We/Wy w tym komputerze.
Procesor Z80 używa ośmiu bitów na liniach A0-A7 do adresowania urządzeń We/Wy. To oznacza, że potrafi bezpośrednio zaadresować 256 różnych urządzeń. Dekodowanie takiej liczby adresów byłoby jednak równie skomplikowane co zbędne, postanowiłem więc pójść w dokładnie przeciwną stronę, a mianowicie wykorzystać dokładnie jeden z tych bitów do wyboru jednego urządzenia We/Wy. Dzięki temu w celu zdekodowaniu adresu muszę dokonać koniunkcji logicznej tylko jednej linii adresowej z linią IORQ.
Tutaj ważna uwaga, ponieważ linie sterujące zarówno procesora, jak i urządzeń peryferyjnych (a także pamięci) są aktywne stanem niskim, koniunkcji logicznej dokonujemy za pomocą bramki OR a alternatywy za pomocą bramki AND, odwrotnie niż w przypadku "normalnej" logiki.
Dalej, niektóre urządzenia posiadają kilka oddzielnych kanałów, np układ DART ma dwa kanały A i B, układ HD44780 ma kanały komend i kanał danych, etc. Zdecydowałem więc że jedynie 6 starszych spośród 8 dostępnych bitów adresu będzie wykorzystywana do wyboru urządzenia We/We, podczas gdy dwa najmłodsze bity posłuża do wyboru kanału. Oznacza to, że ostatecznie będę miał możliwość połączenia sześciu fizycznych urządzeń, każde reprezentujące maksymalnie 4 urządzenia logiczne (lub inaczej mówiąc: kanały). Powinno to wystarczyć do jednoczesnego podłączenia np. wyświetlacza, klawiatury, układu DART, karty dźwiękowej, portu równoległego i pamięci masowej.
W tym schemacie adresy urządzeń fizycznych będą wyglądały następująco (od najstarszego bitu):
011111xx
101111xx
itd. aż do
111110xx
Odpowiedzialnością programisty będzie unikanie jednoczesnego adresowania dwóch lub więcej urządzeń, np:
001111xx
Teraz trochę o samym układzie HD44780. Posiada on, jak wspomniałem, kanał komend i kanał danych. Wybór kanału następuje za pomocą pinu RS (Register Select), który podłączę bezpośrednio do linii A0. W pierwszej iteracji projektu będę do urządzenia jedynie pisał, natomiast nie będę z niego czytał. Tym samym pin R/W' mogę podłączyć bezpośrednio do masy, a pin E (Enable) do linii W procesora (poprzez inwerter, jako że jest aktywny stanem wysokim).
Czytanie z urządzenia jest jednak również ważną częścią komunikacji, której na dłuższą metę nie da się uniknąć. Nawet jeśli nie interesuje mnie sczytywanie znaków które są wyświetlane w danym momencie, zdecyduję się raczej na odczytywanie flagi BUSY. Flaga ta jest użyteczna ponieważ układ potrzebuje pewnego czasu aby wykonać każdą operację, a flagą sygnalizuje że nie jest jeszcze gotowy na przyjęcie kolejnego rozkazu czy danej. Przy częstotliwości zegara procesora rzędu 1Hz nie ma to znaczenia, ponieważ jednak procesor ma wkrótce dostać "prawdziwy" zegar, będzie zmuszony niekiedy czekać na układ HD44780.
Dostępne opcje to albo czekanie bezwarunkowe (maksymalne czasy wymagane do zakończenia danej operacji przez wyświetlacz są w jego karcie katalogowej), co oznaczałoby marnowanie czasu na czekanie nawet gdy nie jest ono konieczne. To byłoby akceptowalne, ale niezbyt eleganckie. Alternatywą jest właśnie sprawdzanie flagi BUSY.
Niestety, o ile większość urządzeń peryferyjnych i pamięci posiada linię adresującą Chip Select, Chip Enable czy występującą pod jakąś podobną nazwą, i osobne linie strobujące dla odczytu i zapisu: R i W, o tyle HD44870 na jedną linię R/W' i jedną linię strobującą E. Z mojej (ograniczonej) wiedzy na temat tego układu wynika, że wszystkie linie oprócz E muszą być ustawione na odpowiednie wartości przed podaniem wygnału strobującego na pin E. Oznacza to, że nie mogę użyć sygnału WR z procesora jednocześnie do strobowania i wyboru kierunku komunikacji pinem R/W (przynajmniej nie bez jakiegoś sposobu opóźnienia sygnału strobującego, np przerzutnikiem D). Co gorsza, odczyt nie byłby w takim wypadku w ogóle możliwy bo sygnał strobujący pojawiałby się na pinie E w zupełnie niewłaściwym momencie.
Wymyśliłem więc, że pin R/W' podłączę do linii A1 procesora, a strobować pin E będę za pomocą sygnału będącego alternatywą logiczną linii RD i WR procesora. Innymi słowy kierunek komunikacji jest wybierany linią adresową, a aktywowanie któregokolwiek z sygnałów RD lub WR spowoduje aktywację pinu E wyświetlacza. Adresy portów będą więc wyglądały następująco:
Ponownie, odpowiedzialność za pisanie tylko do portów dla których A0 ma wartość 0 i czytanie jedynie z portów gdzie A0 ma wartość 1 spada na programistę.
Ostatnia uwaga dotyczy fizycznej realizacji alternatywy logicznej linii RD i WR. Jak pisałem wcześniej, w logice odwrotnej (gdzie sygnały są aktywne stanem niskim) alternatywy dokonujemy za pomocą bramki AND. Jednak jako że mam już na płytce bramki OR i NOT, zrealizuję bramkę AND za pomocą bramki OR odwracając wszystkie sygnały wejściowe i wyjściowe.
Testy będę przeprowadzał w czwartek, gdyby do tego czasu ktoś zauważył, że to co napisałem nie ma sensu lub nie ma prawa działać, proszę o komentarz.
Listing istotnych fragmentów programu:
Jako że jest to pierwsze prawdziwe urządzenie wejścia/wyjścia uważam że to świetny moment żeby przedyskutowac jak będzie wyglądać adresowanie We/Wy w tym komputerze.
Procesor Z80 używa ośmiu bitów na liniach A0-A7 do adresowania urządzeń We/Wy. To oznacza, że potrafi bezpośrednio zaadresować 256 różnych urządzeń. Dekodowanie takiej liczby adresów byłoby jednak równie skomplikowane co zbędne, postanowiłem więc pójść w dokładnie przeciwną stronę, a mianowicie wykorzystać dokładnie jeden z tych bitów do wyboru jednego urządzenia We/Wy. Dzięki temu w celu zdekodowaniu adresu muszę dokonać koniunkcji logicznej tylko jednej linii adresowej z linią IORQ.
Tutaj ważna uwaga, ponieważ linie sterujące zarówno procesora, jak i urządzeń peryferyjnych (a także pamięci) są aktywne stanem niskim, koniunkcji logicznej dokonujemy za pomocą bramki OR a alternatywy za pomocą bramki AND, odwrotnie niż w przypadku "normalnej" logiki.
Dalej, niektóre urządzenia posiadają kilka oddzielnych kanałów, np układ DART ma dwa kanały A i B, układ HD44780 ma kanały komend i kanał danych, etc. Zdecydowałem więc że jedynie 6 starszych spośród 8 dostępnych bitów adresu będzie wykorzystywana do wyboru urządzenia We/We, podczas gdy dwa najmłodsze bity posłuża do wyboru kanału. Oznacza to, że ostatecznie będę miał możliwość połączenia sześciu fizycznych urządzeń, każde reprezentujące maksymalnie 4 urządzenia logiczne (lub inaczej mówiąc: kanały). Powinno to wystarczyć do jednoczesnego podłączenia np. wyświetlacza, klawiatury, układu DART, karty dźwiękowej, portu równoległego i pamięci masowej.
W tym schemacie adresy urządzeń fizycznych będą wyglądały następująco (od najstarszego bitu):
011111xx
101111xx
itd. aż do
111110xx
Odpowiedzialnością programisty będzie unikanie jednoczesnego adresowania dwóch lub więcej urządzeń, np:
001111xx
Teraz trochę o samym układzie HD44780. Posiada on, jak wspomniałem, kanał komend i kanał danych. Wybór kanału następuje za pomocą pinu RS (Register Select), który podłączę bezpośrednio do linii A0. W pierwszej iteracji projektu będę do urządzenia jedynie pisał, natomiast nie będę z niego czytał. Tym samym pin R/W' mogę podłączyć bezpośrednio do masy, a pin E (Enable) do linii W procesora (poprzez inwerter, jako że jest aktywny stanem wysokim).
Czytanie z urządzenia jest jednak również ważną częścią komunikacji, której na dłuższą metę nie da się uniknąć. Nawet jeśli nie interesuje mnie sczytywanie znaków które są wyświetlane w danym momencie, zdecyduję się raczej na odczytywanie flagi BUSY. Flaga ta jest użyteczna ponieważ układ potrzebuje pewnego czasu aby wykonać każdą operację, a flagą sygnalizuje że nie jest jeszcze gotowy na przyjęcie kolejnego rozkazu czy danej. Przy częstotliwości zegara procesora rzędu 1Hz nie ma to znaczenia, ponieważ jednak procesor ma wkrótce dostać "prawdziwy" zegar, będzie zmuszony niekiedy czekać na układ HD44780.
Dostępne opcje to albo czekanie bezwarunkowe (maksymalne czasy wymagane do zakończenia danej operacji przez wyświetlacz są w jego karcie katalogowej), co oznaczałoby marnowanie czasu na czekanie nawet gdy nie jest ono konieczne. To byłoby akceptowalne, ale niezbyt eleganckie. Alternatywą jest właśnie sprawdzanie flagi BUSY.
Niestety, o ile większość urządzeń peryferyjnych i pamięci posiada linię adresującą Chip Select, Chip Enable czy występującą pod jakąś podobną nazwą, i osobne linie strobujące dla odczytu i zapisu: R i W, o tyle HD44870 na jedną linię R/W' i jedną linię strobującą E. Z mojej (ograniczonej) wiedzy na temat tego układu wynika, że wszystkie linie oprócz E muszą być ustawione na odpowiednie wartości przed podaniem wygnału strobującego na pin E. Oznacza to, że nie mogę użyć sygnału WR z procesora jednocześnie do strobowania i wyboru kierunku komunikacji pinem R/W (przynajmniej nie bez jakiegoś sposobu opóźnienia sygnału strobującego, np przerzutnikiem D). Co gorsza, odczyt nie byłby w takim wypadku w ogóle możliwy bo sygnał strobujący pojawiałby się na pinie E w zupełnie niewłaściwym momencie.
Wymyśliłem więc, że pin R/W' podłączę do linii A1 procesora, a strobować pin E będę za pomocą sygnału będącego alternatywą logiczną linii RD i WR procesora. Innymi słowy kierunek komunikacji jest wybierany linią adresową, a aktywowanie któregokolwiek z sygnałów RD lub WR spowoduje aktywację pinu E wyświetlacza. Adresy portów będą więc wyglądały następująco:
Kod: Zaznacz cały
LCD_CMD_WR equ 11110100b ; write command port of the LCD
LCD_DAT_WR equ 11110101b ; write data port of the LCD
LCD_CMD_RD equ 11110110b ; read command port of the LCD
LCD_DAT_RD equ 11110111b ; read data port of the LCD
Ostatnia uwaga dotyczy fizycznej realizacji alternatywy logicznej linii RD i WR. Jak pisałem wcześniej, w logice odwrotnej (gdzie sygnały są aktywne stanem niskim) alternatywy dokonujemy za pomocą bramki AND. Jednak jako że mam już na płytce bramki OR i NOT, zrealizuję bramkę AND za pomocą bramki OR odwracając wszystkie sygnały wejściowe i wyjściowe.
Testy będę przeprowadzał w czwartek, gdyby do tego czasu ktoś zauważył, że to co napisałem nie ma sensu lub nie ma prawa działać, proszę o komentarz.
Listing istotnych fragmentów programu:
Kod: Zaznacz cały
; resets the LCD display
lcd_init:
LD C, LCD_CMD_WR
LD A, 00001111b ; init: set display on, cursor on, blinking on
OUT (C), A
LD A, 00111000b ; set data length: 8b, 2 lines
OUT (C), A
RET
; writes a null-terminated string to the LCD screen
; IX: address of the string
lcd_wriStr:
LD C, LCD_DAT_WR
CALL wriStr
RET
; writes a null-terminated string to an output port
; IX: address of the string
; C: port number
wriStr:
LD A,(IX+0)
CP 0
RET Z
OUT (C),A
INC IX
JR wriStr
Re: Komputer 8-bitowy
Łeee, HD44780 - brzydaljethrotull pisze: ↑wt, 28 września 2021, 13:15 Następnym etapem rozwoju projektu jest dodanie wyświetlacza na układzie HD44780 (a nie HD77840 jak mi się wcześniej pokiełbasiło).
Jako że jest to pierwsze prawdziwe urządzenie wejścia/wyjścia uważam że to świetny moment żeby przedyskutowac jak będzie wyglądać adresowanie We/Wy w tym komputerze

Jak coś, to mogę poszukać DL1414 bo chyba mam. Byłoby z epoki i znacznie ładniej.
- Tomasz Gumny
- 1875...2499 postów
- Posty: 2301
- Rejestracja: pn, 1 stycznia 2007, 23:18
- Lokalizacja: Trzcianka/Poznań
- Kontakt:
Re: Komputer 8-bitowy
Zdaje się, że przy operacjach we/wy na liniach A15..A8 pojawia się zawartość akumulatora.jethrotull pisze: ↑wt, 28 września 2021, 13:15Procesor Z80 używa ośmiu bitów na liniach A0-A7 do adresowania urządzeń We/Wy. To oznacza, że potrafi bezpośrednio zaadresować 256 różnych urządzeń.
Tomek
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
RozkazTomasz Gumny pisze: ↑wt, 28 września 2021, 16:30 Zdaje się, że przy operacjach we/wy na liniach A15..A8 pojawia się zawartość akumulatora.
OUT (n), A
powoduje wypisanie zawartości akumulatora zarówno na A15-A8 jak i na D7-D0. Na pierwszy rzut oka nie wygląda mi to na szczególnie użyteczne zachowanie. Z drugiej strony rozkaz
OUT (C), r
powoduje wypisanie zawartości rejestru B na A15-A8, rejestru C na A7-A0, i rejestru r na D7-D0. Jeśli dobrze rozumiem umożliwa to de facto użycie wszystkich bitów A15-A0 do zaadresowania urządzenia We/Wy?
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Ku mojemu zaskoczeniu, wyświetlacz LCD zadziałał od pierwszego razu!
Kontrast tego wyświetlacza jest beznadziejny, ale mam nadzieję że coś widać na zdjęciu.
Kontrast tego wyświetlacza jest beznadziejny, ale mam nadzieję że coś widać na zdjęciu.
Re: Komputer 8-bitowy
Chyba nastała jakaś moda hehe:
https://www.youtube.com/watch?v=eT20Rmp_S4Y
https://www.youtube.com/watch?v=eT20Rmp_S4Y
Ściąga: Ω µ Π φ α β ε ω 

- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
E tam, oni tam składają gotowy zestaw, a ja projektuję cały komputer od zera 

- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Skończyłem modyfikować płytkę, tak aby obsługiwała zarówno zapisy jak i odczyty z HD44780:
Zamieniłem też RAM 61256 na zgodny pod względem wyprowadzeń układ DS1244, który ma podtrzymanie zawartości pamięci baterią.
Teraz zabieram się za zegar kwarcowy o częstotliwości 1.8Mhz
Zamieniłem też RAM 61256 na zgodny pod względem wyprowadzeń układ DS1244, który ma podtrzymanie zawartości pamięci baterią.
Teraz zabieram się za zegar kwarcowy o częstotliwości 1.8Mhz
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Oto schemat płytki LCD. Nota bene, zauważyłem że prawie wszystkie inne projekty tego typu używają albo mikrokontrolera albo osobnego układu typu PIO do komunikacji z HD44780. Moim celem było sterowanie wyświetlaczem bezpośrednio z procesora, co, jak się wydaje, jest możliwe.
Następna w kolejce jest klawiatura, całkowicie na dyskretnej logice.
Dodatkowo, udało mi się uruchomić zegar 1.8432 MHz.
Następna w kolejce jest klawiatura, całkowicie na dyskretnej logice.
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Załączam (niepoprawny) schemat klawiatury.
Jest to jedna z tych historii, które wydają się proste w idei, ale diabeł tkwi w szczegółach.
Mamy licznik, którego część bitów adresuje rzędy (za pośrednictwem multipleksera), a część kolumny (za pośrednictwem demultipleksera). Pojawienie się sygnału na wyjściu multipleksera oznacza, że wciśnięty został przycisk. Sygnał ten zatrzaskuje bieżący stan licznika (czyli kod znaku - oczywiście nie jest to kod ASCII) w rejestrze '573, do odczytania przez procedurę obsługi przerwania. Jednocześnie ten sam sygnał, zapamiętany w przerzytniku J-K, wysyła do procesora żądanie przerwania, a także bramkuje zegar licznika, dzięki czemu licznik zatrzymuje się aż do odebrania Iterrupt Acknowledge od procesora. Zamodelowałem to naprędce, i bum, działa od pierwszego razu. Świetnie, nie?
Nie. Po dłuższym czasie zdałem sobie sprawę, że układ działa... przypadkiem. Popełniłem dwa błędy, które znoszą się nawzajem, jednak wspólnie powodują nieprzyjemny skutek uboczny. Mianowicie, sygnał bramkujący zegar licznika, przez fakt że przechodzi przez przerzutnik, jest opóźniony o jeden takt zegara w stosunku do sygnału na wyjściu multipleksera. Oznacza to, że po naciśnięciu przycisku licznik zliczy jeszcze jeden takt zegara (przejdzie do kolejnej kolumny klawiatury) przed zatrzymaniem się. Z początku w ogóle tego nie zauważyłem, a później sądziłem że to nie ma znaczenia, jednak niestety oznacza to, że nie mogę wykryć zwolnienia przycisku. Po ponownym dojściu licznika do pozycji odpowiadającej wciśniętemu przyciskowi układ ponownie by się uaktywnił, zostałoby wygenerowane kolejne przerwanie itd. powodując zdublowanie wybranego na klawiaturze znaku.
Drugim moim błedem było przeoczenie faktu, że tylko dzięki temu przeskoczeniu na kolejną kolumnę możliwe jest zresetowanie przerzutnika J-K sygnałem Iterrupt Acknowledge. Reset nie byłby możliwy, gdyby wyjście z multipleksera było utrzymywane w stanie wysokim, jak to zaprojektowałem. W swojej ignorancji sądziłem, że jeśli przerzutnik J-K jest wyzwalany zboczem, oznacza to, że można go zresetować zboczem narastającym na wejściu RESET nawet jeśli wejście J jest utrzymywane w stanie wysokim, i że dopiero kolejne zbocze narastające na tym wejściu ustawi ten przerzutnik z powrotem. Oczywiście jest to bzdura, wyzwalanie zboczem dotyczy jedynie wejścia zegarowego.
Doszedłem więc do wniosku, że będę bramkował zegar bezpośrednio wyjściem multipleksera (zamiast wyjściem przerzutnika). Wtedy istotnie zegar zatrzymuje się natychmiast po wciśnięciu przycisku i osiągnięciu odpowiedniego stanu przez licznik. Ponieważ jednak na wyjściu multipleksera urzymuje się wówczas stan wysoki, zresetowanie układu (a tym samym zwolnienie linii INT procesora) nie jest możliwe aż do zwolnienia przycisku klawiatury. W praktyce oznacza to że przerwanie wywoływane było wielokrotnie dla danego wciśnięcia przycisku, znowu powodując błędne wielokrotne odczyty.
Potrzebuję więc układum który zamieniałby zbocze narastające na pojedynczy impuls. Układem takim jest multiwibrator monostabilny, którego użycie wydaje mi się bardzo mało eleganckie, choćby dlatego że jest on układem zasadniczo analogowym, w związku czym nie da się go zasymulować w Logisimie. Nie widzę jednak za bardzo innej opcji. W stosunku do schematu w załączniku wprowadzę więc zmianę polegającą na tym że sygnał bezpośrednio z miltipleksera będzie podawany na bramkę blokującą zegar licznika, natomiast do przerzutnika J-K będzie dochodził sygnał przepuszczony przez multiwibrator. Zaprototypuję ten układ na płytce uniwersalnej przed zlutowaniem go, żeby upewnić się że działa. Dodatkowego komentarza wymaga sposób podłączenia klawiatury do procesora. Pierwszy mój pomysł polegał na wykorzystaniu pinu NMI do zgłaszania przerwania. Jest to proste rozwiązanie, jako że procedura obsługi przerwania niemaskowalnego ma stały adres w pamięci. Niekorzystną natomiast jego cechą jest że klawiatura powinna raczej mieć najniższy priorytet spośród wszystkich urządzeń We/Wy.
Kolejną opcją jest więc skorzystanie z jednego z trybów obsługi przerwania maskowalnego INT dostępnych w Z80. Spośród trzech dostępnych trybów potencjalnie przydatne są dwa ostatnie: 1 i 2. W trybie 1, podobnie jak w przypadku obsługi przerwania NMI, procedura obsługi ma stały adres i musi sama umieć rozróżnić kóre urządzeni zgłosiło przerwanie. Można by to zaimplementować za pomocą rejestru lub bufora z wyjściem trójstanowym, aktywowanego wewnętrzym sygnałem HELP (w moim przypadku byłoby to wyjście przerzutnika J-K), procesor mógłby wtedy odczytać z tego rejestru czy bufora stałą przypisaną do klawiatury.
Z kolei w trybie 2, w odpowiedzi na sygnał Iterrupt Acknowledge, urzadzenie We/Wy podaje na D7-D0 młodszy bajt adresu procedury obsługi przerwania *). To jest najbardziej elastyczne rozwiązanie, w dodatku implementowane przez urzadzenia peryferyjne z rodziny Z80, takie jak DART. Można by ponownie użyć tu rejestru (umożliwiałby procesorowi zaprogramowanie zaraz po starcie systemu, jaka konkretnie ma być wartość tego młodszego bitu adresu procedury obsługi przerwania, tak jak to się dzieje w przypadku fabrycznych układów We/Wy) lub bufora (tutaj adres byłby zahardkodowany na stałe).
Jednak ja wpadłem na pomysł znacznie prostszy, i nie do końca mogę się zdecydować czy jest to pomysł genialny czy kompletne partactwo. Mianowicie połącze D7-D0 z masą przez rezystory po kilka kiloomów. Procesor wobec tego odczyta z magistrali danych wartość zero, co oznacza tylko tyle że procedura obsługi klawiatury będzie musiała zawsze być pod adresem wyznaczonym zawartością komórek (I):00h, gdzie I jest rejestrem procesora zawierającym starszy bajt tablicy adresów procedur obsługi przerwań. Uff
W przypadku gdy jakieś inne urządzenie będzie zgłaszało przerwanie, będzie mogło ustalić stan magistrali danych dzięki rezystorom. Podobnie przez rezystor szeregowy podłączony będzie sygnał INT (bardziej elegancką alternatywą byłoby użycie bramki z wyjściem trójstanowym, ponownie uaktywnianej sygnałem HELP, ale powiedzmy sobie szczerze, i tak już mam tu 8 różnych układów 74 i nie potrzebuję dziewiątego).
Na koniec zaznaczę tylko że sygnały IEI i IEO (Interrupt Enabled In i Interrupt Enabled Out) służą do negocjacji priorytetów przerwania między urządzeniami We/Wy, u mnie będzie to przynajmniej klawiatura i DART.
*) w rzeczywistości jest to adres w pamięci pod którym znajduje się adres procedury obsługi przerwania, ale to nie ma dla mojego wywodu znaczenia
Jest to jedna z tych historii, które wydają się proste w idei, ale diabeł tkwi w szczegółach.
Mamy licznik, którego część bitów adresuje rzędy (za pośrednictwem multipleksera), a część kolumny (za pośrednictwem demultipleksera). Pojawienie się sygnału na wyjściu multipleksera oznacza, że wciśnięty został przycisk. Sygnał ten zatrzaskuje bieżący stan licznika (czyli kod znaku - oczywiście nie jest to kod ASCII) w rejestrze '573, do odczytania przez procedurę obsługi przerwania. Jednocześnie ten sam sygnał, zapamiętany w przerzytniku J-K, wysyła do procesora żądanie przerwania, a także bramkuje zegar licznika, dzięki czemu licznik zatrzymuje się aż do odebrania Iterrupt Acknowledge od procesora. Zamodelowałem to naprędce, i bum, działa od pierwszego razu. Świetnie, nie?
Nie. Po dłuższym czasie zdałem sobie sprawę, że układ działa... przypadkiem. Popełniłem dwa błędy, które znoszą się nawzajem, jednak wspólnie powodują nieprzyjemny skutek uboczny. Mianowicie, sygnał bramkujący zegar licznika, przez fakt że przechodzi przez przerzutnik, jest opóźniony o jeden takt zegara w stosunku do sygnału na wyjściu multipleksera. Oznacza to, że po naciśnięciu przycisku licznik zliczy jeszcze jeden takt zegara (przejdzie do kolejnej kolumny klawiatury) przed zatrzymaniem się. Z początku w ogóle tego nie zauważyłem, a później sądziłem że to nie ma znaczenia, jednak niestety oznacza to, że nie mogę wykryć zwolnienia przycisku. Po ponownym dojściu licznika do pozycji odpowiadającej wciśniętemu przyciskowi układ ponownie by się uaktywnił, zostałoby wygenerowane kolejne przerwanie itd. powodując zdublowanie wybranego na klawiaturze znaku.
Drugim moim błedem było przeoczenie faktu, że tylko dzięki temu przeskoczeniu na kolejną kolumnę możliwe jest zresetowanie przerzutnika J-K sygnałem Iterrupt Acknowledge. Reset nie byłby możliwy, gdyby wyjście z multipleksera było utrzymywane w stanie wysokim, jak to zaprojektowałem. W swojej ignorancji sądziłem, że jeśli przerzutnik J-K jest wyzwalany zboczem, oznacza to, że można go zresetować zboczem narastającym na wejściu RESET nawet jeśli wejście J jest utrzymywane w stanie wysokim, i że dopiero kolejne zbocze narastające na tym wejściu ustawi ten przerzutnik z powrotem. Oczywiście jest to bzdura, wyzwalanie zboczem dotyczy jedynie wejścia zegarowego.
Doszedłem więc do wniosku, że będę bramkował zegar bezpośrednio wyjściem multipleksera (zamiast wyjściem przerzutnika). Wtedy istotnie zegar zatrzymuje się natychmiast po wciśnięciu przycisku i osiągnięciu odpowiedniego stanu przez licznik. Ponieważ jednak na wyjściu multipleksera urzymuje się wówczas stan wysoki, zresetowanie układu (a tym samym zwolnienie linii INT procesora) nie jest możliwe aż do zwolnienia przycisku klawiatury. W praktyce oznacza to że przerwanie wywoływane było wielokrotnie dla danego wciśnięcia przycisku, znowu powodując błędne wielokrotne odczyty.
Potrzebuję więc układum który zamieniałby zbocze narastające na pojedynczy impuls. Układem takim jest multiwibrator monostabilny, którego użycie wydaje mi się bardzo mało eleganckie, choćby dlatego że jest on układem zasadniczo analogowym, w związku czym nie da się go zasymulować w Logisimie. Nie widzę jednak za bardzo innej opcji. W stosunku do schematu w załączniku wprowadzę więc zmianę polegającą na tym że sygnał bezpośrednio z miltipleksera będzie podawany na bramkę blokującą zegar licznika, natomiast do przerzutnika J-K będzie dochodził sygnał przepuszczony przez multiwibrator. Zaprototypuję ten układ na płytce uniwersalnej przed zlutowaniem go, żeby upewnić się że działa. Dodatkowego komentarza wymaga sposób podłączenia klawiatury do procesora. Pierwszy mój pomysł polegał na wykorzystaniu pinu NMI do zgłaszania przerwania. Jest to proste rozwiązanie, jako że procedura obsługi przerwania niemaskowalnego ma stały adres w pamięci. Niekorzystną natomiast jego cechą jest że klawiatura powinna raczej mieć najniższy priorytet spośród wszystkich urządzeń We/Wy.
Kolejną opcją jest więc skorzystanie z jednego z trybów obsługi przerwania maskowalnego INT dostępnych w Z80. Spośród trzech dostępnych trybów potencjalnie przydatne są dwa ostatnie: 1 i 2. W trybie 1, podobnie jak w przypadku obsługi przerwania NMI, procedura obsługi ma stały adres i musi sama umieć rozróżnić kóre urządzeni zgłosiło przerwanie. Można by to zaimplementować za pomocą rejestru lub bufora z wyjściem trójstanowym, aktywowanego wewnętrzym sygnałem HELP (w moim przypadku byłoby to wyjście przerzutnika J-K), procesor mógłby wtedy odczytać z tego rejestru czy bufora stałą przypisaną do klawiatury.
Z kolei w trybie 2, w odpowiedzi na sygnał Iterrupt Acknowledge, urzadzenie We/Wy podaje na D7-D0 młodszy bajt adresu procedury obsługi przerwania *). To jest najbardziej elastyczne rozwiązanie, w dodatku implementowane przez urzadzenia peryferyjne z rodziny Z80, takie jak DART. Można by ponownie użyć tu rejestru (umożliwiałby procesorowi zaprogramowanie zaraz po starcie systemu, jaka konkretnie ma być wartość tego młodszego bitu adresu procedury obsługi przerwania, tak jak to się dzieje w przypadku fabrycznych układów We/Wy) lub bufora (tutaj adres byłby zahardkodowany na stałe).
Jednak ja wpadłem na pomysł znacznie prostszy, i nie do końca mogę się zdecydować czy jest to pomysł genialny czy kompletne partactwo. Mianowicie połącze D7-D0 z masą przez rezystory po kilka kiloomów. Procesor wobec tego odczyta z magistrali danych wartość zero, co oznacza tylko tyle że procedura obsługi klawiatury będzie musiała zawsze być pod adresem wyznaczonym zawartością komórek (I):00h, gdzie I jest rejestrem procesora zawierającym starszy bajt tablicy adresów procedur obsługi przerwań. Uff

W przypadku gdy jakieś inne urządzenie będzie zgłaszało przerwanie, będzie mogło ustalić stan magistrali danych dzięki rezystorom. Podobnie przez rezystor szeregowy podłączony będzie sygnał INT (bardziej elegancką alternatywą byłoby użycie bramki z wyjściem trójstanowym, ponownie uaktywnianej sygnałem HELP, ale powiedzmy sobie szczerze, i tak już mam tu 8 różnych układów 74 i nie potrzebuję dziewiątego).
Na koniec zaznaczę tylko że sygnały IEI i IEO (Interrupt Enabled In i Interrupt Enabled Out) służą do negocjacji priorytetów przerwania między urządzeniami We/Wy, u mnie będzie to przynajmniej klawiatura i DART.
*) w rzeczywistości jest to adres w pamięci pod którym znajduje się adres procedury obsługi przerwania, ale to nie ma dla mojego wywodu znaczenia
- jethrotull
- 3125...6249 postów
- Posty: 4013
- Rejestracja: sob, 3 czerwca 2006, 21:51
- Lokalizacja: Poznań
Re: Komputer 8-bitowy
Udało mi się zamodelować klawiaturę, która działa, przynajmniej w symulatorze, bez użycia monoflopów.
Przystąpiłem do zakupu części w celu budowy prototypu.
PS. Mam nadzieję, że ktoś to czyta.
Przystąpiłem do zakupu części w celu budowy prototypu.
PS. Mam nadzieję, że ktoś to czyta.