Z komputerem Commodore 64 pierwszy kontakt miałem w 2001 roku mając 14 lat. Podłapałem trochę Basica i zacząłem pisać proste programy użytkowe. Mój ojciec, widząc mój zapał do programowania, sprawił mi pół roku później peceta, a C64 odeszło do lamusa. 22 lata później, podczas sprzątania piwnicy, postanowiłem wyczyścić i odrestaurować swoją maszynę. Komputer był mocno zakurzony, ale na szczęście korozja nie uszkodziła płyty głównej. Najbardziej pracochłonnym zadaniem było odrestaurowanie plastikowych części, mocno nadgryzionych i zażółconych przez czas i promienie UV.




Mając już wyczyszczoną i uruchomioną maszynę, postanowiłem coś na nią napisać. Programowanie w Basicu czy Asemblerze nie było dla mnie. Znalazłem w sieci kompilator dla procesorów 6502 o nazwie CC65
Przez kilka tygodni szukałem pomysłu na swoją pracę. Założenie było takie, aby dało się wykorzystać któryś ze sprzętowych interfejsów komputera, co wymagałoby zaprojektowania również jakiejś elektroniki. W ramach przymiarek inżynierskich zacząłem eksperymentować z user portem. Po opanowaniu konfiguracji i sterowania, wpadłem na pomysł adaptacji gry CodeBreaker / Mastermind, w którą zdarzyło mi się kiedyś zagrać. Zamówiłem przez Internet egzemplarz gry, który miał mi posłużyć za obudowę dla elektroniki.
Planowana zasada działania elektroniki miała polegać na pomiarze czasu ładowania kondensatora na każdym z czterech pinów wejściowych. Czas ładowania miał być różny, w zależności od włożonej małej płytki PCB, na której znajdował się rezystor oraz miejsce na oznaczenie kolorem.

User port w C64 posiada między innymi jeden 8-bitowy port GPIO (PB) oraz zasilanie 5V.
Aby zrealizować działanie gry potrzebowałem:
Aby uzyskać wymaganą ilość pinów wyjściowych użyłem demultipleksera 4HC4514PW,118 z 4 linii na 16, z czego wykorzystanych zostało 10 sygnałów. Połowa portu B była zatem skonfigurowana jako wejście, a druga połowa jako wyjście.

Część wykonawczą, realizującą załączanie zasilania i pomiar, wykonałem za pomocą małych przekaźników RSM957N-0111-85-S005 sterowanych przez tranzystory MMUN2214LT1G. W każdej sekcji odpowiednie diody jak D40 i D20 zastąpiłem rezystorami 0R, ze względu na zbyt wysokie napięcie przewodzenia diod KP-2012MGC, co uniemożliwiało ich świecenie w momencie wysterowania.

Ze względu na rozrzut technologiczny związany z technologią MOS, bezpośredni pomiar czasu ładowania kondensatora bezpośrednio na pinie user portu nie byłby praktyczny. Aby obejść ten problem, zastosowałem konstrukcję z użyciem tranzystora MMUN2214LT1G. Ten model przełącza się, gdy na jego wejściu (bazie) napięcie przekroczy 1V. Dzięki temu możliwe było wykonanie obwodu, który będzie działał w powtarzalny sposób.

Kolejnym aspektem pracy elektroniki było zapewnienie rozładowania kondensatorów pomiędzy pomiarami. W tym celu zastosowałem bocznikowanie za pomocą rezystorów o wartości 1M Ohm.

Dzięki wsparciu kolegi Ralpha w zakresie mechaniki i modelowania CAD, dostałem szczegółowy model 3D obudowy, abym mógł zaplanować w odpowiednich miejscach złącza na płytki PCB reprezentujące wybrany kolor.
Aby móc korzystać z userportu, konieczne jest użycie dedykowanego złącza:

Na potrzeby projektu zaprojektowałem płytkę PCB umożliwiającą krawędziowy montaż złącza user portu oraz montaż przewodu. Płytka posiada także dedykowany konektor, który zostanie użyty w przyszłości do innego projektu.


Od początku założeniem gry nie były efekty graficzne. Gra została podzielona na 2 tryby:
Kluczowym fragmentem kodu jest procedura rozpoznająca obsadzone kolory:
Jako argument wejściowy przekazywany jest numer aktualnej rundy w celu odpowiedniego ustawienia multipleksera.
Na początku funkcji ustawiany jest port B w taki sposób, aby tylko górna część portu pracowała jako wyjście. Następnie zerowane są globalne tablice Ball oraz Ball_Lock w których przechowywane będą początkowo czasówki z odczytów, a później wartości konkretnych kolorów.
Wywołanie procedury SetDemux (0) powoduje brak wysterowania jakiegokolwiek przekaźnika wyzwalającego ładowanie kondensatorów.
Po rozładowaniu kondensatorów (np. z poprzedniej rundy) wywoływana jest funkcja SetDemux(RoundNumber), która załącza odpowiedni przekaźnik w celu wykonania pomiaru.
W pętli inkrementowana jest zmienna 16-bitowa Delay, której chwilowa wartość jest zatrzaskiwana w konkretnych polach tablicy Ball[]. Po wykonanym pomiarze, wartości ulegają konwersji na konkretne kody kolorów.



