Kolejna płytka PCB

Miałem się wziąć za pisanie monitora dla mojego komputera i nawet ostatnio trochę podgoniłem robotę. Mogę już wpisywać z klawiatury pierwsze programy i mogę je też uruchamiać. Gorzej jest z przeglądaniem pamięci – na razie to można robić w ograniczonym zakresie. Wzięło mnie natomiast za przeprojektowanie płytki PCB. Poprzednia płytka miała dwie wady, które były na tyle denerwujące, że zdecydowałem się na zrobienie poprawki. Pierwszą wadą było rozmieszczenie pinów z wyprowadzeniami tak, że nie mogłem podłączyć płytki PCB bezpośrednio do płytki prototypowej. Drugą wadą było kiepskie umieszczenie wyprowadzenia do połączenia zasilania z obu płyek, które często nie kontaktowało, w wyniku czego mój komputer często sam się restartował. Efekt mojej pracy poniższej:

Poprawiona płytka PCB

Jak widać na zdjęciu, wszystkie wyprowadzenia sygnałów, łącznie z zasilaniem, są umieszczone w jednej lini z takim rasterm, że płytka da się już zamontować bezpośrednio na płytce prototypowej. Dodatkowo zrobiłem miejsce na przylutowanie pojedynczej bramki inwertera (75hc1g04), która w razie potrzeby będzie mogła z sygnału RW zrobić sygnał OE potrzebny do sterowania pamięciami. Samego inwertera na razie nie przylutowałem, bo tą funkcję na razie robi dekoder adresów.

Poniżej zdjęcie płytki zamontowane na płytce prototypowej oraz dwa zdjęcia mojego komputera, z nową płytką oraz dla porównania z poprzednią płytką:

moje „opus magnum” ostatnich miesięcy 😉
komputer z nową płytką
komputer z poprzednią płytką

Jak widać na powyższych zdjęciach znowu ubyło sporo kabli. Połączenia są teraz na tyle trwałe, że komputer mógłbym bez problemów przenosić, gdyby nie wypadające gniazdo zasilania. Pojekt płytki umieściłem na github’ie. Można go pobrać tutaj.

Na wyświetlaczu widać już pisany przeze mnie monitor. Dodatkowo dodałem też nakładkę na klawiaturę z opisem klawiszy. Układ klawiszy pewno jeszcze ulegnie zmianie – muszę jeszcze nad nim pomyśleć.

Sama klawiatura (jak widać na dolnym zdjęciu: złożona z czterech klawiatur 4×4) też nie działa najlepiej, więc proszę nie zdziwić się, jak kolejny wpis znowu nie będzie dotyczył monitora, tylko projektu kolejnej płytki PCB, tym razem dla klawiatury.

Opublikowano Uncategorized | Dodaj komentarz

Projekt układu klawiatury

Poniższy wpis przygotowałem, wstyd się przyznać, 1,5 roku temu i zapomniałem go opublikować. W tym momencie nie pamiętam też, czy był on ukończony, czy też miałem coś jeszcze dopisać. Publikuję go tak jak został ostatnio zapisany:

W ostatnim wpisie odgrażałem się, że przygotuję filmik na którym będzie widać jak działa odczytywanie klawiatury, ale jakoś mi się zapomniało. Zamiast tego wziąłem się za przygotowanie układu klawiatury. Główny problem polegał na tym, że moja klawiatura ma tylko cztery rzędy podczas gdy normalne klawiatury od komputerów mają tych rzędów minimum pięć. Miałem więc do wyboru albo zaprojektować sobie płytkę drukowaną z układem klawiszy jak w zwykłej klawiaturze, albo zaprojektować układ klawiatury, taki żeby pasował do tego co mam. Wybrałem to drugie rozwiązanie, jako tańsze w realizacji. W pierwszej chwili chciałem zaprojektować klawiaturę tak jak w sławnym ZX-81:

ZX81

Tylko, że przy takim układzie zostawało mi sporo pustych klawiszy. Klawiatura ZX-81 ma tylko 10 kolumn, a moja aż 16. Jednak zamiast kombinować znalazłem lepszą inspirację kalkulator HP-71B:

hp-71b

Najlepszą rozwiązaniem tej klawiatury jest wydzielony z prawej strony blok numeryczny. W moim projekcie taki blok powinien znacznie przyśpieszyć wprowadzanie programów do pamięci.

poniżej układ klawiatury w wersji alfa:

Q W E R T Y U I O P c d e f
A S D F G H J K L 8 9 a b
Z X C V B N M ([ ]) 4 5 6 7 bck
spc , . \ 0 1 2 3 ent run

