Mikrokomputer CA80
Direct Memory Loader

ładowarka do pamięci


charakterystyka i informacje ogólne
książki / dokumentacja (literatura)
ulotki i broszurki MIK (literatura)
skany artykułów z prasy (literatura)
programator EPROM (aplikacje)
dwupunktowy termometr (aplikacje)
licznik-timer Z80-CTC i dioda RGB (aplikacje)
Direct Memory Loader - ładowarka do pamięci (akcesoria)
próbnik stanów logicznych MIK03C (akcesoria)
zdalnie sterowana klawiatura (akcesoria)
przegląd procedur systemowych (programowanie)

☘☘☘☘☘☘☘☘☘☘

Zabawa w średniowieczną technikę mikroprocesorową oznacza częste borykanie się z zagadnieniem umieszczenia w pamięci systemu własnego, autorskiego oprogramowania. Wyzwanie jest to nie lada w przypadku systemów prymitywnych i pozbawionych systemowego wsparcia dla takich zadań w formie choćby najprostszego bootloadera. Podejść do zagadnienia wgrania binarnego wsadu jest wiele, wszystko zależy od konstrukcji docelowego systemu i jego możliwości komunikacyjnych. W przypadku systemu CA80 istnieje możliwość ręcznego wprowadzania kodów maszynowych Z80 bezpośrednio do pamięci RAM zleceniem *D, przy dłuższych programach (powyżej kilkuset bajtów) jest to jednak mało komfortowe i dość błędogenne. Można wspierać się rozwiązaniami typu emulator pamięci EPROM (z naszych rodzimych konstrukcji to zestaw AVT-270, wspominałam o nim kiedyś w ⇨ Cyfrowej archeologii), to rozwiązanie daje wielki komfort pracy, ale „zablokuje” nam to narzędzie przy CA80, więc po takie rozwiązania sięgamy w przypadku konkretnych projektów, a nie radosnych zabaw i eksperymentów. Kolejna metoda to wzbogacenie naszego systemu o łącze szeregowe RS232, może służyć zarówno do ładowania programów jak i późniejszej ich komunikacji z dużym komputerem, do tego tematu jeszcze kiedyś wrócimy. Na koniec pozostają rozwiązania niszowe, bazujące na specyficznych cechach wykorzystanego w systemie mikroprocesora, w tym przypadku jest to możliwość współpracy Z80 z układem DMA (direct memory access), choć lepiej byłoby napisać - alternatywne wykorzystanie tej możliwości...

klips i kadzidełka



Geneza tego miniprojektu jest dość nietypowa, a mianowicie - podczas jednej z wypraw na warszawski bazar Wolumen udało mi się upolować niesamowicie przydatny gadżet - klips pomiarowy DIP40 firmy 3M, praktycznie nieużywany i dosłownie za grosze (w porównaniu to typowych sklepowych cen), do tego komplet kadzidełek, aromat ich znakomicie komponuje się z wszechobecnym w moim domowym warsztacie zapachem kalafonii. Przymiarki do dużych kostek, które akurat były pod ręką wypadły obiecująco, kilka ujęć widzimy poniżej.





Wtedy też wpadła do łepetyny myśl zaiste szatańska, a może by ten klips zapiąć na procesor Z80 w komputerku CA80 i w jakiś sposób dobrać się do szyn systemu? Biorąc pod uwagę odłączalność gadżetu - ryzyko było w sumie niewielkie, a ciekawość co można w ten sposób uzyskać coraz większa.

co krasnal widzi przez okno

