Przedstawię dziś genezę powstania oraz niuanse techniczne cartridge'a, który nazwałem DCart, przeznaczonego dla 8-bitowych komputerów Atari. Jest to uzupełnienie informacji zawartych na mojej stronie dcart.pl (w języku angielskim), dedykowanej temu rozwiązaniu.
1. Świat cartów do małego Atari
Gdy spojrzymy na plik cart.txt z emulatora atari800, zawierający spis różnych typów cartów dla Atari, to od razu nasuwa się pytanie, po co tyle tego jest, oraz następujące po nim - czy jest sens robić coś nowego? Odpowiedź na te pytania należałoby rozpocząć od przestudiowania świetnego materiału na temat projektowania cartów kolegi Zenona.
Atari wymyśliło, że mamy dwa obszary po 8 kB, gdzie można wpiąć się z zewnętrzną pamięcią. A że to sumarycznie tylko 16 kB, to w sposób naturalny zaczęto kombinować jak tu obsłużyć coraz większe i coraz tańsze pamięci. Magistrala 16-bit ma tylko jedną odpowiedź: bankowanie. Co do bankowania pamięci RAM, standard jest narzucony przez PORTB, ale w przypadku cartów brak standardu. Dlatego każdy z producentów szukał sposobu, jak tu tanio i skutecznie zbudować cartridge, mając w różnym okresie historii różne zasoby i możliwości. Stąd wiele istniejących równolegle rozwiązań, mniej lub bardziej popularnych. Gdy przyjrzymy się opisom sposobów bankowania cartów to dostrzeżemy, że wszystko idzie z grubsza według jednego szablonu. Pamięć ROM/Flash wpięta w obszary $8000:$9FFF i/lub $A000:$BFFF, a sterowanie idzie przez stronę $D5XX, z wykorzystaniem sygnału nCTTL. Generalnie wszystko podobne, różniące się szczegółami...
2. Po co coś nowego?
No dobrze, ale co jest najlepsze dziś? Gdy weźmiemy pod uwagę wszystko, co najlepsze na rynku to pojawi się dylemat, bo drogi są dwie. Jedna to wykorzystać zaawansowany układ FPGA lutowany w BGA, gdzie rdzeń może zaemulować stado komputerów Atari w jednym cyklu. Albo można wziąć z półki to, co najlepsze się ostało w "klimacie retro świata" czyli "przewlekane pięć wolt".
Wiadomo, że o rozwiązaniu optymalnym decydują kryteria (np. prostota budowy, specyficzne potrzeby, pojemność, możliwość zapisu, cena czy dostępność części). Ponieważ przyjmowano różne kryteria to mamy wysyp "standardów". W takim razie i my ustalmy własne kryteria i zobaczymy, co z istniejących rozwiązań je spełnia. No to niech będzie:
łatwy – wpina się do Atari i od razu działa, a jak mi się coś odmieni, to żeby dało się go przeprogramować
prosty – żeby lutowanie poszło nawet "lutownicą do rynien" czyli ma być z elementów przewlekanych;
tani – minimum elementów, czyli 5V i jedna pamięć, jeden układ sterujący, jeden filtr, jeden przełącznik;
ładny – znam tylko jedną profi obudowę dla carta (kopia oryginalnego karta serii XE/XEGS, produkowana przez SikorSoft), więc niech pasuje do niej;
znany – niech jest możliwie jak najbardziej kompatybilny z dostępnymi już narzędziami/standardami; chociaż to kryterium jest kontrowersyjne, bo w świecie retro bardzo często odkrywa się koło na nowo, ale za każdym razem daje to ogromną frajdę odkrywającemu… nawet jak to robi już któryś tam raz po kimś
Największa przewlekana pamięć flash dostępna na rynku, pracująca wprost z 5V, ma pojemność 512kB. I pod te parametry będziemy stroić orkiestrę. No bo więcej to albo SMD, albo kombinowanie z przełączaniem pamięci, albo trzeba zejść z konwerterami na 3V3, a po co komplikować sprawę.
3. Analiza rozwiązań
Patrząc na wspomnianą listę cart.txt z emulatora atari800, nie widzimy wielu "standardów" dla 512 kB. Są wyraźne zaledwie dwa. Pierwszy to Switchable XEGS 512 KB cartridge a drugi Atarimax 1 MB Flash cartridge (w skrócie maxflash). Ale jak to 1 MB? A no tak, że ten 1 MB to są dwie kości po 512 kB i przewidziano, że można wlutować tylko jedną.
Switchable XEGS 512 KB cartridge bazuje na atarowskim XEGS 128 KB cartridge (tu mała osobista dygresja, gra "Flight Simulator" na cartridge'u w tym standardzie to był pierwszy powód, dla którego w ogóle wziąłem się za poznawanie tajemnic cartów). Standard bardzo fajny, świetnie rozpracowany przez kolegów ccwrc oraz x_angel w artykule Atari custom WB/XEGS PCB. Cart może być włączany/wyłączany dynamicznie. Jeden obszar (ostatnie 8 kB pamięci flash) jest cały czas widoczny w drugim banku, a przełączamy bankiem pierwszym. Bardzo to wygodne, bo cześć kodu nam siedzi w stałym miejscu, bez względu na to, który bank włączymy. PCB proste do złożenia, łatwo dostępne. Jedyne, co nam może brakować, to brak możliwości zapisu.
Atarimax 1 MB Flash cartridge może nam zapisywać. Co prawda tylko w konfiguracji Atarimax, ale jest furtka. Kolega Jakub Husak zrobił świetne narzędzie, program flashujący, który ogarnia wszystkie pamięci pracujące zgodnie z maxflashem. Dla tego typu cartów jest też fajne narzędzie "Maxflash Studio Software". Dzięki temu zrobienie własnej składanki programów na cartridgu'u to proste "poklikanie", w połączeniu z programem flashującym, który przygotuje plik do uruchomienia na Atari, do zaprogramowania carta, mamy wszystko co trzeba. Jest jeszcze jedna istotna zaleta: zgodność ze SpartaDOS-X. Jedna z kompilacji jest przygotowana właśnie dla maxflasha. I co ciekawe, sam SpartaDOS-X zajmuje do 128kB, drugie 128kB to są manuale. Mając kostkę 512kB zostaje nam jeszcze sporo miejsca na dodanie własnych narzędzi (i to jest drugi powód, dla którego pociągnąłem do końca projekt budowy DCarta).
Z powodu swej komercyjności, rozwiązanie Atarimax 1 MB dość mocno zawęża pole do manewrów. Narzucona została pamięć, płytka PCB, sposób programowania. Nie spełnia naszych kryteriów. Ale produkt to jedno, a sposób sterowania to inna bajka.
W maxflashu uznano, dla uproszczenia układu sterującego, że przełączanie bankami będzie odbywać się przez zapis adresu. Czyli POKE $D500,cośtam włączy nam bank 0, a POKE $D501,cośtam włączy bank 1. Zwróćmy uwagę, że POKE $D500,numerbanku, jaki jest w Switchable XEGS, wymaga bardziej skomplikowanej logiki. Adres strony $D5XX to 8 bitów. Gdy 7 bit jest ustawiony jako 1 to cart jest odpinany (RD5 przyjmuje stan niski). Jak mamy tylko jedną kość pamięci to bit 6 jest ignorowany. Wtedy POKE $D5FF,cośtam wyłącza carta.
Prosta logika maxflasha ma jedną cechę, która dla mnie jest ogromną wadą. PEEK($D5XX) przełączy nam bank carta. I wydawałoby się, że to bez znaczenia. Większość rozsądnych programistów do wyboru banku zastosuje w swoim programie np. STA $D500,X, bo LDA to jakieś takie "dziwne". Tylko wyobraźmy sobie, że nie chodzi o to, czy w kodzie będzie LDA od CPU, ale jakikolwiek odczyt na magistrali w tym zakresie $D5xx przełączy nam bank. Nawet jak to będzie ANTIC, który właśnie poleciał w "maliny". A dla niego to nie trudne, bo zwykle gdzieś tam "pląta się" po wyższych adresach. Wyłapanie takiego buga, gdzie ANTIC przełącza nam banki carta, graniczy z cudem. Wyłączone przerwania, program siedzi na pętli JMP do_siebie, a i tak nagle wszystko się wiesza.
3. Moje zmiany
Taka sytuacja jak powyżej opisałem, mocno mnie kiedyś przeczołgała. Mnóstwo straconego czasu, aby dojść, gdzie jest błąd. Dlatego pierwszą zmianą (mutacją), jaką zaproponowałem, było to, by cart nie mógł się przełączać na odczytach. Tylko zapis do rejestru może coś zrobić. Logiczne. A że zupełnie to nie przeszkadza aplikacjom typu SpartaDOS, no to wszystko gra.
Sterowanie bankami musi mieć minimum dwie jednostki. Zatrzask, który będzie pamiętał wybrany bank. Czyli na przykład POKE $D503,coś zapamięta w rejestrze $03 czyli bank 3. I będzie to pamiętane aż do powtórzenia tej figury sprawczej. Logikę, która ogarnie, że nCTTL jest niski, że zegar jest tak, a RW tak (zwłaszcza jak chcemy mieć zapis), trzeba gdzieś zrealizować. Mniej więcej wychodzi, że dwie ekstra TTL-ki trzeba dać. Do tego zatrzask po włączeniu Atari należy zresetować. No i robi nam się już trochę elektroniki na płycie, która musi być na rynku, którą trzeba zamówić, zapłacić i zlutować.
A gdyby logikę i zatrzask zastąpić jednym układem programowalnym, GALem? Dobranym w stylu retro, przewlekanym na 5V. Fakt, trzeba go będzie raz w życiu zaprogramować, ale w zamian dostaniemy pewne korzyści. No i tak wyszła nam kolejna mutacja. Cart będzie przełączał banki na zapis do $D5XX. A odczyt? Wygląda na to, że nic nie robi. No to niech coś robi, dlaczego ma się marnować? I tu opiszę mały trick, który robi z cartridge'a DCarta.
Gdy użyjemy PEEK($D500), na magistrali pojawi się wartość $D500 czyli 1101010100000000. Teoretycznie na stronie D5 interesuje nas tylko to, co w poniższej tabelce oznaczone na niebiesko. Ale przecież magistrala cartridge'a sięga aż do $A12, więc to, co oznaczone boldem też będzie określone. Co oznacza, iż można tak zrobić, że nawet jak cart jest wyłączony, to PEEK zaglądnie do carta. A gdzie zaglądnie? Pod adres $1500 banku (10101=$15). Atari widzi bank od adresu $A000, więc $A000+$1500 daje nam $B500, co tworzy kopię adresu $D500. W skrócie: PEEK($D500) odczyta nam, nawet przy wyłączonym carcie, to samo co PEEK($B500), gdyby cart był włączony. W praktyce piszemy (w najlepszym assemblerze dla małego Atari czyli MAD-sie):
ORG $B500 MYPROC .local D5WIN,$D500 STA $D500 JSR $A000 STA $D580 RTS .end
Teraz, nawet gdy cart jest wyłączony i cała pamięć RAM jest dla nas, robimy JMP $D500, tam czeka nasza procedurka, która może na chwilę włączyć bank, potem skoczy do $A000 z pamięci flash, po powrocie wyłączymy carta, ale D5 z kopią z banku cały czas będzie widoczny. Robimy RTS i wracamy gdzieś tam z wywołania. Wszystko przeleciało bez użycia RAM! Jedyne, na co trzeba uważać, to na jakim banku wyłączamy carta. $D580 to bank 0, ale jak wyłączymy przez $D581 to na banku 1. Tam może być inny kod. Ten trik masowo wykorzystuje SpartaDOS X. Z tym, że robi na zakresie $A000-$BFFF. Wygląda to dość zabawnie, bo używamy STA $D501, a tu następna instrukcja leci z innego banku.
Czy jest to przydatne? Jeżeli nie ma potrzeby to nie używamy i mamy wszystko jak w maxflash. Dla mnie przydatne, bo znacznie poprawiło sprawność w moim konwerterze plików ATR na wsady carta (o nazwie "ATR2DCART", następcy "ATR2CAR"). Zwykle gry/programy całodyskowe panoszą się po całym RAM. Nie ma pewności kiedy jaka komórka pamięci zostaje użyta. Klasyczny maxflash wymaga procedury obsługi w RAM, więc jest zagrożony. Umieszczenie procedury na stronie $D5 czyni ją niezniszczalną, zwłaszcza gdy jej kopia jest w każdym banku. Gdy program chce czytać z dysku i wykonuje JMP DSKINT to podmieniamy na JMP $D500, a tam już czyha odpowiedni magik, który sprawdzi czy na pewno lecimy do DSKINT czy jednak może odczytamy sektor z carta.
4. GALu, zrób co trzeba
Pomysł jest, więc trzeba go zrealizować. Jeden GAL może w sobie mieć i zatrzask i logikę jednocześnie. GAL umie też ładnie się podnieść po włączeniu. Kolejna zaleta - oprócz pinu zegarowego mamy dość dużą dowolność w przypisaniu sygnałów wejściowych i wyjściowych. W efekcie można zminimalizować liczbę przelotek na PCB. No i najważniejsze, produkuje sygnały z bardzo dobrą tolerancją czasową, czego nie da się uzyskać łącząc różne TTLki. A wiemy, że najważniejszy sygnał PHI2 porusza się po złączu carta jak po pijaku. Wtedy GAL dość dobrze prostuje jego chwiejne nogi.
Piny w GALu przyporządkowujemy łopatologicznie,
wejściowe: PIN 1 = CLK; PIN 2 = WP; (…)
wyjściowe: PIN 14 = RD5; (…)
Zapis dla logiki również jest prosty, przykładowo: nCE = ( nS5 & ( nCCTL # nRW ) ) ;
Troszkę kłopotów sprawia robienie zatrzasków. Jak zrobić, żeby po włączeniu był pożądany stan? Ponieważ GAL ma tylko jeden sygnał zegarowy i do niego podłączyliśmy PHI2, to nie ma innej możliwości i przy każdym zboczu narastającym zegara będzie się zatrzaskiwał. Ale stary trick pozwoli nam zatrzaskiwać to, co miał ostatnio, lub zatrzaskiwać to, co ma nowe. Dla bitu, który po włączeniu zasilania ma mieć zero: Logika: trig = ( CCTL & nRW ); ntrig = ( !trig ); i zatrzask: A13.D = ( ( trig & A0 ) # ( ntrig & A13 ) );
A dla bitu, który ma mieć jeden po włączeniu. Wszystko pracuje jakby w negacji, ten wykrzyknik jest informacją dla kompilatora, że ma aktywować NOT na wyjściu z przerzutnika: RD5.D = !( ( trig & A7 ) # ( ntrig & ( !RD5 ) ) );
Teraz najciekawsze, żeby DCart stał się DCartem: nCE = ( nS5 & ( nCCTL # nRW ) ) ; czyli widać, że gdy nCCTL będzie niski i zażądamy odczytu, to pamięć flash dostanie ChipEnable. Patrząc na zapis łatwo wykombinować (co wykasować), żeby z DCarta zrobić zwykłego maxflasha. Przy tej samej płycie i tej samej elektronice.
Aby cart był zapisywalny, trzeba zerknąć jaka pamięć flash jest użyta. SST39SF040 ma najmniejszy sektor i została przeze mnie wybrana, bo może w przyszłości uda się zrobić zapis dla emulowanych plików ATR. SST39SF obskoczymy kodem: nOE = ( nRW ); nWE = ( nS5 # RW # nPHI2 # nWP );
5. Reszta to formalność
Mamy więc jedną pamięć flash, sterownik w postaci GAL, gdzie mogliśmy sobie wygodnie przyporządkować sygnały. Teraz PCB to tylko „druty” i parę przelotek. Płytę bazową, według szablonu kolegi Mq, która pasuje do obudów SikorSoft widzimy poniżej.
Żeby jeszcze coś pożytecznego dodać, to opcjonalnie jest przełącznik WriteProtect. Jak przy dyskietce, zabezpieczmy przed zapisem poprzez przestawienie pozycji. Można tego nie wlutować, za to zrobić sobie coś innego w tym miejscu. Np. przycisk reset (pady pod rezystory podciągające są już pod rezystory SMD). Z kolei dioda to pomysł kolegi kkrys. Separujemy GALa i jego stan niski od sygnału RD5, dzięki czemu zadziała nam ładnie HardReset.
DCart jest rozwiązaniem w pełni otwartym, bez żadnych ograniczeń. Można korzystać edukacyjnie, hobbistycznie, a nawet komercyjnie (PCBWay). Dokładne opisy, pliki i narzędzia wspomagające można znaleźć pod wspomnianym adresem dcart.pl. Projekt i opis powstał dla wzbogacenia idei rozwijanej przez Polskie Towarzystwo Ochrony Dziedzictwa Technicznego.
Przepiękne. Już sama ilość wolnego miejsca na PCB daje ogromne możliwości dla własnej inwencji twórczej :)
Tylko małe sprostowanie: obudowa od Sikora nie jest kopią obudowy cartów XE (wbrew pozorom bardzo się różni). Założeniami przy projektowaniu między innymi była zgodność z dwoma typami oryginalnych cartów Atarowskich: od WB i od karbowanych szaraków XE.
Mq @2024-08-09 00:28:33
Gratuluję! Dobrze wymyślone. Oby tylko 22V10 były dostępne bez ograniczeń, bo jak nagle znikną, to nie bardzo miał bym pomysł żeby go się dało czymś zastąpić. Gówniane to czasy, że każdy projekt wisi na włosku przez (nie)dostępność elektroniki, bo ktoś z góry decyduje co ma być teraz akurat dostępne lub nie.
zenonek @2024-08-09 07:07:39
Eksperymenty i wytrwałość skutkują powodzeniem. To lubię. Najlepszy pomysł twórców Atari, by było to gniazdko. Bez niego . . . THE END.
zenonek @2024-08-09 07:08:02
Eksperymenty i wytrwałość skutkują powodzeniem. To lubię. Najlepszy pomysł twórców Atari, by było to gniazdko. Bez niego . . . THE END.
zenon @2024-08-09 07:09:55
No tak, dwa razy poszło to samo. Proszę usunąć niepotrzebne
GienekP @2024-08-09 09:18:27
W sumie to należą się podziękowania całej społeczności ATARI. Projekt jest kompilacją pomysłów, przemyśleń i wskazówek od ludzi, którzy cały czas coś przy cartach grzebią. Tak, to "gniazdko" jak określił Zenon, to z jednej strony pozostałość po konsolach, ale z drugiej strony okno na świat dla dzisiejszej elektroniki. I żeby nie wpaść w zagrożenie o którym wspomniał Mq, trzeba cały czas działać, bo jeszcze wiele rzeczy zostało do przepchania przez złącze ATARI Cartridge.
Racjonalista @2024-08-09 09:26:39
Mq: " bo ktoś z góry decyduje co ma być teraz akurat dostępne lub nie."
Czytasz mi w myślach. Tajemny krąg steruje rynkiem chipów realizując w ten sposób strategię "NWO" i "DEPO". Dokładnie! Dobrze , że nie jestem osamotniony we wnioskach.
BartGo @2024-08-09 09:56:57
Powiedzmy, że jako la(jkon)ik chciałbym na DCart trzymać dane (nie program wykonywalny) i czytać (pisać?) po nich paczkami po 1kB. Czy dobrze rozumiem, że to byłoby do wykonania w dwóch krokach:
1) przełączając się na nowy bank robię POKE dowolnej wartości (np. $FF) do $D500..$D57F (zależnie od ośmiokilobajtowego banku, który chcę)
2) PEEK/POKE na przedziale $A000..$BFFF daje dostęp do dodatkowej pamięci.
Tak po prostu? Jeśli faktycznie, to jest to dla mnie BARDZO użyteczne.
Super rzecz. Miałem i wciąż mam okazję testować DCart i jestem niebywale zaskoczony prostotą rozwiązania. A co najważniejsze - bardzo łatwo można było przystosowywać wsad do swoich własnych potrzeb. Tak o to powstał MIDIcarSDX - bazujący właśnie na DCart!. GienekP - masz świetne pomysły a my korzystamy z Twojej wiedzy na maksa :-) Dzięki!
Jeżeli ktoś będzie chętny poznać GienekP na żywo albo zadać mu jeszcze jakieś pytania to przypomnę, że będzie obecny na najbliższym LWAS-ie (w Krakowie), wstępne infona forum: https://atarionline.pl/forum/comments.ph...
Zenon @2024-08-09 12:06:46
GienekP napisał że jeszcze wiele rzeczy zostało do przepchania przez gniazdko.... To moje (nie wszystkie) działające projekty: Programator EEPROM AT28C64 i nie tylko Programator EPROM do 512k Programator procesora AT89Cx051 WERONIKA, Atari współpracuje z drugim procesorem Interface drukarki igłowej Sterownik perforatora (taśma papierowa do tokarki CNC) Sterowniki różne do zabawek (samobieżny samochodzik etc...) Sterownik, moduł do testów z wyświetlaczem LCD Zegar, minutnik połączony kabelkiem ok. 10 No i takie fajne kartridże do gier jak LAURA, BOMB JACK i inne Halo! Dopisywać kto tam ma co jeszcze swojego.
vega @2024-08-09 12:11:20
jeżeli powstanie nowa gra to ja pod karta od razu zrobię wersję :)
vega @2024-08-09 12:12:50
fajnie jakby takie karty mogły coś dopalić...sprity programowe to jednak mocno obciążają procesor...aczkolwiek mając tyle pamięci to i tak sporo daje na szybkości
Mq @2024-08-09 13:42:31
@BartGo: jeśli chodzi o odczyt kartridża, to jest dokładnie tak prosto jak piszesz. Jeśli natomiast chodzi o zapis, to nie jest to już taka pojedyncza sprawa, bo to nie jest pamięć RAM, tylko EEPROM, więc obowiązuje protokół współpracy z taką pamięcią, trzeba wysyłać do niej odpowiednie komendy żeby kasować sektor takiej pamięci lub całą pamięć i wtedy można (też odpowiednimi komendami) zapisywać pojedyncze bajty. Dodatkowo trzeba pamiętać, że pamięć taka nie jest wieczna i ma ograniczoną ilość cykli kasowania/zapisu. Nie ma tragedii, bo to jest na poziomie 100-200tys cykli, ale trzeba to mieć na uwadze, żeby nie robić jakiegoś ciągłego zapisywania i kasowania w tym samym miejscu, bo można szybko osiągnąć limit wbrew pozorom. Natomiast jakieś zapisy sejwów w grach, czy zmiany zawartości całego EPROM-u okazjonalnie, to jak najbardziej się sprawdza dobrze, tylko trzeba do tego sobie napisać procedurkę która to robi, bo zwykłe POKE nie zapisze nam nic do EEPROM-u.
Wróż Maciej @2024-08-09 14:28:41
Mq - pisząc EEPROM i EPROM miałeś prawdopodobnie na myśli pamięć flash o której mowa w tym projekcie. Bo procedury zapisu na EPROM wyglądają zupełnie inaczej niż to co mówisz, prawda? To tylko tak w ramach sprostowania.
Wróż Maciej @2024-08-09 14:30:38
chociaż teraz czytam że EEPROM to cała rodzina obejmujące też pamięci flash, więc możesz też mieć racje. to już się nie wtrącam :D
Wróż Maciej @2024-08-09 14:34:17
a projekcik super fajny. podoba mi sie to tajne okienko przy wyłączonym karcie.
GienekP @2024-08-09 16:24:11
Zenon, super te projekty. Ja teraz mam na stole współpracę z drugim prockiem. Zobaczymy ile czasu dla niego zostanie jeżeli na gnieździe carta siądzie atarowski CPU i ANTIC.