Jak widać niektóre pola klawisze nie mają jeszcze przypisanych znaków. Nie zaprojektowałem też alternatywnych znaków (czyli tych które będą pojawiać się po wciśnięciu klawiszy niebieskiego i żółtego.

Opublikowano home brew computer, komputer domowej roboty | Otagowano , | Dodaj komentarz

Oprogramowanie klawiatury wersja 0.1

Przeglądając wcześniejsze wpisy zauważyłem, że nie opublikowałem oprogramowania do klawiatury. Pora to nadrobić. Całość jest dostosowana do dekodera 55KB z ostatniego wpisu.

Pierwszy plik to właściwy program do obsługi klawiatury:

; Keyboard test program by M. Bartosiak
!cpu 65c02
!to "via-keyboard-5.bin", plain
keyb_row = $8000
key_pressed = $C001
via2a_out = $D004
delay_via = $D805
param_addr_ptr = $FE
!source "via-addrs-2-A8.h"
*=$E000
; reset vector
; everything starts here after power up or reset
reset_vec
lda #$0 ; a = 0
sta keyb_row ; keyb_line = a = 0
sta via2a_out ; via2a_out = a = 0
lda #$1 ; a = 1
jsr lcd_init ; initialize lcd
jsr via_init ; initialize vias
lda #<msg1
sta param_addr_ptr ; store high byte of message address
lda #>msg1
sta param_addr_ptr+1 ; store low byte of message address
jsr lcd_print ;print message
jmp main_loop ;
msg1 !raw "OK."
!byte $00 ;terminating null for string
nmi_vec
pha
bit via1_t1c_l ; read anything from t1c_l to turn off interrupt signal
lda via1_iora ; read keyboard status from VIA
bmi + ; if a < 0 go to "+" label (key not pressed)
sta key_pressed ; key_pressed = a (store pressed key)
pla
rti
+ ; key not pressed. prepare to scan next row
lda keyb_row ; a = keyb_line
clc ;
adc #1 ; a++
cmp #8 ;
bne + ; if a != 7 then
lda #0 ; a = 0
+
sta via1_iora ; send to via1 port A
sta keyb_row ; keyb_line = a
lda #$FF
sta key_pressed ; key_pressesd = 0
pla
rti
irq_vec
pha
bit via2_t1c_l ; read anything from t1c_l to turn off interrupt signal
lda delay_via ; a = delay_via
bne + ; if a == 0 then
lda #$10 ; a = $10
+
sec
sbc #1 ; a--
sta delay_via ; delay_via = a
bne + ;
clc
lda via2a_out ; a = char_to_via
sta via1_iorb ; send to via1 port B
sta via2_iora ; send to via2 port A
rol ; a =>> 1
bne ++ ; if a == 0 then
lda #$1 ; a = $1
++
sta via2a_out ; char_to_via = a
+
pla
rti
main_loop
lda #40
jsr lcd_goto
lda keyb_row
jsr lcd_hex
lda #':'
jsr lcd_putchar
lda key_pressed
jsr lcd_hex
jmp main_loop ;
;;; VIA's STUFF
via_init
pha
lda #%00000111 ; load #$ff into via_ddra
sta via1_ddra ; set first 3 bits pf port A of via1 to output
lda #$ff ; load #$ff into via_ddra
sta via1_ddrb ; set port A of via2 to output
sta via2_ddra ; set port A of via2 to output
lda #$0
sta via1_iora ; set port A pins to low state
sta via2_iora ; in both vias
sta via1_iorb ; set port A pins to low state
; initialize timer
lda #%01000000
sta via1_acr ; set timer to continous mode, no PB7
lda #%11000000
sta via1_ier ; enable timer 1 interrupt on via1
lda #$ff
sta via1_t1c_l ; set timer to interrupt
sta via1_t1c_h ; ... every 65535 ticks
; initialize timer
lda #%01000000
sta via2_acr ; set timer to continous mode, no PB7
lda #%11000000
sta via2_ier ; enable timer 1 interrupt on via1
lda #$ff
sta via2_t1c_l ; set timer to interrupt
sta via2_t1c_h ; ... every 65535 ticks
cli
pla
rts
; insert LCD stuff
!source "lcd.s"
;;; STANDARD 65c02 VECTORS
*=$FFFA
!word nmi_vec
!word reset_vec
!word irq_vec

Drugi plik zawiera definicje rozmieszczenia rejestrów układów VIA:

; VIA registers mapping for homebrew computer
; by M. Bartosiak
; decoder A15..A8
via1_iorb = $DC00
via1_iora = $DC01
via1_ddrb = $DC02
via1_ddra = $DC03
via1_t1c_l = $DC04
via1_t1c_h = $DC05
via1_t1l_l = $DC06
via1_t1l_h = $DC07
via1_t2c_l = $DC08
via1_t2c_h = $DC09
via1_sr = $DC0A
via1_acr = $DC0B
via1_pcr = $DC0C
via1_ifr = $DC0D
via1_ier = $DC0E
via1_iora_nh = $DC0F
via2_iorb = $DD00
via2_iora = $DD01
via2_ddrb = $DD02
via2_ddra = $DD03
via2_t1c_l = $DD04
via2_t1c_h = $DD05
via2_t1l_l = $DD06
via2_t1l_h = $DD07
via2_t2c_l = $DD08
via2_t2c_h = $DD09
via2_sr = $DD0A
via2_acr = $DD0B
via2_pcr = $DD0C
via2_ifr = $DD0D
via2_ier = $DD0E
via2_iora_nh = $DD0F

Trzeci plik to „biblioteka” procedur do obsługi wyświetlacza.

; library for LCD with HD44780 chip
; by M. Bartosiak
; adresses of LCD registers
lcd_i = $DF00
lcd_d = $DF01
;_lcd_str_ptr must be defined elsewhere!!!!
; init and clear lcd display
; accumulator preserved
lcd_init
pha
jsr lcd_busy
lda #%00111000 ; $38: function set: 8 bit, 2 lines, 5x7
sta lcd_i
jsr lcd_busy
lda #%00000110 ; $06: entry mode set: increment, no shift
sta lcd_i
jsr lcd_busy
lda #%00001100 ; $0e: display on, cursor off, blink off
sta lcd_i
jsr lcd_busy
jsr lcd_clear
lda #$0
jsr lcd_goto
pla
rts
; print null-terminated string (up to 255 chars)
lcd_print
pha ;save a, y to stack
phy
ldy #$00
- lda (param_addr_ptr),y
beq +
jsr lcd_putchar
iny
bne -
+ ply ;restore a, y
pla
rts
; clear lcd and return cursor to home
; accumulator not preserved
lcd_clear
lda #%00000001 ; clear display
sta lcd_i
jmp lcd_busy
; to return from subroutine
; we will use "rts" from lcd_busy
; goto specific postion on lcd
; accumulator not preserved
lcd_goto
ora #%10000000
sta lcd_i
jmp lcd_busy
; to return from subroutine
; we will use "rts" from lcd_busy
; print byte as hex
; (accumulator not preserved)
lcd_hex
pha
lsr
lsr
lsr
lsr
jsr _lcd_hex
pla
and #$F
; here we are going to _lcd_hex
; without jump... 🙂
_lcd_hex
cmp #$A ; if a > 0xA
bcc + ; then
adc #$6 ; a += 0x6
+
adc #$30 ; a += '0'
; next we are going to lcd_putchar
; without jump... 🙂
; print single character from accumulator
; (accumulator not preserved)
lcd_putchar
sta lcd_d ; output the character
; next we are going to lcd_busy
; without jump... 🙂
; wait until lcd busy bit is clear
; (accumulator not preserved)
lcd_busy
- nop ; slow down a little
lda lcd_i ; read register instruction from lcd
bmi - ; check bit 7 (busy)
; after return in accumulator
; we should have current lcd memory location
rts
view raw lcd.s hosted with ❤ by GitHub

Za parę dni zamieszczę w tym wpisie filmik, który pokaże jak działa całość…

Opublikowano home brew computer, komputer domowej roboty | Otagowano | Dodaj komentarz

55K RAM

Na płytce drukowanej, którą zaprojektowałem jakiś czas temu, przewdziałem miejsce na dwa układy pamięci RAM. Zrobiłem to, prawdę mówiąc, trochę na zapas – bez planów wykorzystania tej możliwości. W takim projekcie jak mój, 32 KB RAM to i tak dużo. Ale, skoro kostka już była to, jak to bywa, w końcu skusiło mnie żeby spróbować jej użyć…

Zaczęło się od tego, że zamontowałem dodatkową kostkę, żeby całość lepiej wyglądała na zdjęciach. Oczywiście zamontowana na płytce kostka była od razu gotowa do pracy – nie miała tylko podłączonego pinu CE . Żeby mój komputer działał tak jak poprzednio, musiałem na ten pin doprowadzić stan wysoki (czyli musiałem wprowadzić ten układ w stan wysokiej impedancji). I rzeczywiście całość działała bez problemów. Przy okazji zauważyłem, że wykorzystanie tej kostki nie będzie wymagało żadnych przeróbek na płytce prototypowej. Jedyną zmianą będzie przeróbka dekodera adresów i podłączenie do niego pinu CE. No i oczywiście będę musiał przerobić nieco oprogramowania, aby korzystało z nowego podziału pamięci.

Przypominam, że dotychczasowy podział pamięci przedstawiał się następująco: 32KB RAM, 24KB dla urządzeń wejścia-wyjścia i na końcu 8KB dla pamięci EEPROM.

W pierwszej kolejności przygotowałem uproszczony dekoder, na bazie wcześniejszego rozwiązania (opis można znaleźć we wpisie „Jeszcze inny dekoder”) z następującym podziałem pamięci: 48 KB RAM (32K z pierszej kości i 16K z drugiej), 8 KB dla urządzeń we-wy i 8 KB na EEPROM. Schemat dekodera poniżej:

W stosunku do poprzedniego dekodera, zmiany są niewielkie:

  • podłączenie do szyny adresowej musiałem zwiększyć do dodatkowy bit – nowy dekoder używa dodatkowo linii adresowej A11, pozostałe linie A15-A12 zostały bez zmian.
  • wyprowadzenie sygnału CE dla drugiej kostki zrobiłem na dotychczas nieużywanym pinie 13, czyli zaraz obok pinu wyprowadzającego sygnał CE dla pierwszej kości RAM

Dzięki takiemu podejściu nie musiałem przebudowywać istniejących już połączeń na płytce prototypowej.

Podział pamięci w nowym dekoderze przestawiał się następująco:

			1111 1100 0000 0000
			5432 1098 7654 3210
RAM_1	0000-7FFF	0... .... .... .... 32K
RAM_2	8000-BFFF	10.. .... .... .... 16K
LCD	C000-CFFF	1100 .... .... ....  4K
VIA_1	D000-D7FF	1101 0... .... ....  2K
VIA_2	D800-DFFF	1101 1... .... ....  2K
ROM	E000-FFFF	111. .... .... ....  8K

Plik PLD do zaprogramowania układu GAL poniżej:

Name address-decoder-16v8-2 ;
PartNo 00 ;
Date 2017-02-05 ;
Revision 01 ;
Designer Maciej Bartosiak ;
Company m ;
Assembly None ;
Location ;
Device g16v8a;
/* *************** INPUT PINS *********************/
pin 1 = PHI2; /* clock PHI2 */
pin 2 = RW; /* RW signala from 65c02 */
pin [3..7] = [A15..A11];
/* *************** OUTPUT PINS *********************/
pin 14 = !RAM_1 ; /* RAM_1 0000-7FFF 0... .... .... 32K */
pin 13 = !RAM_2 ; /* RAM_2 8000-BFFF 10.. .... .... 16K */
pin 15 = LCD ; /* LCD C000-CFFF 1100 .... .... 4K */
pin 16 = !VIA_1 ; /* VIA_1 D000-D7FF 1101 0... .... 2K */
pin 17 = !VIA_2 ; /* VIA_2 D800-DFFF 1101 1... .... 2K. */
pin 18 = !ROM ; /* ROM E000-FFFF 111. .... .... 8K */
pin 19 = !OE ;
/* *************** LOGIC ***************************/
OE = RW;
RAM_1 = !A15 & PHI2;
RAM_2 = A15 & !A14 & PHI2;
IO_SP = A15 & A14 & !A13;
LCD = IO_SP & !A12 & !A11 & PHI2;
VIA_1 = IO_SP & A12 & !A11;
VIA_2 = IO_SP & A12 & A11;
ROM = A15 & A14 & A13;

Zmiany w oprogramowaniu sprowadziły się do przerobienia adresów wskazujących poszczególne układy. Dodatkowo przeniosłem kilka zmiennych ze strony zerowej do obszaru zajmowanego przez drugi układ RAM, żeby sprawdzić czy druga kostka pamięci działa poprawnie.

Ponieważ całość w tej konfiguracji działała bez problemów postanowiłem pójść „za ciosem” i zmaksymalizować ilość dostępnej pamięci RAM. Zmiany robiłem krok po kroku, za każdym razem dodając po jednej linii adresowej, aż wykorzystania ośmiu linii adresowych (A15-A8). Na samym końcu przeprojektowałem też wyprowadzenia pinów, aby ułatwić podłączenie całości na płytce prototypowej. Poniżej ostatnia wersja przerobionego dekodera:

Jak widać po stronie „wejściowej” dekodera znalazły się linie PHI2 i linie adresowe od A15 do A9. Wyprowadzenie linii adresowych po jednej stronie umożliwiło mi wykorzystanie  do podłączenia ośmiolinowej tasiemki.  Po stronie wyjściowej są wyprowadzenia sygnałów do pamięci i układów wejścia-wyjścia. Sygnały do sterowania pamięcią są tak ułożone, żeby dało się je połączyć z płytką drukowaną (prawie) jeden do jednego.

Nowy podział pamięci w tym dekoderze przedstawia się następująco:

			1111 1100 0000 0000
			5432 1098 7654 3210
RAM_1	0000-7FFF	0... .... .... .... 32K	
RAM_2A	8000-BFFF	10.. .... .... .... 16K
RAM_2B	C000-CFFF	1100 .... .... ....  4K
RAM_2C	D000-D7FF	1101 0... .... ....  2K
RAM_2D	D800-DBFF	1101 10.. .... ....  1K
VIA_1  	DC00-DCFF	1101 1100 .... .... .25K
VIA_2  	DD00-DDFF	1101 1101 .... .... .25K
VIA_3	DE00-DEFF	1101 1110 .... .... .25K
LCD	DF00-DFFF	1101 1111 .... .... .25K
ROM  	E000-FFFF	111. .... .... ....  8K

Jak widać z powyższego podziału dostępna pamięć RAM ma teraz 55 KB. Urządzenia wejścia-wyjścia 2 KB i na końcu pamięć EEPROM.

Dodatkową nowością w tym dekoderze jest wyprowadzenie dodatkowego sygnału do sterowania trzecim układem wejścia wyjścia (tu roboczo nazwałem go VIA3). Wcześniej zastanawiałem się czy nie przeznaczyć tego wolnego pinu na kolejne rozszerzenie szyny adresowej, ale zrezygnowałem z tego pomysłu, bo dzięki temu mógłbym uzyskać 0.5 KB pamięci  RAM więcej. Uznałem, że lepiej na przyszłość mieć możliwość podłączenia podłączenia dodatkowego układu, bez przerabiania dekodera. Plik PLD do zaprogramowania układu GAL poniżej:

Name address-decoder-16v8-A8 ;
PartNo 00 ;
Date 2017-02-25 ;
Revision 01 ;
Designer Maciej Bartosiak ;
Company m ;
Assembly None ;
Location ;
Device g16v8a;
/* *************** INPUT PINS *********************/
pin 1 = PHI2 ; /* clock PHI2 */
pin 11 = RW ; /* RW signala from 65c02 */
pin [2..9] = [A15..A8];
/* *************** OUTPUT PINS *********************/
pin 14 = !RAM_1; /* RAM_1 0000-7FFF 0... .... .... .... 32K */
pin 13 = !RAM_2;
/* RAM_2A 8000-BFFF 10.. .... .... .... 16K */
/* RAM_2B C000-CFFF 1100 .... .... .... 4K */
/* RAM_2C D000-D7FF 1101 0... .... .... 2K */
/* RAM_2D D800-DBFF 1101 10.. .... .... 1K */
pin 17 = !VIA_1; /* VIA_1 DC00-DCFF 1101 1100 .... .... .25K */
pin 18 = !VIA_2; /* VIA_2 DD00-DDFF 1101 1101 .... .... .25K */
pin 19 = !VIA_3; /* VIA_3 DE00-DEFF 1101 1110 .... .... .25K */
pin 16 = LCD; /* LCD DF00-DFFF 1101 1111 .... .... .25K */
pin 12 = !ROM; /* ROM E000-FFFF 111. .... .... .... 8K */
pin 15 = !OE;
/* *************** LOGIC ***************************/
OE = RW;
RAM_1 = !A15 & PHI2;
RAM_2A = A15 & !A14;
RAM_2B = A15 & A14 & !A13 & !A12;
RAM_2C = A15 & A14 & !A13 & A12 & !A11;
RAM_2D = A15 & A14 & !A13 & A12 & A11 & !A10;
RAM_2 = (RAM_2A # RAM_2B # RAM_2C # RAM_2D) & PHI2;
IO_SP = A15 & A14 & !A13 & A12 & A11 & A10;
VIA_1 = IO_SP & !A9 & !A8;
VIA_2 = IO_SP & !A9 & A8;
VIA_3 = IO_SP & A9 & !A8;
LCD = IO_SP & A9 & A8 & PHI2;
ROM = A15 & A14 & A13;

Zmiany w oprogramowaniu sprowadziły się znowu do dostosowania adresów przypisanych do układów wejścia-wyjścia. Jedyną dodatkową zmianą, którą zrobiłem, było przeniesienie kilku zmiennych ze strony zerowej do obszarów pamięci, przy których dekoder powinien aktywować dostęp do drugiej kości (RAM_2A, RAM_2B itd.).

Opublikowano home brew computer, komputer domowej roboty | Otagowano | Dodaj komentarz

Porządki na płytce

Po zrobieniu i przetestowaniu płytki drukowanej postanowiłem uporządkować resztę mojego komputera. Płytka drukowana poprawiła znacząco stabilność komputera, ale powiększyła też całą konstrukcję. Mój komputer składał się już z trzech części: płytki drukowanej z głównymi układami, dużej płytki prototypowej z układami VIA, dekoderem adresów i wyświetlaczem, oraz z mniejszej płytki prototypowej z klawiaturą. Poniżej powtarzam zdjęcie z poprzedniego wpisu przed uporządkowaniem:

komputer-2

W pierwszej kolejności postanowiłem zrezygnować z małej płytki prototypowej i przenieść klawiaturę na dużą płytkę. W tym celu musiałem przenieść układ VIA1 wraz układami do obsługi klawiatury. Kolejną przeróbką było zastąpienie przewodów zworkami, tam gdzie się dało. Ta zamiana umożliwiła mi schowanie od klawiaturą całego kablowania do jej obsługi. Dodatkowo przesunąłem nieco w lewo wyświetlacz tak aby nie wystawał poza płytkę. Efekt końcowy widać na poniższym zdjęciu:

komputer-3

Przerobiłem też zasilanie komputera, co widać w lewym górnym rogu. Wcześniej korzystałem z modułu do zasilania płytek prototypowych. Zamiast niego zastosowałem mały moduł z układem AMS1117. Teraz komputer jest teraz zasilany z regularnego zasilacza sieciowego dającego na wyjściu 7,5V.

Opublikowano home brew computer, komputer domowej roboty | Otagowano | 2 Komentarze

Płytka drukowana

Po ponad rocznej przerwie spowodowanej różnymi zawirowaniami znalazłem wreszcie trochę czasu, żeby wrócić do  mojego projektu. W tym czasie komputer leżał na biurku i w kółko chodził na nim program z ostatniego wpisu. Niestety, od czasu do czasu komputer przestawał działać i musiałem poświęcać mu trochę uwagi i sprawdzać co się dzieje. Objawy były najróżniejsze, ale ich naprawa sprowadzała się do jednego: zawsze musiałem poprawiać przewody, które nawet przy niewielkich ruchach potrafiły się się wysunąć z płytki prototypowej. Dodatkowo okazało się, że rozwiązanie jakie zastosowałem do zamocowania pamięci EEPROM jest bardzo niewygodne. Przewody podłączeniowe bardzo utrudniały wyjmowanie i wkładanie kości EEPROM, a i sama podstawka testowa potrafiła „wyskoczyć” z płytki prototypowej. Pisanie i testowanie kolejnych wersji oprogramowania w takich warunkach byłoby dość karkołomnym zadaniem. Stale miałbym problem: czy popełniłem błąd w programie czy znowu coś mi nie kontaktuje na płytce.

Musiałem coś z tym zrobić i wymyśliłem, że zrobię płytkę płytkę drukowaną, na której umieszczę przynajmniej część elementów mojego komputera. Do projektowania użyłem programu Eagle PCB w wersji „freeware” (ten sam, w którym rysowałem schematy do poprzednich wpisów). Program w tej wersji posiada jedno dość znaczące ograniczenie: projektowana płytka nie może być większa niż 8×10 cm. Przy projektach z mikrokontrolerami może to nie ma znaczenia (płytka Arduino Uno ma wymiary ok. 5×7), ale w projekcie takim jak mój, w którym układy scalone są dość duże wraz dużą ilością połączeń, jest to problem. Od razu wiedziałem, że na płytkę wejdzie mi tylko część układów. Po kilku próbach z różnymi elementami zdecydowałem się, że na płytce umieszczę tylko mikroprocesor, dwie pamięci RAM oraz pamięć EEPROM na podstawce testowej. Założenie, że zastosuję podstawkę testową jest tu istotne ponieważ zajmuje ona więcej miejsca niż zwykła podstawka.

Schemat płytki przedstawia się następująco:

plytka-schemat-maly

Jak widać na płytkę, oprócz głównych układów, postanowiłem wcisnąć też generator kwarcowy, układ resetu (układ DS-1813 wraz z przyciskiem), listwę zaciskową do połączenia zasilania i kilka zworek do konfiguracji. I oczywiście gniazda szpilkowe, do połączenia z płytką prototypową gdzie będzie na razie reszta układów.

Parę słów wyjaśnienia o zworkach do konfiguracji płytki: zworki przy procesorze umożliwiają albo podciągnięcie  sygnałów NMIB, IRQB i RDY  poprzez rezystory 3,3K do VDD (gdy te sygnały nie są używane) lub wyprowadzenie ich na gniazdo szpilkowe. Zworki przy pamięci EEPROM mają umożliwić zamianę stosowanej przeze mnie pamięci 28C64  na układy typu 28C256 (czyli 32KB) lub 28C65 (8K z wyprowadzonym sygnałem RDY). Szczególnie ciekawe było by zastosowanie tego drugiego układu, ponieważ po podłączeniu go można by do niego wpisywać dane jak do zwykłej pamięci RAM (z tym że sporo wolniej). Inaczej mówiąc można by przy pomocy tego układu zrobić komputer z możliwością programowej aktualizacji.

Na powyższym schemacie nie widać jednej dość poważnej zmiany, której się „dopuściłem”: pozamieniałem wyprowadzenia obu pamięci RAM do szyny adresowej. Niestety pamięci RAM i EEPROM mają kompletnie niezgodnie ze sobą wyprowadzenia tych sygnałów. Nie dość że są one rozmieszone w odwrotnej kolejności  to jeszcze są one częściowo wymieszane. Mapowanie pinów tych układów do szyny adresowej przedstawia poniższa tabela:

ADDR0  -> A14
ADDR1  -> A13
ADDR2  -> A12
ADDR3  -> A11
ADDR4  -> A10
ADDR5  -> A9
ADDR6  -> A8
ADDR7  -> A7
ADDR8  -> A3
ADDR9  -> A2
ADDR10 -> A0
ADDR11 -> A1
ADDR12 -> A6
ADDR13 -> A4
ADDR14 -> A5

Taka zamiana nie ma najmniejszego wpływu na pracę komputera, a bardzo upraszcza prowadzenie ścieżek na płytce. Tylko uwaga: zmianę taką można zrobić tylko dla pamięci RAM, której to nie będziemy wyjmowali z płytki.

Samo wykonanie płytki zleciłem firmie znalezionej w internecie i już po 2 tygodniach otrzymałem gotowe płytki:

plytka-proto

Niestety przy sprawdzeniu płytki okazało się, że ma ona jeden duży błąd: brak połączenia wszystkich mas ze sobą. Nie wiem dlaczego, ale Eagle PCB, który potrafi dość dobrze sprawdzić poprawność płytki, tego błędu akurat mi nie wykrył. Na szczęcie naprawa płytki była dość prosta. Przewierciłem płytkę (w okolicach napisu EEPROM), przy otworze zdrapałem trochę soldermaski i połączyłem masy przylutowując kawałek drutu z obu stron płytki.

Kolejnym problemem na jaki się natknąłem to montaż podstawki testowej pod EEPROM. Okazało się, niestety, że otwory mają zbyt małą średnicę na zamontowanie typowej podstawki TEXTOOL. Po różnych próbach skończyło się na tym, że zniszczyłem 2 podstawki i uszkodziłem płytkę. Na szczęście firma, w której zamówiłem płytkę ma miły zwyczaj, że nawet jak zamawiamy jedną płytkę to dostajemy dwie. Tak więc miałem jeszcze do dyspozycji drugą płytkę. Jednak nie ryzykowałem już z kolejnymi podstawkami TEXTOOL, tylko znalazłem na Allegro podstawki firmy ARIES. Gdy podstawki dotarły do mnie, okazało się, że był to strzał w dziesiątkę. Są one dużo solidniej wykonane, a nóżki nie różnią się wielością od samych układów i idealnie pasują do płytki. Jedyną różnicą jest to, że są one prawie dwa razy droższe od podstawek TEXTOOL, ale to nie jest problem: mówimy o cenach 6 złotych dla podstawki TEXTOOL i 10 dla ARIES.

Cała płytka po zmontowaniu wygląda przedstawia się następująco:

plytka-proto-gotowa

Dodatkowym usprawnieniem poprawiającym stabilność mojego komputera była przeróbka kabli połączeniowych. Już wcześniej stosowałem kable połączone ze sobą w taśmę. Teraz zamieniłem pojedyncze obudowy końcówek na obudowy w których można jednocześnie zamontować kilka końcówek. Obudowy takie, w różnych rozmiarach można kupić bez problemu na Allegro. Poniższe zdjęcie przestawia taśmę 8 żyłową po zmianie (po lewej) i przed zmianą (po prawiej):

goldpins

Na zakończenie jeszcze zdjęcie całości:

komputer-2

Opublikowano home brew computer, komputer domowej roboty | Otagowano | Dodaj komentarz

Klawiatura nr 2 — dla leniwych programistów

W poprzednim wpisie zapowiadałem, że napiszę lepszą procedurę obsługi klawiatury, ale zanim się za to wziąłem to zacząłem kombinować jak tu sobie uprościć życie i przynajmniej część roboty zwalić na sprzęt.

W pierwszej kolejności, pomiędzy wyjście z portu PA układu VIA i klawiaturę postanowiłem wstawić dekoder 74HC238. Układ ten ma 3 linie wejściowe i osiem wyjściowych. Działa to w ten sposób, że w zależności od kombinacji sygnałów na wejściu, na wyjściu w stanie wysokim jest utrzymywana tylko jedna linia, reszta jest w stanie niskim. Dzięki temu, zamiast przesuwać pojedynczy bit przez cały rejestr PA, wystarczy w  3 bity tego rejestru (te które są podłączone do wejścia dekodera) wpisywać po kolei liczby od 0 do 7, a dekoder ustawi jedną z linii podłączonych do klawiatury w stan wysoki. Podłączenie dekodera nie sprawiło mi większych trudności i komputer ruszył od pierwszego razu (oczywiście po niewielkiej przeróbce oprogramowania). Postanowiłem od razu pójść za ciosem i zastosować podobne rozwiązanie z drugiej strony klawiatury, czyli zastosować enkoder (układ działający dokładnie odwrotnie do dekodera). Niestety tu pojawił się problem. O ile dekodery są robione w dwóch wersjach, różniących się stanem wyjścia (aktywne wyjście w stanie niskim w 74HC138 lub aktywne wyjście w stanie wysokim w 74HC238), to enkoder jest dostępny tylko z liniami wejściowymi aktywnymi w stanie niskim. Chcąc uzyskać poprawne działanie całości musiałem pomiędzy klawiaturę i enkoder wstawić aż osiem inwerterów. Schemat tego co zrobiłem przedstawia się następująco:

6502-via-keyboard-238

Diody (D1-D8) na powyższym schemacie mają zabezpieczyć dekoder przed zwarciem w przypadku, gdybym w czasie testów nacisnął dwa klawisze, natomiast rezystory podciągające do masy (RN2) mają na celu utrzymać stan niski na wyjściach z klawiatury kiedy nie jest naciśnięty żaden klawisz.

Schemat jak schemat – wygląda całkiem zgrabnie, niestety jego realizacja na płytce prototypowej wymagała już sporej plątaniny kabli.

Po kolejnej poprawce programowania, podłączona klawiatura zaczęła działać poprawnie. Natomiast ja zacząłem kombinować jak uprościć całość. Osiem inwerterów to dwa scalaki, dekoder i enkoder to kolejne dwa. Dotychczas mój komputer składał się z sześciu układów scalonych, a teraz zrobiło się ich już dziesięć, więc było o co walczyć. Przede wszystkim zamieniłem dekoder 74HC238 na 74HC138. Ponieważ w układzie 74HC138 aktywna linia jest w stanie niskim, usiałem więc zmienić polaryzację diod na przeciwną oraz przełączyć rezystory podciągające, tak aby na wyjściu klawiatury stan wysoki. Poniższy schemat przedstawia ostateczną wersję podłączenia klawiatury:

6502-via-keyboard-138

Po treningu jaki miałem z podłączeniem ośmiu inwerterów, podłączenie tej wersji poszło całkiem sprawnie. Oprogramowanie tym razem zostało bez zmian – sygnały wychodzące i przychodzące do układu VIA były dokładnie takie same jak w wersji z dekoderami.

Na koniec parę słów podsumowania: Udało mi się zaprojektować całkiem fajną klawiaturę, która wykorzystuje tylko siedem bitów jednego rejestru układu VIA. Wolny bit, który został będę mógł w przyszłości wykorzystać do podłączenia dodatkowego klawisza (np. „Shift” lub „Control”). Komunikacja poprzez jeden rejestr układu VIA powinna też uprościć znacząco program do obsługi klawiatury. Dzięki temu powinienem uniknąć kłopotliwego przeliczania pozycji aktywnych bitów na indeks tablicy z mapowaniem znaków. Oczywiście, porządne oprogramowanie klawiatury jest jeszcze przede mną. Mógłbym też spróbować uprościć konstrukcję mojego komputera i zrezygnować z jednego układu VIA.

Teraz nie nie mam żadnych wymówek i muszę w końcu się wziąć za oprogramowanie klawiatury…

Opublikowano home brew computer, komputer domowej roboty | Otagowano | Dodaj komentarz

Klawiatura

Po przetestowaniu liczników zostało mi jeszcze do sprawdzenia przyjmowanie danych przez układ VIA (na portach PA i PB). W tym wypadku postanowiłem pójść trochę na skróty i tą funkcjonalność sprawdzić przy okazji podłączenia klawiatury.

Nad podłączeniem klawiatury myślałem już od pewnego czasu. Na internecie można znaleźć kilka, mniej lub bardziej ciekawych rozwiązań, ale żadne z nich mi nie pasowało. Musiałem więc, zrobić to po swojemu i wymyśliłem sobie klawiaturę matrycową 8×8 (czyli 64 klawiszową). Chciałem mieć do dyspozycji w miarę pełną klawiaturę, zbliżoną układem mniej-więcej do typowej klawiatury „qwerty” i jednocześnie taką, którą będę mógł w miarę łatwo podłączyć do układu VIA.

Sam pomysł wydawał się być prosty i ładnie pasujący do całego projektu, jednak zrealizowanie go już takie łatwe nie było. O ile w sieci są dostępne tony klawiatur 4×4 i sprzedawcy, zwłaszcza chińscy, prześcigają się w obniżaniu ich cen, to klawiatura 8×8 jest prawie nie do zdobycia. Jedyne miejsce gdzie udało mi się  znaleźć taką klawiaturę to sklep polskiej firmy „Cyfronika” (klawiatura jest dostępna  tylko na zamówienie – dla zainteresowanych: klawiatura UM214.71 lub w innej kolorystyce UM214.72). Jednak nie zdecydowałem się na zakup tej klawiatury. Moją klawiaturę postanowiłem zrobić z 4 małych klawiatur 4×4, kupionych oczywiście w Chinach za nie całe 20 zł (przesyłka była za darmo – jak się im to opłaca?).

Klawiatury 4×4 kupiłem w wersji do samodzielnego montażu. W gotowych klawiaturach goldpiny  wyprowadzone są do góry, a mi zależało mi żeby były jednak skierowane do dołu, tak aby można było je łatwo zamontować na płytce stykowej. Całość po zamontowaniu na płytce wygląda następująco:

6502-keyboard

Jak widać moja klawiatura przypomina tylko z grubsza normalną klawiaturę. W pierwszym rzędzie pewno będą cyfry, w kolejnych litery odpowiadające układowi normalnej klawiatury („Q”, „A”, „Z” itd.). Jak widać brakuje piątego rzędu na spację, którą będę pewno musiał umieści gdzieś obok. Nieco lepiej wygląda jak popatrzymy na kolumny. Normalne klawiatury mają około czternastu kolumn (bez bloku numerycznego), u mnie jest ich szesnaście, więc będę miał parę klawiszy w zapasie, także zmieści się spacja i jeszcze parę klawiszy.

Schemat podłączenia klawiatury do komputera przedstawia się następująco:

6502-via-keyboard

Klawiatura jest podłączona do pierwszego układu VIA (tego, który generuje przerwanie niemaskowane NMIB). Wybrałem przerwanie niemaskowane, żeby klawiatura była zawsze obsługiwana.

Zastosowanie diod na wyjściu z portu PA układu VIA podpatrzyłem w konstrukcji komputera ZX81. Ich zastosowanie wydaje się zgodne z ogólną regułą łączenia bramek logicznych, która mówi, że można łączyć jedno wyjście do wielu wejść, ale nie wiele wyjść do jednego wejścia.  Poza tym diody powinny zabezpieczyć układ VIA przed zwarciem, w przypadku gdy zostaną naciśnięte dwa klawisze jednocześnie. Z drugie strony klawiatury, przy porcie PB zastosowałem drabinkę rezystorową 10KΩ, żeby wejściowe piny PB nie wisiały w  powietrzu.

Po zaprojektowaniu sprzętu przyszła pora na oprogramowanie całości. W pierwszej kolejności przepisałem prawie od nowa procedury obsługi wyświetlacza i i przeniosłem je do oddzielnego pliku:

; library for LCD with HD44780 chip
; by Maciej Bartosiak

	; adresses of LCD registers
	lcd_i		= $8000
	lcd_d		= $8001
	
	;_lcd_str_ptr must be defined elsewhere!!!!
	
; init and clear lcd display
; accumulator preserved
lcd_init
	pha
	jsr lcd_busy
	lda #%00111000	; $38: function set: 8 bit, 2 lines, 5x7
	sta lcd_i
	jsr lcd_busy
	lda #%00000110	; $06: entry mode set: increment, no shift
	sta lcd_i
	jsr lcd_busy
	lda #%00001110	; $0e: display on, cursor on, blink off
	sta lcd_i
	jsr lcd_busy
	jsr lcd_clear
	lda #$0
	jsr lcd_goto
	pla
	rts

; print null-terminated string (up to 255 chars)
lcd_print
	pha		;save a, y to stack
	phy
	ldy #$00
-	lda (param_addr_ptr),y
	beq +
	jsr lcd_putchar
	iny
	bne -
+	ply		;restore a, y
	pla
	rts

; clear lcd and return cursor to home
; accumulator not preserved
lcd_clear
	lda #%00000001	; clear display
	sta lcd_i
	jmp lcd_busy
	; to return from subroutine
	; we will use "rts" from lcd_busy

; goto specific postion on lcd
; accumulator not preserved
lcd_goto
	ora #%10000000
	sta lcd_i
	jmp lcd_busy
	; to return from subroutine
	; we will use "rts" from lcd_busy

; print byte as hex
; (accumulator not preserved)
lcd_hex
	pha
	lsr
	lsr
	lsr
	lsr
 	
	jsr _lcd_hex

	pla
	and #$F
	; next we are going to _lcd_hex
	; without jmp or jsr :)
	
_lcd_hex
	cmp #$A		; if a > 0xA
	bcc +		; then
	adc #$6		; 	a += 0x6
+
	adc #$30	; a += '0'
	; next we are going to lcd_putchar
	; without jmp or jsr ... :)