Przyznaję, przyjęta w dokumentacji CA80 metoda tłumaczenia działania mikroprocesora na przykładzie mieszkających w nim krasnoludków kiedyś mocno mnie irytowała, wydawało się to po prostu dziecinne. Z biegiem lat doszłam jednak do wniosku, że taka metoda przekazywania wiedzy pozwala szybko zmieniać punkt widzenia na system mikroprocesorowy i rozpatrywać go w różnych aspektach (model matematyczny, model fizyczny, przebiegi na magistralach) a jednocześnie daje możliwość zakończenia rozważań na dowolnym poziomie szczegółowości krótkim stwierdzeniem – ten krasnal tak robi i już! Spróbujmy zatem spojrzeć oczami krasnala z procesora Z80 na pozostałe elementy systemu, szczególnie na układy pamięci. Dostęp do dowolnej komórki pamięci w obrębie 64kB przestrzeni adresowej Z80 uzyskujemy wystawiając na liniach A15..A0 szesnastobitową liczbę binarną jednoznacznie identyfikującą lokalizację w pamięci. Sygnałami /WR (write), /RD( read) oraz /MREQ (memory request) dajemy znać pamięci oraz ewentualnie układom towarzyszącym (na przykład dekoderom adresowym lub dodatkowej logice) że zamierzamy wykonać zapis lub odczyt danych – ogólnie mówiąc uzyskać aktywnych dostęp do szyny danych D7..D0. I teraz wyobraźmy sobie, że nasz krasnal to takie uczynne stworzenie, które jak poprosimy, to nam na chwilę odstąpi sygnały sterujące magistralą do dowolnego wykorzystania. On sam stanie z boku i będzie cierpliwie czekał pamiętając stan swych rejestrów, aż wykonamy pracę i oddamy mu z powrotem sterowanie. O, i za taką opowiastką stoi właśnie idea wykorzystania sygnału /BUSRQ (bus request), który wykorzystywany jest przez układ Z80-DMA do przejmowania kontroli nad szynami systemu celem wykonania transferu obszaru pamięci. My w sumie chcemy zrobić to samo, a mianowicie – skoro krasnal udostępnił nam sterowanie to generując identyczne jak on przebiegi na magistralach sytemu będziemy w stanie zapisywać do pamięci RAM w wybranych przez siebie lokalizacjach. I co ważne, skoro nasz punkt widzenia to wnętrze procesora (i rzeczone okno – szyny adresowa, danych i sterująca) to wszelka dodatkowa logika dekodująca adresy nie będzie nam przeszkadzać – do pamięci sięgamy dokładnie tak, jak robi to krasnal, to znaczy CPU.

ładowarka na trzy rejestry

Zweryfikowanie koncepcji z /BUSRQ w praktyce sprowadza się do schematu jak na rysunku poniżej.



Widzimy główne składniki ładowarki oraz dla ustalenia uwagi – procesor Z80 wraz z magistralami. Arduino (Nano lub Uno) odpowiedzialne jest za komunikację z komputerem PC, realizując proste SPI ładuje do rejestrów U1,U2 adres komórki pamięci, do U3 – daną do wpisania do tak wskazanej lokalizacji. Generując niskie stany logiczne na wyprowadzeniach /MREQ i /WR tak jakby robił to procesor Z80 wykonuje prosty cykl zapisu do pamięci, cała sekwencja powtarzana jest dla kolejnych komórek, które chcemy zapisać. Oczywiście pozostaje sprawa przejęcia kontroli nad systemem - stąd podłączenie do Ardu sygnału /BUSRQ, którego niski stan logiczny informuje Z80 o konieczności zwolnienia magistral. Dla uproszczenia nie sprawdzam już faktu oddania sterowania (sygnał /BUSACK), ale oczywiście jest taka techniczna możliwość. Układ z tranzystorem NPN przy wejściu /RESET to dodatek na okazję konieczności twardego wyzerowania systemu, podpórka tranzystorem jest konieczna z uwagi dość spore pojemności w układzie zerowania mojego CA80. Pewnego komentarza wymaga samo podłączenie się do linii /BUSRQ procesora, tu trzeba dokładnie zaznajomić się z realiami naszego systemu. W komputerku CA80 sygnał ten jest na stałe podłączony do +5V, więc wymagane było przecięcie tego połączenia i wymuszenie stanu H przy pomocy rezystora podciągającego, po tym zabiegu (etapy widoczne na fotografiach poniżej) można już bezpiecznie wymuszać na końcówce D4 Ardu niski stan logiczny. Ja dla bezpieczeństwa dodałam po drodze do Ardu niewielki rezystor (300Ω), ponieważ nie wszystkie z moich CA80 mają wykonany opisywany wyżej zabieg z linią /BUSRQ.



Przy okazji asekurancko informuję - jeżeli ktoś nie czuje się na siłach wykonać taki mod, to lepiej zrezygnować. Płytki drukowane starego CA80 nie są zbyt dobrej jakości, wszystko jest dość delikatne i tak po prawdzie mamy do całej zabawy (w mojej ocenie) jedno podejście, kolejnego lutowania płytka może zwyczajnie nie przetrwać.



prototyp na jeden wieczór

