Merhaba,
CPLD Logic kısmını artık tam olarak bitirdim sanırım. Color RAM'e de yazabiliyorum, bir sıkıntı kalmadı.
CPLD kısmı ile ilgili teknik bilgi vereceğimi belirtmiştim, şimdi biraz fırsat buldum.
CPLD kodunu WinCUPL ile yazıyorum, VHDL den biraz farklı ama kolay bir mantığı var.
CPLD vb programlarken bilinmesi gereken şey, yazılan kodun sıralı bir şekilde çalışmadığı. Yani örneğin A=!B dediğinizde, A bacağı her zaman B bacağının tersi olacak şekilde mantık programlanmış olur.
A=!B önermesinin gerçekleşmesi için yazılan kodun ilgili satırına gelmesine gerek yoktur, bu önerme her zaman için geçerlidir.
Bu kısa ön bilgiden sonra, Doberman64'ün logic kodunu aşağıda açıklayarak paylaşıyorum;
/* C64 INTERFACE */
PIN[11,10,8,6,5,3,2,44]=[C64_DATA0..7];
PIN[43]=C64_DMA;
PIN[42]=C64_RW;
PIN[40]=C64_BA;
PIN[37]=C64_PHI2;
PIN[35]=C64_RESET;
PIN[33]=C64_DOTCLK;
Burada, C64 tarafında kullandığımız hatları CPLD pinlerine tanımladık.
/* ADDRESS OUTPUT ENABLE */
PIN[12]=ADDR_OE;
/* PIC INTERFACE */
PIN[27]=REQ_DMA;
PIN[30]=IN_DMA;
PIN[23]=P_RW;
PIN[25]=P_START;
PIN[34]=P_DONE;
PIN[28]=REQ_RESET;
PIN[13,14,15,18,19,20,21,22]=[BUS0..7];
Burada da PIC tarafındaki pinleri tanımladık.
ADDR_OE pini ise, 2 adet 573 latch'ine bağlı durumda.
/* ********************************************************** */
/* RESET HANDLER */
/* ********************************************************** */
C64_RESET.oe=REQ_RESET;
C64_RESET.le='b'1;
C64_RESET.l='b'0;
Burada, PIC tarafından reset request gelir ise, C64 tarafındaki C64_RESET pini tetikleniyor.
Mantık şu, C64 tarafına bağı olan RESET Cell, her zaman 0 durumunda. (Son iki satır bunu sağlıyor.)
PIC tarafından RESET req. gelir ise, bu cell'in outputları enable ediliyor ve hat low'a çekilmiş oluyor.
Bu sayede pini open collector gibi kullanmış oluyorum. Normalde bu çıkış high-z, yani boşta kalıyor.
/* ********************************************************** */
/* C64 PHI2 SHAPER */
/* ********************************************************** */
/* Usage: PHI2 & C64_PHI2 */
/* ********************************************************** */
/* C64_PHI H-L Delay:10ns */
/* C64_PHI L-H Delay:40ns */
/* ********************************************************** */
PINNODE = PHI2;
PHI2.ck=!C64_DOTCLK;
PHI2.d=C64_PHI2;
Burada enteresan bir mantık kullandım. Bildiğiniz gibi Phi2 clock'un çıkan kenarının şekilsiz olduğunu farketmiştim.
Aynı zamanda okuduğum bazı bilgilere göre, Phi2 nin bu çıkan kenarını referans olarak kullanmak doğru değilmiş.
Normalde yapılması gereken, düşen kenara senkronize olan bir Phi2 clock yaratmak ve onu kullanmak. Ama bu CPLD içinde dışarıdan eleman kullanmadan kolay olmayacağı için başka birşey yaptım.
Phi2 çıkan kenardan sonra gelen ilk DOT_CLOCK'un düşen kenarını referans aldım.
DOT_CLOCK bilindiği üzere, 8MHZ civarı yani Phi2 den 8 kat hızlı çalışan bir clock.
Kodun geri kalanında bu yeni ürettiğim PHI2 sinyalini kullandım ve daha önce yaşadığım problemler ortadan kalktı.
Buna ait plot aşağıda:

/* ********************************************************** */
/* DMA_SAFE = BA + 3 PHI2 CYCLE COUNTER */
/* ********************************************************** */
/* Usage: DMA_SAFE3 */
/* ********************************************************** */
PINNODE = [DMA_SAFE0..3];
[DMA_SAFE0..3].ck=PHI2;
[DMA_SAFE0..3].ar=C64_BA;
DMA_SAFE0.d='b'1;
DMA_SAFE1.d=DMA_SAFE0;
DMA_SAFE2.d=DMA_SAFE1;
DMA_SAFE3.d=DMA_SAFE2;
Burada da, DMA'ya giriş için daha önce konuştuğumuz BA Low olduktan sonraki 3 clockluk gecikmenin nasıl yapıldığı görülüyor.
4 Adet Flip Flop arka arkaya bağlı. Hepsinin clock'u PHI2. Yani her PHI2 cycle da bir sonraki FF High oluyor.
Son FF da high olduktan sonra DMA ya girebiliriz.
Buna ait plot aşağıda:

/* ********************************************************** */
/* DMA REQUEST HANDLER */
/* ********************************************************** */
/* Sadece DMA_SAFE iken DMA'a gir... */
/* PHI2 Low iken yani VIC-II cycleda iken cikabiliriz... */
/* ********************************************************** */
IN_DMA.le=DMA_SAFE3;
IN_DMA.l=REQ_DMA;
IN_DMA.ar=(!C64_RESET) # (!PHI2 & !C64_PHI2 & !REQ_DMA);
C64_DMA.le='b'1;
C64_DMA.l=!IN_DMA;
Burada, PIC'ten gelen DMA Requesti, sadece biraz önce bahsettiğimiz DMA_SAFE durumunda işlenecek şekilde bir mantık var.
DMA'dan çıkış için bir optimizasyon yaptım. Artık bir sonraki Bad Line'ı beklemek yerine, PHI2 Low iken yani VIC-II devrede iken çıkabiliyorum.
Burada dikkat edilmesi gereken, PHI2 High iken DMA'dan çıkılmaması.
Giriş ve çıkış plotları:


/* ********************************************************** */
/* PIC <-> C64 PROCESS HANDLER */
/* ********************************************************** */
/* Three Step State Machine */
/* P_START oldugunda sira ile tetiklenirler */
/* WAIT: Isleme baslamadan once ilk VIC-II cycle'i bekler */
/* PROG: VIC-II Cycle biter bitmez tetiklenir (Gercek islem) */
/* DONE: Tekrar VIC-II Cycle basladiginda islemimiz bitmistir */
/* ********************************************************** */
PINNODE=WAIT;
PINNODE=PROG;
PINNODE=DONE;
WAIT.l = 'b'0;
WAIT.ck = 'b'0;
WAIT.ap = P_START & (!PHI2) & (!C64_PHI2);
WAIT.ar = !P_START;
PROG.l = 'b'0;
PROG.ck = 'b'0;
PROG.ap = WAIT & PHI2 & IN_DMA & C64_BA;
PROG.ar = !P_START;
DONE.l = 'b'0;
DONE.ck = 'b'0;
DONE.ap = PROG & (!PHI2);
DONE.ar = !P_START;
Burada transfer işlemini gerçekleştiren state machine arka rkaya bağlı üç FF ile kuruldu.
İlk Flip Flop VIC-II sırasının gelmesini bekliyor. Bu sayede sıra bizdeyken, yani clock'un yarısında transfere başlamamış olduğumuzdan emin oluyoruz.
Zaten request geldiğinde, eğer sıra VIC-II deyse bu state hemen geçiliyor.
İkinci FF, gerçek transfer işleminin yapıldığı zaman yani Phi2 iken set oluyor.
Phi2 tekrar low a düşünce yani sıra tekrar VIC-II ye gelince işlem tamamlanmış oluyor.
/* ********************************************************** */
/* DONE Signal To PIC */
/* ********************************************************** */
P_DONE.l=DONE;
P_DONE.le='b'1;
İşlem bitince bunu tekrar PIC'e bildirdiğim bölüm.
/* ********************************************************** */
/* ADDRESS Ouput Logic (Both Read & Write) */
/* ********************************************************** */
ADDR_OE.l=!(PROG & (!DONE));
ADDR_OE.le='b'1;
İşlem read veya write, farketmiyor, adres bilgisini PIC latchlere zaten yazdı.
Bizim sadece doğru zamanda, yani PROG anında bunu output etmemiz gerekiyor.
/* ********************************************************** */
/* C64 R/W Pin (Only in Write Operation) */
/* ********************************************************** */
C64_RW.l='b'0;
C64_RW.le='b'1;
C64_RW.oe=PROG & (!DONE) & P_RW;
/* ********************************************************** */
/* C64 DATA Bus Output Enable (Only in Write Operation) */
/* ********************************************************** */
[C64_DATA0..7].l=[BUS0..7].io;
[C64_DATA0..7].le=P_RW;
[C64_DATA0..7].oe=PROG & (!DONE) & P_RW;
Bu iki işlem sadece PIC Write yapmak istemiş ise yapılacak. Yani C64 tarafındaki R/W Pini low'a çekilecek, ve BUS'taki data C64 Adres Bus'ına basılacak.
/* ********************************************************** */
/* C64 DATA > PIC Internal Bus Latch (Read Operation) */
/* ********************************************************** */
[BUS0..7].l=[C64_DATA0..7].io;
[BUS0..7].le=PROG & (!DONE) & (!P_RW);
[BUS0..7].oe=(!P_RW) & (DONE);
Son olarak eğer PIC read yapıyor ise, doğru zamanda, C64 Data Bus'ı, internal BUS'a latchliyoruz.
PIC, Requesti sonlandırana kadar data orada kalıyor ve PIC okuyabiliyor.
Tüm CPLD kodu bu kadar.
Bu kod kullandığım CPLD'nin yaklaşık yarısını kaplamış durumda.
Total I/O pins used 31/32 (96%)
Total Logic cells used 31/64 (48%)
Total Flip-Flop used 30/64 (46%)
Total Foldback logic used 0/64 (0%)
Total Nodes+FB/MCells 31/64 (48%)
Eğer merak ettiğiniz bir yer varsa seve seve açıklarım.