; print single character from accumulator
; (accumulator not preserved)
lcd_putchar
	sta lcd_d	; output the character
	; next we are going to lcd_busy
	; without jmp or jsr ... :)

; wait until lcd busy bit is clear
; (accumulator not preserved)
lcd_busy
-	nop		; slow down a little
	lda lcd_i	; read register instruction from lcd
	bmi -		; check bit 7 (busy)
	; after return in accumulator 
	; we should have current lcd memory location 
	rts

Nie będę opisywał kodu, mam nadzieję, że jest zrozumiały. Proszę jedynie zwrócić uwagę pewną sztuczkę, polegającą na brak dwóch rozkazów „jsr lcd_busy; rts” na końcu procedury lcd_putchar. Nie są one potrzebne, bo procesor i tak przejdzie do następnej procedury – lcd_busy, bez używania skoku. Powrót z funkcji zapewni rts na końcu lcd_busy. Tą samą sztuczkę zastosowałem też w lcd_hex (która na końcu przechodzi do lcd_putchar), oraz w lcd_goto i lcd_clear (które kończą się skokiem bezwarunkowym do lcd_busy). Puryście pewno będą się oburzali na taki styl programowania, ale w starych dobrych czasach takie „numery” robiło się nagminnie – żeby było i szybciej, i krócej.