No i wracamy do naszego cudnego klipsa DIP40, oto w rolach głównych jako najbardziej zacny składnik powstałego na płytce stykowej druciaka. Połączenie całości było nieco żmudne, ale w końcu jakoś się udało. Długość przewodów pomiędzy płytka a klipsem/procesorem nie miała wpływu na pracę prototypu, za to dały się we znaki...styki. Tak, ten cudak działał raptem jeden wieczór, potem możliwe że w ferworze walki połączeniem szarpnęłam - układ zaczął żyć swoim życiem i stał się nieprzewidywalny. Udał mi się natomiast namacalnie zweryfikować, że schemat ma sens i następny krok to budowa zabawki na płytce drukowanej.







Dość ciekawe zdjęcia klipsika DIP40 w akcji, naprawdę jest to megawygodny wynalazek.



Niestety (choć to już zależnie od realiów) daje się czasem we znaki wysokość klipsa. W moim CA80 płyta główna jest ścieżkami do góry, główne układy wiszą niczym nietoperze głowami w dół, do blatu biurka jest kilka centymetrów. Zabawa z klipsem wymagała postawienia CA80 na podwyższeniu, stąd takie instalacje jak na dalszych zdjęciach. No i jak łatwo zgadnąć, takie wygibasy wcześniej czy później kończą się mikrozwarciem lub przerwą i zabawka przestaje stabilnie działać.



Filmik poniżej to radosne zabawy ze sprowadzaniem sygnału /BUSRQ do niskiego poziomu logicznego, widać że system CA80 zawiesza pracę, w szczególności przestaje działać multipleksowanie wyświetlacza (zjawisko groźne dla VFD!), po zwolnieniu /BUSRQ procesor podejmuje prace jakby nic się nie stało. Ot, chwilowa przerwa w życiorysie, która zdarzyć się może każdemu.



płytka drukowana z literówką

Kolejne zdjęcia dotyczą wykonania płytki drukowanej, problemy są dwa. Jedne w sumie śmieszny - LRD zamiast LDR, od loader, ale to detal. Gorzej, że dopiero na późniejszym etapie testów układu okazało się koniczne poprowadzenie sygnałów /IORQ i /RD z Z80 do Ardu. Przecież one wchodzą w High-Z gdy procesor zwalnia magistrale, naiwnością jest oczekiwanie, że tam sam z siebie pojawi się stan High i zapewni nieaktywność sygnałów. Sama płytka wykonana domowym sposobem na zasadzie żelazka i papieru kredowego, układ ścieżek jest na tyle prosty, że od biedy można by ją wykonać flamastrem.

Materiał wejściowy do metody żelazkowej (płytka po poprawkach):









lutowanki

Montaż całości nie nastręcza trudności, ale warto płytkę przez lutowaniem sprawdzić na okazję przerw czy mikrozwarć, u mnie dwa drobiazgi się znalazły, ale udało się to pocerować fragmentami cienkiego drucika. na koniec całość obleciana od spodu słynnym z napisu "nie pić!" lakierem z kalafonii i ruskiego spirytusu.





przedłużacz do procesora Z80

No, ten etap prac to było wyzwanie i szkoła cierpliwości. I potwierdziła się moja teoria, że do takich robótek to trzeba być w naprawdę dobrej kondycji emocjonalnej. Oskubanie czterdziestu kabelków, polutowanie tego na zakładkę i wpasowanie pomiędzy dwie podstawki precyzyjne, tak aby bokiem, na taśmie wyszedł nam drugi, zapasowy komplet wyprowadzeń Z80 - to właśnie całość pracy do wykonania. Udało się z jedną drobną poprawką, która szczęściem wypatrzyłam przez zlutowaniem dolnej i górnej podstawki.











Test wtyku, jeszcze na sucho, czy z tak osadzonym procesorem komputerek CA80 wystartuje i będzie stabilnie pracował. Udało się.



ładowarka w komplecie





Dla kompletu, wspominany wcześniej problem ze ścieżkami do /RD i /IORQ, no takie życie złośliwie, dobrze że jednak jakoś to wyszło i udało się całkiem łatwo załatać. Docelowo pewnie tam wyląduje kynarek, a póki co pamiątkowe zdjęcie.



oprogramowanie i prostowanie pokręconych ścieżek

Program w Pascal jest dość prymitywna aplikacją konsolową upychającą kolanem w Arduino kolejne rekordy wczytanego pliku Intel Hex. Transmisja szeregowa jest natury blokującej i odbywa się z szybkością 19200 bodów, co daje pewne pole do popisu w kontekście przyspieszenia zabawki, gros czasu tracone jest na komunikację z PC. Cały programik w lokalizacji ca80mem/ca80mem.pas, w ramach ewentualnych modernizacji można sobie z tego zrobić aplikację okienkową. Sesję z programikiem ca80mem ładującym kod do sterowania diodką RGB widzimy poniżej:



Program sterujący w Ardu jest równie nieskomplikowany, a jego głównym zdaniem jest interpretowanie nadsyłanych z komputera nadrzędnego rekordów w formacie Intel Hex i generowanie właściwych sekwencji sterujących magistralami systemu. Istnieje oczywiście możliwość zdalnego resetu systemu, gdyby jednak okazało się, że Z80 ma jednak jakiś problem z kontynuowaniem pracy po zwróceniu mu magistral. Zauważmy, że adres komórki pamięci do zapisu jest ustalany i wgrywany do rejestrów przystawki za każdym cyklem zapisu, daje to możliwość aplikowania „precyzyjnych łatek”, ale odbywa się to nieco kosztem ogólnej szybkości działania. Transmisja obszaru 8kB trwa w modelowym rozwiązaniu kilkanaście sekund, co wprawdzie nie poraża szybkością, ale jest w miarę akceptowalne.

Przy okazji Ardu chcę poruszyć temat współgrania oprogramowania i sprzętu. Rzućmy okiem na szkic PCB:



Jak widać, ścieżki idą sobie całkiem zgrabnie i na krótko pomiędzy pinami procesora Z80 i rejestru 74595. Tylko że takie uproszczenie powoduje wymieszanie sygnałów i przykładowo linia danych D0 trafi z bit numer 1 (QB) rejestru, bit trzeci tegoż (QC) to będzie dla odmiany linia danych D7. I tak dalej. Widać, że plątanina się robi na poziomie sygnałów, ale za to ścieżki mamy ładnie. Drugi koniec kija to spójne przypisanie sygnałów D0-QA...D7-QH, ale kosztem skomplikowania mozaiki ścieżek, które pewnie zdyskwalifikuje płytkę do wykonania mazakiem. I tu w mojej opinii jest miejsce na zastosowanie drobnej sztuczki z przekładaniem bitów na poziomie programu. Niby jest to komplikacja kodu, ale ja osobiście wolę wszystko zwalić na pogram i go poprawiać niż użerać się z fikuśną mozaika ścieżek. Zerknijmy na fragment kodu:

//ca80loader_ardu.ino
typedef struct {
  unsigned char QA : 1;
  unsigned char QB : 1;  
  unsigned char QC : 1;
  unsigned char QD : 1;  
  unsigned char QE : 1;
  unsigned char QF : 1;  
  unsigned char QG : 1;  
  unsigned char QH : 1;    
} T74595OUT;

typedef struct {
  unsigned char D0 : 1;  
  unsigned char D1 : 1;  
  unsigned char D2 : 1;    
  unsigned char D3 : 1;
  unsigned char D4 : 1;    
  unsigned char D5 : 1;
  unsigned char D6 : 1;  
  unsigned char D7 : 1;
} TData;

typedef union {
  unsigned char rawByte;
  TData         data;
  T74595OUT     outs;
} TWires;

Definiujemy sobie dwie strukturki, będące de facto polami bitowymi, najmłodszy bit jest pierwszy w kolejności wystąpienia w strukturze (dla implementacji avr-gcc). Oczywiście nazwy pól są zorientowane na rzeczywisty obiekt, D7-D0 dla procesora i QH-QA dla kostki rejestru. Następnie definiujemy sobie unię czyli takiego kameleona, który zależnie od kontekstu może być traktowany jako jeden ze składowych typów danych, u nas to: pole bitowe szyny danych Z80, piny rejestru '595 oraz zwykły, najzwyczajniejszy bajt do prostych przypisań. I teraz szkicujemy sobie funkcję - mapper, czyli nasza rozplątywaczkę do ścieżek:

//ca80loader_ardu.ino
unsigned char wireDataBus( unsigned char in ) {
  TWires z80pins, serReg;
  z80pins.rawByte = in;
  serReg.outs.QC = z80pins.data.D7;
  serReg.outs.QE = z80pins.data.D6;  
  serReg.outs.QF = z80pins.data.D5;
  serReg.outs.QH = z80pins.data.D4;  
  serReg.outs.QG = z80pins.data.D3;
  serReg.outs.QD = z80pins.data.D2;  
  serReg.outs.QA = z80pins.data.D1;
  serReg.outs.QB = z80pins.data.D0;  
  return serReg.rawByte;
}

