♫ ♩ ♪ Walk In Darkness ⚡ ☘ ⚡ Time To Rise ♪ ♩ ♫
https://youtu.be/hG8Ged5Hb5c
Zakładam, że większość owej pisaniny po pewnych reedycjach i uporządkowaniu wyląduje na bienata, na podstronach właściwych CA80, ale póki co tu chciałabym opisywać to, co spontanicznie się dzieje.
Temat interfejsu szeregowego do komputerka CA80 nie jest nowy, choćby w Radioelektronik 1/94 opisywano całkiem sympatyczną konstrukcję takiej przystawki http://bienata.waw.pl/ca804.php Między innymi ten właśnie artykuł za lat mych szczenięcych skutecznie konkurował z koniecznością uczenia się do matury, no cóż - definicja słowa pokusa jest jak widać wielowymiarowa. I nawet coś tam powstało i to dokładnie na bazie kostki 8251A, pamiątkowa fotografia poniżej.
Sprawa RS232 do CA80 nabrała ponownie rumieńców po skleceniu `Ładowarki do pamięci` no i chyba też po rozpoznaniu pakietu SDCC, narzędzia deweloperskie są, można się zmierzyć z tematem raz jeszcze, a cel ćwiczenia zdefiniowałam następująco: ma powstać przystawka/rozszerzenie do starego CA80 umożliwiające komunikację szeregową na dwóch niezależnych kanałach z typowymi (dla mojego retro) parametrami transmisji. Całość utrzymana w klimatach antycznych, nowobogackie wstawki ograniczone do minimum. Oprócz podstawowej komunikacji via RxD/TxD ma być dostępne proste I/O na okazję eksperymentów z RS485, do przełączania kierunków. Dlaczego akurat do starego CA80? Na trzech laminatach?
No właśnie ze względu na otwartość tej konstrukcji (wyprowadzona szyna systemowa), tego brakuje nowej wersji CA. No i z chwilą sklonowania pcb MIK290 nowy CA80 stracił dla mnie cały urok i smaczek kolekcjonerskiej niszy. Docelowo przystawka ma stać się integralną częścią systemu, podobnie jak płytka MIK89 z kostkami 8255 i Z80-CTC.
Wybór UART... no cóż, tu łatwo nie miałam. Kostkę Intel 8251 obćwiczyłam swego czasu dokładnie, była dodatkowo w użyciu w komputerku dino-85, tak więc nuda to nieco. Dodatkowo, jej integracja z systemem przerwań maskowalnych oznaczałaby konieczność rezygnacji z trybu IM2 ( a to mnie aktualnie intryguje ) lub zagonienie do współpracy kostki Z80-CTC (jako odbiorcy/generatora przerwań), tak czy inaczej fotomontaż. No i dwa kanały to dwa takie układy.
Podobnie wychodzi z 8250 czy 16550, całość zoo w trakcie przeglądu w formie wystawki na fotografii.
Niby implementacja tych kostek jest prosta, ale to jednak układy z poza rodziny Zilog, pełna integracja wymagałaby kilku dodatkowych zabiegów sprzętowych. I tym prostym sposobem stanęło na tym, że w interfejsie będzie pracował dedykowany układ Zilog, wybór w tym zakresie mamy w sumie niewielki - SIO lub DART. Układów DART mam tylko dwa, więc instynkt samozachowawczy odradził pakowanie się w użycie kostek, których nagły zgon (np. z nieprzemyślanej mej głupoty) skutecznie rozłoży projekt. Układów SIO znalazło się kilka, niemniej jednak w większości posiadały one dość istotną wadę - wygląd. A raczej jego brak. Podpisane MME wyglądają tak, jakby zrobiono je pilnikiem w stodole, to już nasze układy CEMI czy rosyjskie klony wyglądały o niebo lepiej.
Na szczęście znalazł się egzemplarz SIO, który nadaje się do ludzi - tak więc reszta wywodów będzie skoncentrowana na Z80-SIO/0, choć to nie rasowy Zilog ale włoski SGS Microelettronica (potem SGS-THOMSON, finalnie STMicroelectronics).
W trakcie prac kartkowane namiętnie są dwie pozycje - Zilogowy manual od gawła i po naszemu, kniżka bodajże z bazarku.
Testowo roboczy schemat ideowy prezentuje się skromnie, ale to piaskownica to dalszych zabaw:
Kostka Z80-SIO posadzona na płytce stykowej nie wymaga póki co dodatkowych elementów, sygnał zegarowy CLK taktujący interfejs od strony procesora pochodzi z CA80, taktowanie rejestrów przesuwnych transmisji szeregowej (RxTxC, itp) zrobiłam sobie z Analog Discovery 2, podobnie jak podgląd tego, co układ nadaje po zaprogramowaniu testowym kodem.
No i póki co jest całkiem nieźle, kostka jest rozmowna i AD2 całkiem ładnie pokazuje to, co jest wysyłane przez dwa niezależnie pobudzane kanały:
Fragment "programu" głównego:
sio_demo_1.c pisze:Kod: Zaznacz cały
const char *pMsg[2] = {
"Tosia",
"tasza"
};
unsigned char n;
sioInit();
while (1) {
for (n = 0; n < strlen( pMsg[0] ); n++ ) {
putChar( 0, pMsg[0][n] );
}
for (n = 0; n < strlen( pMsg[1] ); n++ ) {
putChar( 1, pMsg[1][n] );
}
delay( 10 );
}
A to szkic funkcji putChar() w wersji blokującej, z kontrolą wysłania znaczka:
sio.s pisze:Kod: Zaznacz cały
SIO_BASE .equ 0xE8
SIO_A_DAT .equ SIO_BASE+0
SIO_B_DAT .equ SIO_BASE+1
SIO_A_CMD .equ SIO_BASE+2
SIO_B_CMD .equ SIO_BASE+3
;
_putChar:
ld IY,#2
add IY,SP
ld A,0(IY) ; numer kanału (0,1)
add A,#SIO_A_CMD ; SIO_A_CMD+0 lub SIO_A_CMD+1 czyli SIO_B_CMD
ld C,A ; będzie od teraz numerem portu
; czekaj aż skończy poprzedni transfer
putChar_wait:
ld A,#0
out(C),A ; wybierz RR0 wskazanego kanału
in A,(C) ; daj RR0
bit 2,A ; czy Transfer Buffer Empty? (D2==1)
jr Z,putChar_wait ; to czekaj dalej
; przerób _CMD na _DAT czyli C := C-2
dec C
dec C ; w C jest adres portu danych :)
ld IY,#2
add IY,SP
ld A,1(IY) ; weź znaczek
out (C),A ; i wyślij
ret
I tu tak ogólnie mam teraz dylemat - jak zaprojektować wygodne API do tej kostki. Widzę trzy konkurencyjne warianty: osobne zestawy nisko i wysokopoziomowych funkcji dla każdego z kanałów (np. putCharA, putCharB), można też (jak w przykładzie powyżej) podawać numer kanału jako parametr wywołania. Można w końcu poprzestać na uniwersalnym putChar() a nazwijmy to kontekst pracy (kanał - A lub B) wskazywać dodatkową funkcją, dziwne to ale gdzieś w tyle głowy mi kołacze. Póki co jest jak widać funkcja z parametrem.
Rozkład rejestrów Z80-SIO jest jak w definicjach .equ powyżej, przy pomocy nieskomplikowanych zabiegów można wskazać zarówno rejestr poleceń jak i danych wybranego kanału przez proste operacje arytmetyczne, co powyższy kod skrzętnie wykorzystuje i funkcja całkiem ładnie działa.
#slowanawiatr