Sama obsługa klawiatury przedstawia się następująco:

; Keyboard test program by M. Bartosiak

	!cpu 65c02
	!to "via-keyboard-1.bin", plain

	loop_count	= $00
	kbd_count 	= $01
	kbd_line	= $02
	kbd_row		= $03
	via2a_out	= $04
	delay_via	= $05
	kbd_line_prev	= $06
	
	param_addr_ptr	= $FE
	
	!source "via-addrs.h"
	
	*=$E000
	
; reset vector
; everything starts here after power up or reset
reset_vec
	lda #$0		; a = 0
	sta loop_count	; loop_count = a = 0
	sta kbd_count	; kbd_count = a = 0
	sta kbd_line	; kbd_line = a = 0
	sta kbd_row	; kbd_row = a = 0

	lda #$1		; a = 1
	sta via2a_out	; via2a_out = a = 1
	jsr lcd_init	; initialize lcd
	jsr via_init	; initialize vias
	
	lda #msg1
	sta param_addr_ptr+1	; store low byte of address
	jsr lcd_print	; print message
	jmp main_loop	;

msg1	!raw "OK."
	!byte $00           ;terminating null for string

nmi_vec
	pha
	bit via1_t1c_l	; read anything from t1c_l to turn off interrupt signal

	lda kbd_count	; a = kbd_count
	clc
	rol		; a =<> 1
	bne ++		; if a == 0 then
	lda #$1		;   a = $1