No i na koniec sztuczka: jeżeli bajt danych przepuścimy przez taką funkcję mapującą przez wysłaniem do rejestru, to po wysłaniu - wybrane bity wejściowe pojawią się na tych liniach, na których sobie założyliśmy upraszczając bieg ścieżek. Tak komplementarnie - skoro mamy "poprzekładane" na płytce drukowanej, to aby mieć ciągle to samo musimy "odpoprzekładać" przed wysyłką. Cały program dla Ardu mocno eksploatujący tę sztukę znajdziemy w lokalizacji: ca80loader_ardu/ca80loader_ardu.ino Oczywiście można dyskutować o czasowej efektywności tego rozwiązania, stąd stosować je należy z rozwagą i tylko tam, gdzie naprawdę nas na to stać. Dla ciekawskich - proponuję sobie obejrzeć kod assemblerowy pozyskany z pliku *.elf i samodzielnie ocenić koszt takich bitowych manipulacji.

cd /tmp/arduino_build_?????
avr-objdump -d ca80loader_ardu.ino.elf

Inne podejście do tego tematu to realizacja lookup-table i potraktowanie bajtu wejściowego jako indeksu tabeli, zwracany element ma mieć bity poustawiane zgodnie z naszym mapowaniem i poplątanymi ścieżkami. Intuicyjnie rzecz traktując, takie rozwiązanie będzie o klasę szybsze, ale przygotowanie wsadu czyli treści tabel dekodujących może być cokolwiek upierdliwe, tak więc kwestia do decyzji - w którą stronę idziemy i czy w ogóle.

kompleksowy test ładowarki

Skoro opisywany układzik ma aspiracje do bycia narzędziem to wypada gruntownie go przetestować. Chwila prawdy polega na wyczyszczeniu RAM systemu CA80 i wgraniu przy pomocy ładowarki obrazu systemowego MIK33 ale od adresów 4000 i 8000 (moje dwa banki NVRAM specjalnego zastosowania). Porównanie zawartości przy pomocy wbudowanego zlecenia *86. Gdy są różnice - zlecenie pokazuje na którym adresie (guzik [=]), kolejne rozbieżności wyszukujemy sukcesywnie wciskając klawisz [.]. Gdy obrazy wskazanych obszarów są binarnie identyczne - zlecenie zwyczajnie wraca do monitora CA80. I to właśnie ma miejsce, co jest potwierdzeniem poprawnego działania ładowarki.



krytycznym okiem

Na koniec kilka uwag w odnośnie do korzystania z przystawki. Komputer CA80 obsługuje klawiaturę i wyświetlacz w przerwaniach niemaskowalnych NMI, na czas zwolnienia magistral procedurka obsługująca NMI nie pracuje, automatycznie nie działa multipleksowanie wyświetlacza. Jeżeli z ładowaniem trafimy akurat na moment, że wszystkie segmenty wyświetlacza są wygaszone to świetnie. Częściej jednak coś tam się na wyświetlaczu zapodzieje i ten przechodząc z pracy dynamicznej na statyczną zapali segmenty jednej z cyfr z pełną mocą. To zjawisko jest wręcz groźne dla wyświetlaczy VFD, więc proponuję zrealizować w dowolnie wybrany sposób (choćby przekaźniczkiem) obwód rozłączania napięcia anodowego na czas nieaktywności procesora Z80 – najłatwiej skorzystać z dostępnego sygnału /BUSRQ. Wypadałoby wspomnieć o ograniczeniach – najważniejsze to takie, że układ nadaje się do pracy tylko i wyłącznie z pamięciami statycznymi (w CA80 popularne są kostki 6116, 6264 czasem 62256) a wynika to faktu, że Z80 nie generuje cykli odświeżania pamięci dynamicznych gdy odda sterowanie magistralami. Pewnym wyzwaniem może być także praca w systemie, gdzie zrealizowano bankowanie pamięci RAM, to znaczy pewien zakres adresów jest współdzielony przez kilka układów, a ich wybór dokonywany jest stanem portu I/O. Tu akurat można dość łatwo zmodyfikować program ładowarki i obsługując dodatkowo sygnał /IORQ pokusić się o zapis do portu I/O i przełączanie banków, zachęcam do takich eksperymentów. No i pozostaje pytanie o stabilność systemu z sygnałami procesora wyprowadzonymi na odległość kilkunastu centymetrów. W moim przypadku taśma ma około 30 cm, a procesor Z80 taktowany jest zegarem 4MHz i całość pierwszorzędnie działa, czego wszystkim wespół z krasnoludkiem na zakończenie życzę.


#slowanawiatr, kwiecień 2019

Natasza Biecek 2004-2019/~, e-mail