++
	sta via2a_out	; char_to_via = a
+
	pla
	rti


main_loop
	lda kbd_line
	beq +

	lda #40
	jsr lcd_goto

	lda kbd_row
	jsr lcd_hex

	lda #':'
	jsr lcd_putchar

	lda kbd_line
	jsr lcd_hex
+
	jmp main_loop	;

;;; VIA's STUFF

via_init
	pha
	lda #$ff	; load #3 into via_ddra
	sta via1_ddra	; set port A of via1 to output
	sta via2_ddra	; set port A of via2 to output

	lda #$0
	sta via1_iora	; set port A pins to low state
	sta via2_iora	; in both vias

	; initialize timer
	lda #%01000000
	sta via1_acr	; set timer to continous mode, no PB7

	lda #%11000000
	sta via1_ier	; enable timer 1 interrupt on via1
	
	lda #$ff
	sta via1_t1c_l	; set timer to interrupt
	sta via1_t1c_h	; ... every 65535 ticks

	; initialize timer
	lda #%01000000
	sta via2_acr	; set timer to continous mode, no PB7

	lda #%11000000
	sta via2_ier	; enable timer 1 interrupt on via1
	
	lda #$ff
	sta via2_t1c_l	; set timer to interrupt
	sta via2_t1c_h	; ... every 65535 ticks

	cli

	pla
	rts

	; insert LCD stuff
	!source "lcd.s"
	
;;; STANDARD 65c02 VECTORS

	*=$FFFA
	!word nmi_vec
	!word reset_vec
	!word irq_vec

Jak widać powyższy program jest z poprzedniego wpisu. Układ VIA1 jest tak skonfigurowany, żeby do 65535 cykli zegara generować przerwanie – sprawdzenie klawiatury odbywa się właśnie w procedurze obsługi przerwania. Mechanizm jest prosty: na porcie PA, na kolejnych pinach ustawiany jest stan wysoki. Jeśli zostanie naciśnięty którykolwiek klawisz, to na jednym z pinów portu PB pojawi się też stan wysoki. Jeśli zajdzie taka sytuacja to stan portu PB zapisujemy do kbd_row. W pętli głównej natomiast wypisujemy na wyświetlaczu zmienną kbd_line, przechowującą stan ustawiony na porcie PA oraz zapamiętaną zmienną kbd_row. Efekt jak zawsze na filmiku:

Na powyższym filmie naciskam kolejne klawisze najpierw po przekątnej (stąd takie same wartości dla kbd_col i kbd_line), później naciskam klawisze przypadkowo. Zastosowany mechanizm jest dość „drewniany” i poza testowaniem klawiatury nie będzie się do niczego nadawał. W kolejnej części pewno będę musiał napisać lepszy mechanizm czytania stanu klawiatury, czyli czeka mnie sporo programowania…

Opublikowano home brew computer, komputer domowej roboty | Otagowano | Dodaj komentarz

Liczniki i przerwania, czyli dalej o VIA 65c22

Przy podłączeniu układów VIA wykonałem tylko jeden, dość prosty test ograniczający się do sprawdzenia wysyłania danych z mikroprocesora do obu układów. Pora zatem na sprawdzenie innych możliwości jakie oferują te układy. Na początek postanowiłem sprawdzić działanie liczników i przy okazji przećwiczyć obsługę przerwań.

Układy 65C22 posiadają dwa liczniki, oznaczane zazwyczaj jako „1” i „2”. Różnią się one dość znacznie funkcjonalnością. Licznik 1 ma dwa tryby pracy: tryb pracy ciągłej i tryb pracy jednorazowej. Dodatkowo, dla każdego trybu możemy włączyć pin PB7, żeby pracował jako wyjście. Natomiast licznik 2 może działać jedynie w trybie jednorazowym (bez wykorzystania wyjścia na pinach) lub w trybie zliczania impulsów pojawiających się na pinie PB6.

W programie, który przygotowałem do testu, wykorzystałem licznik 1 obu podłączonych układów. Poniżej inicjacja licznika w trybie ciągłym bez wykorzystania pinu PB7:

lda #$ff
sta via1_t1c_l ; set timer to interrupt
sta via1_t1c_h ; ... every 65535 ticks
lda #%11000000
sta via1_ier ; enable timer 1 interrupt on via1
lda #%01000000
sta via1_acr ; set timer to continous mode, no PB7

W pierwszej kolejności do obu rejestrów licznika (T1C_L i T1C_H) wpisałem wartość $FF, co dało mi maksymalny czas między kolejnymi przerwaniami. Następnie ustawiłem w rejestrze IER generowanie sygnału przerwania w momencie wyzerowania licznika. Na końcu ustawiłem w rejestrze ACR tryb pracy ciągłej. Inicjacja licznika w układzie VIA2 wygląda identycznie.

Następnie przygotowałem procedury obsługi przerwań. Procedury są dwie bo wcześniej oba układy VIA podłączyłem do 2 różnych przerwań: NMI (układ VIA1) i IRQ (VIA2). Tekst źródłowy obu procedur poniżej:

nmi_vec
pha
bit via1_t1c_l ; read anything from t1c_l
; to turn off interrupt signal
lda char_to_via1; a = char_to_via2
sta via1_iora ; send to via2 port A
clc
rol ; a =<< 1
bne ++ ; if a == 0 then
lda #$1 ; a = 1
++
sta char_to_via2; char_to_via = a
+
pla
rti
irq_vec
pha
bit via2_t1c_l ; read anything from t1c_l
; to turn off interrupt signal
lda delay_via ; a = delay_via
bne + ; if a == 0 then
lda #$10 ; a = $10
+
sec
sbc #1 ; a--
sta delay_via ; delay_via = a
bne + ;
lda char_to_via2; a = char_to_via
sta via2_iora ; send to via2 port A
clc
rol ; a =<< 1
bne ++ ; if a == 0 then
lda #$1 ; a = 1
++
sta char_to_via2; char_to_via = a
+
pla
rti

Obie procedury są do siebie podobne. Do wizualizacji działania przerwań wykorzystałem przesuwanie pojedynczego bitu w bajcie i wysyłanie tej wartości do odpowiednich portów PA1 obu układów. Dało to efekt „przesuwającej się diody”. Procedura dla przerwania IRQ zawiera dodatkowo mechanizm powodujący, że przesuwanie bit będzie wykonywane co szesnaste przerwanie. Takie opóźnienie jest potrzebne bo inaczej na podłączonych diodach niewiele widać, co prezentuje poniższy film (po lewej przerwanie NMI bez „opóźniacza”, po prawej IRQ):

Opublikowano home brew computer, komputer domowej roboty | Otagowano , | Dodaj komentarz

Jeszcze inny dekoder

Tym razem nie będzie to kolejny pomysł na dekoder adresów , który umożliwiłby mi podłączenie jeszcze większej liczby układów peryferyjnych. Logika dekodera, który zaprojektowałem jest dokładnie taka sama jak poprzednio. Różnica jest sprzętowa: zamiast składać dekoder z układów logicznych serii 74xx zrobiłem go przy użyciu układu programowalnego GAL 16V8.

Głównym powodem tej zmiany była potrzeba wygospodarowania trochę miejsca na płytce stykowej. Poprzedni dekoder składał się aż trzech układów i zajmował na płytce sporo miejsca. Poza tym, układom programowalnym tego typu przyglądałem się już od pewnego czasu, zwłaszcza że w sieci można znaleźć kilka projektów, które ich używają, właśnie do dekodowania adresów.

Jedyny problem z układami programowalnymi jest taki, że potrzebny jest do tego specjalny programator. Niestety profesjonalny programator odsługujący dużą liczbę układów kosztuje masę pieniędzy, więc zakup takiego urządzenia nie wchodził w grę. Musiałem poszukać programatora, który będzie obsługiwał przynajmniej kilka podstawowych typów i nie będzie kosztował zbyt dużo. Mój wybór padł na chiński programator TL866CS. Można go też kupić w Polsce za 240-300 zł. Można go też sprowadzić z Chin prawie o połowę taniej  (ok. 130 zł, przez ebay). Ja zdecydowałem się na zakup w Chinach, chociaż zdaję sobie sprawę, że w razie problemów na naprawę gwarancyjną nie mam co liczyć.

Programator TL866CS obsługuje tylko układy ATF16V8B firmy Atmel oraz rodziny układów GAL16V8, GAL20v8i GAL22v10 firmy Lattice. Nie jest to dużo – ale na potrzeby mojego komputera w zupełności wystarczy. Dodatkowym „bonusem” jest możliwość zaprogramowania całkiem sporej liczby różnych układów układów EEPROM i mikrokontrolerów.

Samo podłączenie układu w komputerze przedstawia się następująco:

6502--gal

Na powyższym schemacie piny CLK (nr 1) i OE (nr 11) są używane jako zwykłe sygnały wyjścia/wyjścia. Zgodnie w powyższym oznaczeniem są one wykorzystywane dopiero w trybie rejestrowym.

Do przygotowania dekodera, który został zaprogramowany w układzie użyłem programu WinCUPL firmy Atmel. Program jest do pobrania za darmo ze strony producenta. Trzeba się jedynie zarejestrować. Samo programowanie w języku CUPL nie jest zbyt skomplikowane i sprowadza się do zdefiniowania poszczególnych pinów układu i opisania zależności logicznych między wejściem i wyjściem. Opis dekodera o funkcjonalności takiej samej jak opisałem w poprzednim wpisie przedstawia się następująco:

Name address-decoder-16v8 ;
PartNo 00 ;
Date 2014-10-20 ;
Revision 01 ;
Designer Maciej Bartosiak ;
Company m ;
Assembly None ;
Location ;
Device g16v8a;
/* *************** INPUT PINS ***************************/
pin 1 = PHI2 ; /* clock PHI2 */
pin 2 = RW ; /* RW signala from 65c02 */
pin [3..5] = [A15..A13];
/* *************** OUTPUT PINS ***************************/
pin 14 = !RAM ; /* RAM 0000 7FFF 0... .... .... .... */
pin 15 = LCD ; /* LCD 8000 9FFF 100. .... .... .... */
pin 16 = !VIA_1 ; /* VIA_1 A000 CFFF 101. .... .... .... */
pin 17 = !VIA_2 ; /* VIA_2 D000 DFFF 110. .... .... .... */
pin 18 = !ROM ; /* ROM E000 FFFF 111. .... .... .... */
pin 19 = !OE ; /* */
/* *************** LOGIC *********************************/
OE = RW;
RAM = !A15 & PHI2;
LCD = A15 & !A14 & !A13 & PHI2;
VIA_1 = A15 & !A14 & A13;
VIA_2 = A15 & A14 & !A13;
ROM = A15 & A14 & A13;

Na początku są informacje nagłówkowe. Są tutaj dwie ważne informacje: pole „name” i z nazwą dla pliku wynikowego, oraz „device” z informacją dla kompilatora dla jakiego układu ma być wygenerowany plik wynikowy. Dalej są definicje pinów wejściowych i wyjściowych, a  na końcu są równania logiczne jakie układ ma realizować.

Test całości polegał na uruchomieniu programu z poprzedniego wpisu. Działanie całości z nowym dekoderem było dokładnie takie samo jak poprzednio, więc zrezygnowałem z kręcenia filmu. Jedynie zrobiłem zdjęcie na którym widać działający komputer:

6502-gal1

Jak widać udało mi się wygospodarować trochę miejsca przy wyświetlaczu, więc będę mógł dokładniej przetestować układy VIA. Ponadto układ GAL ma jeszcze kilka nie wykorzystanych pinów. W razie czego będę miał możliwość dołożenia kolejnych układów peryferyjnych.

Opublikowano home brew computer, komputer domowej roboty | Otagowano , | 2 Komentarze