18 Temmuz 2012 Çarşamba

Peki Neden Trap Flag?

Aslında yazının tam başlığı "Peki Neden Trap Flag? veya FLAGS Yazmacı ve Debuggerlara Genel Bir Bakış" olmalıydı. Son birkaç yazıyı donanımla ilgili yazmışken biraz da yazılımla ilgili birşeyler yazmak aklımdaydı. Bu seferki yazı yazılımla ilgili olacak ağırlıklı olarak.

Önce neden trap flag sorusuna cevap vereyim: Çünkü programlamada en çok kullanılan zero flag adı blogspot'ta alınmıştı. Ayrıca bundan 6-7 sene öncesinde kendi debugger'ımı yazmak aklımdaydı. Hatta bence en zaman alıcı kısım olan disassembler rutinleri hemen hemen hazırdı. Haliyle bir debugger'ın en çok kullanması gereken trap flag aynı zamanda blog adı oldu.

http://css.csail.mit.edu/6.858/2012/readings/i386/s02_03.htm
Neden böyle düşündüğümü bilmiyorum ama FLAGS yazmacı bence x86'ların en eğlenceli yazmacı. 80286'larla birlikte Virtual 86 modunu desteklemek için bir kaç bit eklendi ve 32 bitlik 80386'larla FLAGS yazmacı da 32 bite çıkarıldı ve adı EFLAGS oldu. Benim değineceğim daha çok ilk 16 bitlik FLAGS kısmı. Zaten assembly'e elini bulaştıran herkes az çok Zero Flag (ZF) ile yada Carry Flag (CF) ile uğraşmıştır.


  • Carry Flag (CF): İşlem sonucunda bir elde yada bir taşma varsa set edilir. 8086'da iki 32 bitlik sayıyı toplarken önce düşük anlamlı 16 bit ADD ile toplanır, sonraki yüksek anlamlı 16 bit ADC (add with carry) ile toplanır. ADC eğer ilk ADD işlemi carry oluşturduysa sonuca bir daha ekler. Carry aynı zamanda kaydırma (shift) ve döndürme (rotate) işlemlerinde de kullanılır. Bir tamsayı tek mi çift mi anlamak için sayı sağa kaydırılır. Carry flag set edildiyse tektir, edilmediyse çifttir. Set durumunda CY (Carry), reset durumunda NC (No Carry) adını alır. İçeriği doğrudan CLC, STC ve CMC komutlarıyla değiştirilebilen ender flag'lardandır.
  • Parity Flag (PF): İşlem sonucunda sonuçta tek sayıda bit varsa set edilir, çift sayıda bit varsa resetlenir. Yoksa tam tersi miydi? Hatırlayamadım. Pek kullandığım bir bit değil. Çift bit için PE (Parity Even), tek bit için PO (Parity Odd) adını alır.
  • Auxiliary Carry (AF): CF'ın bir nibble'da (4bit) oluşan eldeler için olanı gibi düşünülebilir. Doğrudan kullanılmasa da AAA, DAM gibi komutlar bu bit yardımıyla BCD düzenlemesi yaparlar. Set durumunda AC (Auxiliary Carry), reset durumunda NA (No Auxiliary Carry) adını alır.
  • Zero Flag (ZF): Yapılan işlemin sonucu sıfırsa bu set edilir. Bu aslında doğrudan kullanmaya kalktığımızda çok da bir işe yaramayacağı açık. CMP ve TEST komutları sırasıyla mikroişlemcide sonucun operandları değil sadece FLAGS'i etkilediği bir çıkarma ve VE (AND) işlemi gerçekleştirir. CMP AL, 23h çalıştığında sonucunda FLAGS'ın değeri SUB AL, 23h çalıştırmakla aynı olur ancak AL'nin içeriğine dokunulmaz. Bu da eğer AL'nin değeri 23h ise ZF set edilir. Bundan sonra JZ yada JNZ komutlarıyla AL'nin içeriğine göre dallanma gerçekleştirilebilir. Set durumunda ZR (Zero) reset durumunda NZ (Non-Zero) adını alır.
  • Sign Flag (SF): Yapılan işlemin en yüksek anlamlı biti olan işaret biti bu bitin içeriğine kopyalanır. Çıkarma işleminin sonucunun negatif olup olmadığını kontrol edebileceğiniz gibi CMP işleminden sonra kullanıldığında sayının büyük yada küçük olup olmadığı kontrol edilebilir. JG ve JL komutları bu flag'ın içeriğine bakar. Reset edildiğinde PL (Plus), set edildiğinde NG (Negative) olur. 
  • Trap Flag (TF): Dediğim gibi bir debugger için en önemli flag. Eğer set edilmişse işlemci her bir komutun çalıştırılması biter bitmez Single Step diye bilinen 1 numaralı kesmeyi çağırır. Ekrana bir numaralı kesmenin vektörünü yazan bir program yazıp bunu hem debugger'da hem de komut satırında çalıştırın. Farkı görün. Debugger'lar bu kesmeye asılırlar. Set edildiğinde EI (Enable Interrupt); reset edildiğinde DI (Disable Interrupt) değerindedir. 
  • Interrupt Flag (IF): IRQ kesmelerini kapatır yada açar. Eğer bir kesme vektörünü değiştirmek, kesme denetleyicisini programlamak vb. kritik bir iş yapıyorsanız bunu resetlemeniz tavsiye edilir ki tam siz vektörü değiştirirken kullanıcı klavyeden bir tuşa basıp bir siz daha tam işinizi bitirirememişken bir kesme oluşturmasın. NMI (Non Maskable Interrupt) haricindeki bütün kesmeler iptal olur. Bunu reset etmek için CLI set etmek için de STI komutları bulunur. Resetleyince DI (Disabled Interrupts), set edince EI (Enabled Interrupts) değerini alır.
  • Direction Flag (DF): MOVS, STOS, LODS gibi komutlar çalıştırıldıktan sonra indis yazmaçlarının (SI ve DI) değerlerinin arttırılacağı yada azaltılacağı seçilir. Yani bellek bloğu işlemleri bellekte ileri doğru yada geriye doğru yapılır. Hangisi reset'ti hangisi set'ti unuttum ama bir değeri UP diğer değeri de DN'dir (Down). STD ve CLD komutlarıyla değeri değiştirilebilir.
  • Overflow Flag (OF): Yapılan işlemin sonucunda bir overflow varsa set edilir yoksa reset'lenir. Hakkında tek bildiğim işaretsiz sayılarda yapılan karşılaştırmalarla ilgili olduğuydu. Set edildiği zaman değeri OV (Overflow), reset edildiği zaman ne oluyordu onu da unuttum.

Buradan sonra asıl görevini açıklayacağım trap flag.


- DOS'un debug.exe'si benzeri basit bir debugger nasıl yazılır? 

Öncelikle eğer .exe dosyaları debugger'da açmak istiyorsanız nasıl belleğe yüklendiklerini bilmek gerekiyor, ki bunu ben de çok az biliyorum. .com dosyaları ele alalım. Onların belleğe yüklenmesi kolay. Herhangi bir segmentin 0100h adresine yükleniyorlar. Segmentte 0000h ile 0100h adresleri arasında .com dosyanın içerisinde bulunmayan, DOS'un exec() fonksiyonunun ürettiği bir kısım var, adı program segment prefix (PSP). Bu kısmı ayrıntısıyla hatırlamak zor ancak 0000h adresinde 0CDh ve 20h byte'ları var. Bu çalıştırılabilir bir kod ve assembly karşılığı INT 20h. DOS'un eski usül (CP/M zamanlarından kalma) kodu sonlandırma fonksiyonu. Diğer DOS kodunu sonlandırma yolları AH'nin değeri 00h yada 4Ch iken INT 21h'yı çağırmak. İlk iki yolu DOS'un ilk versiyonu bile destekliyor. Son yol ise DOS2.0 ile birlikte destekleniyor ve DOS'a bir geri dönüş değeri (Errorlevel) bildirebilmek için tek yol. PSP'nin 80h ile 0FFh byte'ları arasında programın çağırıldığı komut yer alıyor. Komut karakterlerinin nasıl tutulduğunu anlamak için örnek resme bakmak yeterli.


PSP'nin CP/M zamanlarında kalma olduğunu söylemiştim. JMP 0000h gibi bir komut .com dosyayı sonlandırmak için yeterli aslında. Program ilk defa belleğe yüklendiğinde aslında stack'da da bazı değerler oluyor. Bunları tam bilmemekle birlikte bunlardan ilki her zaman 0000h değeri. Dolayısıyla RET komutu da .com dosyayı pekala sonlandırıyor. Bunun nedeninden tam olarak emin olmamakla birlikte bir seçenek yine CP/M'e uyumluluk için bırakılmış olabileceği. Diğer uzak bir olasılıksa UNIX uyumlulularında her program aslında çekirdeğin çağırdığı bir fonksiyon olarak ele alınıyor. POSIX standardı bile olabilir. Bu nedenle DOS'u bilmem ama UNIX için C kodu yazarken main()'i mutlaka int olarak tanımlamak gerekiyor. void tanımlamak DOS'da sorun çıkarmazken UNIX'de sorun çıkarabilir. Herneyse eğer program bir fonksiyonsa onu sonlandırmak için RET çağırmaktan daha doğal birşey olamaz.

Bu arada bir program çalıştığında DOS ona dallanmadan önceki son CS:IP değerlerini INT 22h'nin vektörüne yazıyor ancak programı INT 22h'yi çağırarak sonlandırmak, programın çalıştığı bellek bloklarının işletim sistemine geri verilememesine açtığı dosya ve sistemden aldığı diğer kaynakların açık kalarak sisteme iade edilememesine neden olacaktır. Eğer exec()'i işletim sistemi değil başka bir program çağırmışsa o zaman kesme vektörü o programın CS:IP'sini gösterecektir. INT 23h CTRL+C yada CTRL+Break tuş kombinasyonu basıldığında aktif hale gelir. Bir tuşa basılır basılmaz klavye IRQ'sunun kesme hizmet programı basılan tuşu (yada ASCII kodunu) klavye belleğine (keyboard buffer) kopyalar ve çalışmayı o anda ödünç aldığı (kestiği) programa geri döner. DOS kesme hizmet programını değiştirip geliştirebilir. Komut satırındayken CTRL+C için eğer basılan tuş buysa klavye belleğine kopyalamayıp yeni bir komut satırı açar yada o anda bir program çalışıyorsa o programı sonlandırabilir. Bir program da yazılma amacına göre bu kesmeyi değiştirip (hatta yeri geldiğinde klavye kesme hizmet programını da değiştirebilir) CTRL+C'ye basıldığında başka birşeylerin yapılmasını sağlayabilmelidir. Tam ayrıntısını bilmemekle birlikte bir program çalışırken CTRL+C'ye basıldığında DOS, kesme hizmet programından sonra INT23h'ü çağırır. (Sanırım geri dönüş değerlerinin DOS çekirdeği mi yoksa ayrı bir program mı olduğunu kontrol ediyor.) Eğer program INT23h'ü değiştirmişse kendi istediklerini yapabilir. Son olarak herhangi önemli bir DOS hatası oluşursa yine CTRL+C'de olana benzer biçimde INT24h çağrısı yapılır. Bütün bu kesmelerin dökümantasyonu dünyaca ünlü Ralf Brown's Interrupt List'de bulunabilir. Ben bile bunları yazarken arada bu listeye bakıyorum.

Debugger'da .com dosya için uyumluluk için bile olsa uygun PSP oluşturmak gerekli. Bu INT 21h'in büyük olasılıkla AH=26h altfonksiyonunu (yada belki AH=4Bh ama bence 26h'dır kesin) çağırarak halledilebilir. Kodu belleğe yükledikten sonra kullanıcıdan debug.exe gibi komutlarını alıyoruz. Eğer g (Go) vermişse direk çalıştırıyoruz yani kodu yüklediğimiz segmentin 0100h offsetine dallanıyoruz. Eğer p (Proceed yani Step/Trace Over) yada t (Trace yani Step/Trace Into) çağırıldıysa işte o zaman trap flag'i set edip kodun son kaldığı yere dallanmak gerekiyor. Bu durumda program çalışırken bütün yazmaçların değerlerini yedeklemeli ve komut verildiğinde dallanmadan önce bu değerleri geri yüklemeli. Bu arada Intel'in Pentium'lara eklediği LOADALL adında dökümante etmediği bir komutu vardı sanırım, POPA'ya benzeyen. Trap flag en son set edilmeli yada trap flag'i set eden bir komut çalıştırılacak kodun başına eklenip o kodun uzunluğu kadar geriye de dallanılabilir. Tabi uygun bir INT 01h yordamı da yazıp vektörünü girmek gerekiyor. Bütün işleri yapan tek bir INT 01h kullanılacaksa program başlar başlamaz set edilebilir ama t için ayrı p için ayrı INT 01h yazmak bana daha tercih edilebilir geliyor. debug.exe'de INT 01h'in hizmet programı, komutun çalışması sonlanınca yazmaçların değerlerini ve sıradaki kodu hem makina kodu olarak hem de disassemble edilmiş karşılığını ekrana yazıyor. Debugger'ın disassembler rutinleri bu aşamada gerekli (bir de u (Unassemble) komutu verildiğinde).

Bir de debugger'in asıl daha önemli bir kesmesi var ki o da INT 3. Bütün debugger'lar bu kesmeye de asılırlar (hook). INT 3'ün önemli özelliği makina kodu olarak hem 0CDh 03h ile hem de 0CCh ile çağırılabilir olması. Tabii ki tercih edilen yol 0CCh ile çağırmak. Tek byte opkod programcıya tek byte'ı değiştirerek oraya kırılma noktası (break point) eklenebilmesini sağlıyor. Aslında kesmenin başka da önemli bir özelliği yok çünkü aynı işi iki byte'da da yapabilmek olanaklı ve debugger olmadıkça INT 3'ün içeriği bir IRET'den ibaret (en azından öyle olması gerekir ama ne yapacağı işletim sistemine kalmış). INT 01h'ya benzer şekilde bütün işi INT 3'ün vektörünü yazmak olan bir programımız olsaydı, bu da debugger'da farklı kendi kendine farklı sonuçlar verecekti.

Debugger'lar bu kadarla bitmiyor, örneğin derleyiciyle çalıştırılabilir kodun içerisinde sembolleri saklayacak biçimde derledikten sonra bunları okuyabilir olması gerek. Sanırım debug.exe'de bu özellik bulunmuyor. Bundan başka breakpoint'lere değindim ama bunların belli koşul gerçekleştiğinde çalışanları, "conditional breakpoint"'ler de güzel bir özellik. debug.exe de bundan da yok. Assembler ile kodun içerisinde çalışırken kodları değiştirebilme gibi özellikler zaten olmazsa olmaz. Sadece trap flag ile iş bitmiyor. Bu yazıyı genel bir fikir vermesi için yazdım. İş debugger'i kodlamaya geldiğinde bu kadar basit olmayacağı açıktır.

12 Temmuz 2012 Perşembe

PCAD ile Baskı Devre Çizelim

Bu yazıda PCAD'le baskı devre çizimine değineceğim ve basit bir baskı devreyi çizerek göstereceğim. Yazı biraz uzun ve dolayısıyla sıkıcı olabilir. 90'ların sonunda benim görebildiğim kadarıyla amatör piyasaya Boardmaker programı hakimdi. Sonuçta o zamanlar hiçbirşey bilmeyen 15 yaşında çiçeği burnunda ergen elektronikçi adayıydım ve esnaf (çoğunlukla Pala Elektronik) ne derse onu yapıyorduk. Internet henüz tam anlamıyla yaygınlaşmadığından ve olan kaynaklara da henüz ulaşmayı bilmediğimden fazla bir seçeneğimiz kalmıyordu. Boardmaker, tek disketlik ve yanlış hatırlamıyorsam sadece baskı devre çizimi yapabildiğimiz (devre şeması çizemiyordu) bir programdı. Kitabıyla birlikte satılıyordu. Kitabını alıp bir haftasonunda bilgisayarın başında deneye deneye bitirdim ama beni tatmin etmemişti. Gel zaman git zaman seçenekler çoğaldıkça nasıl olduğunu hatırlamıyorum ama PCAD ile tanıştım. Windows altında çalışan, zengin bir dijital devre elemanı özellikle de mikroişlemci kütüphanesi bulunan (Intel 80286 bile vardı daha ne olsun) ve devre yollarını autoroute özelliğiyle kendi çizen muhteşem bir programdı. Yıllar boyu o kadar alıştım ki hala 2000 sürümünü (15.10.17) kullanıyorum ve çok memnunum. Bu kadar gevezelikten sonra programı anlatayım.



Programı açar açmaz yukarıdaki gibi bir pencere geliyor. Kullanışlı ve önemli özellikleri kenara yazdım. Yanlış hatırlamıyorsam 255 katmana kadar destekliyor ve siz programı açar açmaz 9 yada 10 katman kendisi ekliyor. Bunlardan önemli olanlar (diğerlerini ben de bilmiyorum aslında) :
  • Top: Bakır yolların olduğu katman
  • Bottom: Çift taraflı baskı devrelerde alt katman
  • Top Silk: Bakır yolların olmadığı tarafta devre elemanlarının tanımları (R2, C3, Q1 gibi) yazar ya işte o.
  • Bottom Silk: Top silk'in çift taraflı karşılığı. SMT kullanmayacaksanız çok da gerekli değil.
  • Board: Baskı devrenin sınırlarını belirleyen katman.

Program ilk defa kurulduğunda henüz kütüphaneler ekli olmuyor. Kütüphanelerde kullanacağımız devre elemanlarının hazır ölçülmüş biçilmiş şekilleri olduğundan sizi tek tek elemanı ölçüp ona göre delik koyma zahmetinden kurtarıyor. Devre elemanlarına tıklayınca liste bomboşsa kütüphaneler henüz ekli değildir. Yukarıda Library menüsünden Setup'u seçip kütüphaneleri eklemek gerekiyor. Bazı kütüphaneleri hiç kullanmadımsa da hepsini eklemeyi tercih ediyorum. Az bilinen garip bir devre elemanıyla karşılaşınca hepsini gözden geçirmek için tekrar eklemeye gerek kalmıyor.

Alt katman devredışı
Kütüphaneleri ekledikten sonra program kullanıma hazır duruma geliyor. Bundan sonra herhangi bir çizime başlamadan önce mutlaka yapılması gereken iki şey var. Birincisi katmanları belirlemek. Eğer çift taraflı bir devre geliştirmeyecekseniz Bottom'u (hatta Bottom'la ilgili bütün katmanları) kapatmakta yarar var. Options menüsünden Layers'i seçerek yada Top'un yanındaki kırmızı kutucuğa tıklayarak katmanların belirlendiği arabirimde önce Layers altında bottom'a sonra da sağda Disable düğmesine basarak alt katmanı kapatıyorum.




Bu arabirimi kullanarak Sets sekmesinde bu katmanlara ek olarak kendi katmanınızı oluşturabilirsiniz ancak bence gerek yok.

Örnek için şu adresten bulduğum basit sayılabilecek devre şemasını kullanacağım. 

Katmanları belirledikten sonra yapılması gereken ikinci iş yapılacak plaket boyutlarına karar vermek. Ben devre kartını aldıktan sonra kesme zahmetine girmemek için kafamda yaklaşık bir boyut belirliyorum. (Bu devre şu kadar alanda yapılabilir gibi...) Sonra gidip ona en yakın boyutlardaki bakırlı plakayı alıyorum ve çizimi o plakaya göre yapıyorum. Örneğin bu devreyi 5cm x 5cm'lik plakada yapalım. PCAD inç ve mil birimlerini kullandığından ölçüleri çevirmek gerek. (1 inç = 2.54cm, 1 inç = 1000 mil). Dolayısıyla 2 inç x 2 inç yani 2000 mil x 2000 mil'lik bir alan gerekli. Ekrandaki noktalar yeşil değil de beyaz olana kadar gözkararı biraz yaklaştırıyorum. Yeşil noktalar varsa sizin çözünürlüğünüz (Aşağıda ABS düğmesinin yanında mil cinsinden belirtilen değer) görüntülenen alana sığmadığından nokta sayısı azaltılır. Yakınlaştıkça beyaz noktalar görünmeye başlar. Beyaz noktaların arası sizin seçtiğiniz çözünürlüktedir.

Aşağıda Board katmanını seçip, sonra bu alanı soldaki çizgi gerecini seçip bir kareyle belirliyorum. Çizerken sağ altta çizginin uzunluğu belirtiliyor. Önce bir köşeye tıklıyorum, imleç şekil değiştiriyor, sonra diğer köşeye tıklıyorum, çizginin uzunluğu istediğim kadar olmadıysa aynı yönde biraz daha tıklayıp 2000 olana kadar çiziyorum. Sonrasında dik açıyla diğer kenarı köşesine tıklayarak belirliyorum. Dört kenarın tamamını belirleyip kare (yada istediğiniz herhangi bir şekil) oluşturduktan sonra sağ tıklayarak çizimi bitiriyorum. Board katmanının renginden bir kare oluşması gerekiyor.

Bundan sonra View menüsünden Extent diyip çizimi ekrana sığdırıyorum ve Top katmanını seçip devre elemanlarını eklemeye başlayabilirim. İlk zamanlarda devre elemanlarının nerede oldukları yada olmayan eleman için ne kullanmak gerektiği biraz sıkıcı olabilir. Önemli kütüphaneler ve içeriklerini kısaca belirtmeye çalıştım:
  1. CONNECT.LIB: DB9, DB25, dişi ve erkek slotlar (ISA, PCI gibi) için bağlantılar. 
  2. DIODE.LIB: Diyotlar
  3. PCBCONN.LIB: Connect.lib'dekine benzer bağlantılar ama daha fazla çeşit var.
  4. PCBMAIN.LIB: En çok kullanılan kütüphane. Kondansatörler, entegreler, dirençler, jumperlar ve bazı genel diyot ve transistörler bu kütüphanede bulunur.
  5. PCBSMT.LIB: SMT için gerekli devre elemanları.
  6. TRANS.LIB: Transistörler
Burada devre elemanlarını seçerken Browse düğmesine basıp şeklini görmek de olası. Eğer Browse'ye basınca şekil çıkmıyorsa o eleman baskı devre çizimi için değil devre şeması çizimi içindir. (Daha önce de belirttim PCAD'in bir de devre şeması çizimi için modülü var ancak ben onu kullanmıyorum.) Çizimi yaparken şemanın hemen altındaki delikli pertinaks çizimine sadık kalmayacağım ama elbetteki sonuçlar benzeyecektir. Pil beslemesi ve hoparlör plaketin üzerinde olmayacağından ben onlar için iki delik (PAD) atıp tel lehimlemeyi tercih edeceğim ancak potansiyometre plaketin üzerinde olacak. Butonu koymayacağım. Bir de devreyi basmadan önce protoboard'da yapıp, çalışıp çalışmadığından emin olduğumu varsayarak elemanların elimde olduklarını yani bacak aralarını bildiğimi varsayacağım. Örneğin bazı elektrolitik kondansatörlerin iki bacağı arası 100 milken diğerlerinin arası 200 mil olabiliyor. Bacakları uzatarak yada bükerek lehimleyince sorun olmaz ama tam uzaklığı neyse onu kullanmak devreye daha profesyonel bir görünüm veriyor.

Önce besleme ve hoparlör için 2şer delik (pad) ekledim.

Devre elemanlarını eklerken hangilerinin kullanılacağı biraz deneyim gerektiriyor. Örneğin standart dirençler için RES400 kullanınca tam oturuyorlar. Biraz daha tel bırakmak gerekirse RES500 kullanmak gerekli. Devre elemanları için sırasıyla devre elemanları düğmesine tıklayıp, boş bir yere tıklamak, yerleştirilecek elemanın bulunduğu kütüphaneyi seçmek (örn. PCBMAIN.LIB) ve o kütüphanenin içinden elemanı (örn. RES400) seçmek gerekiyor. Sonra kaç tane RES400 kullanılacaksa (bu örnekte üç) tıklaya tıklaya yaklaşık yerlerine koyuyorsunuz. Sonrasında sağ tuşla tıklayıp normal fare imlecine dönüyorsunuz. Benim yerleştireceğim dirençler dikeydi fakat PCAD onları yatay koydu. Hemen önce en sol üstteki fare imleçli düğmeye basıp yerleştirdiğim direncin üzerine tıklıyorum. Direnç seçiliyor, sonra klavyeden 'R' tuşuna basarak döndürüyorum. Yada fare düğmesine bastıktan sonra masaüstündeki ikonları seçer gibi dirençleri seçip çoklu seçmek ve 'R' ye basarak hepsini birden çevirmek olanaklı. Çevirdikten sonra fare imleciyle yaklaşık yerlerine sürükleyip aşağıdaki duruma getirdim.

Benzeri şekilde tüm elemanları PCBMAIN.LIB kütüphanesinden; elektrolitik kondansatör için CAP200RP, normal kondansatör için CAP200, LEDler için LED100 ve 555 için DIP8 seçerek yerleştirdim. Ancak bir tek potansiyometre için satın almış olduğuma uygun bir eleman bulamadım. Böyle durumlarda potansiyometreyi kumpasla yada protoboard'la ölçerek (protoboard'un delikleri arası 100 mil'dir) elemanın bacakları arasındaki mesafeyi bulup ona göre pad'ler yerleştirmek gerekir. Ayrıca kendi başına duran delikler anlamsız olacağından (en azından devreye bir sene sonra tekrar bakınca kesin anlamsız gelecektir.) Top Silk katmanında potansiyometrenin sınırlarını belirlemek için bir dikdörtgen atmak mantıklı olabilir.


Ben, tek başına bir dikdörtgen de çok açıklayıcı olmayacağından yazı aracını kullanarak 'POT1M' yazısını ekledim. Yazı aracını kullanmak basit. Üzerinde 'A' olan düğmeye bastıktan sonra yazının yaklaşık olarak yerleştirileceği yere tıklayıp çıkan pencerede yazıyı ekledikten sonra 'Place' demek yeterli. Yerini beğenmediğiniz yazıyı yine devre elemanına yaptığım gibi fare imleciyle seçip sürükleyebilir yada döndürebilirsiniz.

Tüm elemanları yerleştirdikten sonra geriye bağlantıları yapmak kalıyor. Bağlantıların doğrudan baskı devre yollarıyla bir ilgisi yok ancak yolları yerleştirirken bağlantıları kısa tutmakta her zaman yarar var. Uzun yolların diğer yolları kesme olasılığı artıyor. Bağlantılar ters 'N' biçimli araçla yapılıyor. Yapılacak iş ters 'N' bağlantı aracını seçmek ve bağlantı yapacağınız deliğin birini diğerine sürükleyerek elemanların bacaklarını birbirlerine bağlamak. Bağlarken ilk defa bir bağlantı yaparsanız size NET'in adını soracak. Bunlara ne ad verdiğinizin bir önemi yok ama özellikle artı besleme ve toprağın NET00000 ile NET00001 olması size sonradan kolaylık sağlayacaktır. Ben ilk önce + beslemeyi üstteki LED'in + bacağına bağlayarak NET00000 adını buna verdim sonra da GND'yi LED'in eksi bacağına bağlayıp buna da NET00001 dedim. Bir kere bağlantıya bir ad verdikten sonra bundan sonra aynı yere bağlanan her bağlantının adı da aynı olacak. Yani bundan sonra GND baskı devrenin her yerinde NET00001 olacak. Tüm bağlantılar bittiğinde özellikle 555'in civarında karışık bir görünüm olacak. Net'lerin adları burada önem kazanıyor. Devreyi kontrol etmek için sol üstteki fare imleci moduna geçip - beslemenin bulunduğu deliği seçip sonra sağ tıklıyorum. Çıkan menüde Highlight Net dediğim zaman o Net'e bağlı olan bütün delikler farklı renkte gösteriliyor. Hata kontrolü için yararlı. Seçimi geri kaldırmak için Unhighlight Net demek gerekli.

Kondansatörler, LED ve 555'in birinci bacağı eksiye bağlı olmalıydı. Demek ki sorun yok.

Aslında buraya kadar herşey tamamlandı ama tavsiye edeceğim bazı noktalar var. Gördüğünüz delikleri çapı 60mil yani 1.5mm. Eğer matkap ucunuz biraz titreşiyorsa bile bu delikleri delmek imkansız hale gelebiliyor. Matkap ucu sallanarak lehimlenecek yerleri de götürebiliyor. Benim bu duruma karşı önerim delikleri büyütmek.

Pad'e sağ tıklayınca çıkan menüden Properties'i seçip Pad Styles düğmesine basın. Herhangi birine tıklayıp Copy diyin ve istediğiniz bir adda kopyalayın. Örnekte ben P:BIR adını seçtim. Sonra Modify (Simple)'ı seçecek Width/Height değerlerini değiştirin. Çok büyük değerler deliklerin çevresinde kalan bakırların birbirine değmesine yol açabilir. Benim önerim Width (En) için 70mil Height (Boy) için de 160 mil Shape (Biçim) olarak da Oval iyidir. Değişikleri yapıp OK dedikten sonra Pad style olarak yeni tanımladığımız Pad'i seçip tekrar OK diyince artık geniş Pad yerleştirilmiş oluyor. Diğer Pad'ler için yine Properties'e gelip çıkan arabirimde Pad Style olarak yeni oluşturulmuş Pad'i seçip OK deyince diğer Pad de büyütülür. Elbette bunları tek tek yapmak sıkıcı olacaktır. Fare imlecindeyken CTRL'ye basılı tutarak hoparlöre ve potansiyometreye ait delikleri seçip hepsini bir seferde değiştirmek olası. Ancak böyle yapınca potansiyometreye ait deliklerin uzun tarafları birbirlerine yakın olacaktır. Daha düzgün olması için bir Pad daha tanımlayacağız. Bu seferkinin eni 160mil boyu 70 mil olacak. Yani eskisinin 90 derece dönmüşü olacak. Herhangi bir deliğe tıklayıp aynı şekilde özelliklerden varolan bir delik biçimini kopyalayıp en ve boy değerlerini değiştirmek yeterli.

Bundan sonra devre elemanlarının bacaklarını da bu deliklere uyduralım. Benzer elemanlar CTRL ile toplu seçilerek değiştirilebilir. Örneğin RES400'lerin tümünü seçip sağ tuşla tıklıyorum ve Properties'i seçiyorum. Çıkan arabirimde Pattern Pads sekmesine gidiyorum ve solda A ve B olarak gördüğüm iki tür deliği de seçiyorum. Normalde dikkat edilirse dirençlerin bir bacağı kare diğer bacağı yuvarlaktı. A kare olan bacak, B yuvarlak olan bacak. Genelde bu türden bir farklılaşma kutupları fark eden devre elemanlarında birinci bacağı belirtmekte kullanılır. Örneğin elektrolitik kondansatörün + bacağını yada entegrelerin birinci bacaklarını ayırdetmek için kare delik koymak mantıklıdır. Dirençte böyle bir farklılaşma olmadığından ben her ikisine de oval delik koyacağım. Her iki deliği de (A ve B) seçtikten sonra Pad Style olarak P:IKI'yi (fark etmez P:BIR de seçilebilir ama P:IKI bana daha güzel göründü.) seçiyorum ve alttaki Apply düğmesine basıyorum. Sadece A'yı değiştirirseniz sadece kare olan bacaklar değişir. Benzer biçimde LED'leri seçip her iki deliğini P:IKI yapıyorum. Burada dikkat edilmesi gereken LED'lerin bacakları birbirine yakın olduğundan P:BIR yapılırsa bakırlı yollar birbirine değecektir. CAP200 ve CAP200RP'yi birlikte seçip Properties'i seçince Pattern Pads sekmesine tıklanmıyor. Bunun nedeni daha önce dediğim gibi aslında her ikisi de kondansatör olsa bile ikisinin türünün farklı olması. Dolayısıyla aynı işlemi CAP200 için ayrı CAP200RP için ayrı yapmam gerekli. Son olarak entegre kaldı. Bunun için yine Pattern Pads de sekiz bacağını birden seçip Pad Style olarak P:IKI seçilebilir. Eğer birinci bacağın Pad'i dikdörtgen olması istenirse tekrar bir Pad tanımlayıp boyutları aynı fakat shape olarak Rectangle seçmek gerekli. Yazıyı çok uzatmamak için ayrıntısına değinmeyeceğim. Ben olduğu gibi bıraktım.

Pad'leri değiştirdikten sonra baskı devrenin görünümü.
Bu aşamada baskı devrede sadece bağlantıları tanımladım ama bakırlı yolları çizmedim. Bu biçimiyle diske kaydediyorum ancak kaydederken ASCII olarak kaydedicem. Binary olarak kaydetmemin bir zararı yok ama Autorouter'ı kullanırken zaten kendisi ASCII'ye çevireyim mi diye soracak.

Bakırlı yollar, sol üstte ikinci satırda (fare simgesinin altında) Route Manual aracıyla elle çizilebilir. Yapmam gereken Route Manual'i seçtikten sonra herhangi bir deliğe tıklamak. Tıkladıktan sonra o Net'in rengi değişecek (Highlight) sonra o Net'e bağlı başka bir deliğe tıklayıp yolu götürecem; sağ tuşla tıkladığımda da bakırlı yol çizilmiş olacak. Yol üst katmanda olduğundan, kırmızı görünecek. Diğer taraftan üzülerek belirtmeliyim ki bilgisayarın kendi algoritmasıyla çizdiği yol, en azından benim çizdiğim bütün yollardan genel olarak daha iyi oluyor ve otomatik yol çizimi basit bir devre için bile en az bir saatlik işten kurtarıyor. Otomatik yol çizimi için Route menüsü altında Autorouters'ı seçip gelen arabirimde Autorouter olarak Quick Route'u seçiyorum. Quick Route PCAD'in kendi yol çizme programı. İstenirse SPECCTRA adlı yazılım yüklenerek yol çizimi SPECCTRA'ya da yaptırılabilir. Öncelikle Quick Route'u seçip Start diyorum. Devrenin çizilmişi çıkıyor.


Bu haliyle bende +'dan LED'e giden bir yolu çizemeyip mavi renkli bağlantı olarak bıraktı. Bunun nedeni hoparlör için koyduğum Pad'lerin birbirine yakın olmalarından dolayı arasından yol geçememesi. (Ben de sonradan fark ettim). PCAD ile yol çizdirince çizilmiş yolların olduğu dosya yeniden kaydediliyor ve başına bir R harfi ekleniyor (Route anlamında). Yapılacak şey hoparlör için bıraktığımız Pad'lerin arasını açmak. Bunun iki yolu var, hiç yol olmayan 'R'siz ilk dosyaya döner, deliğin arasını açarım yada yolların olduğu dosyada deliğin arasını açar tekrar yol çizdiririm (yada elle çizerim). R'li dosyaya baktığımda kılavuz noktaların yine yeşile döndüğünü görüyorum çünkü Autorouter, Routing Grid diye bir parametre alıyor ve 25mil olarak seçili. Bunun anlamı en yakın iki yol birbirine 25 mil'den daha yakın olamaz demek. Otomatik olarak kılavuz noktalar 25mil'e indirildi ama yeterli zoom olmadığından yeşil noktalar görünüyor. İstenirse en alt satırda 100mil'e geri alınabilir. Ben ilk dosyada sağdaki deliği biraz daha sağa aldım ve tümünü yeniden çizdirdim. Başka bir seçenek de iki delik daha ekleyip baskı devrenin üst katından köprüyle birleşmeyen yolları birleştirmek.


Şu haliyle herşey hazır ama yine yapılmasını tavsiye edeceğim ufak şeyler var. Birincisi her ne kadar Autorouter kullanmak elle çizmekten daha iyi olsa da Autorouter bir algoritma olduğundan bazı şeyleri kendisi akıl edemiyor. Bir numaralı RES400'ün yukarıdaki bacağını ele alalım. Bir tane entegrenin üçüncü bacağına giden düz bir yol çıkıyor ve entegrenin altıncı bacağına giden yolun dibinden geçiyor, bir de ayrı bir yol hoparlör deliklerine giderken aynı yerden 45 derece açıyla çıkıyor. 45 derece açıyla çıkan yol anlamsız onun yerine alttaki yolla T biçiminde birleşse daha iyi olacak. Ayrıca başka bir bakır yolun o kadar yanından geçeceğine iki numaralı direncin iki bacağı arasında kocaman boşluk var. Daha yukarıdan geçse baskı devreyi basarken biraz rahatlık sağlar. Özellikle Positive20 kullanırken eksik pozlandırmada birbirine çok yakın geçen yolların arası erimiyor. Veya üçüncü dirençten gelen yol entegrenin altıncı yerine yedinci bacağına bağlansa ortalık biraz daha ferahlar. Bu nedenle Autorouter'in çizdiği yollar her zaman elle düzeltmeye ihtiyaç duyuyor. Bunu yapmak oldukça kolay. Yerini beğenmediğim devre yolunu fare imleciyle tıklayıp seçtikten Delete tuşuyla siliyorum. Silinen yolun yerini yine mavi bağlantı alıyor. Bütün beğenmediğim yolları silip Routing Manual ile sildiğim yolları elle düzeltiyorum.

Bir diğer sıkıntı da yolların çok ince olması. Aslında Net'lerin özellikleriyle (Attribute) oynayarak bir çok özelliğini değiştirmek olası. Width özelliği de bakırlı yolların kalınlığını belirleyen özellik ancak bu birçok durumda özelliği değişen Net'in bakırlı yola dönüşememesine neden oluyor. Yollar için Autoroute arabiriminde 10mil gibi bir kalınlık veriyor ki bu da çeyrek milimetre anlamına geliyor. Belki CNC tezgahta işlenebilir ama elle yapmak için çok ince, üstelik yine üretimde Positive20 kullanılacaksa sıkıntılı. Maalesef PCAD yolların kalınlığını bir seferde değiştirme gibi bir olanak sunmuyor. Yol kalınlığı değişince çoğunlukla Routing Grid parametresinde de değişiklik yapmak gerekiyor. Yol kalınlıklarını değiştirmek için iki yöntem var. Birincisi Autoroute bittikten sonra bakırlı yola çift tıklamak (yada sağ tuşla tıklayıp Properties'den) ve çıkan arabirim penceresinden yol kalınlığını değiştirmek. Yine bunu bütün yollar için ayrı ayrı yapmak gerekiyor. Ben genelde plaket üzerinde yer varsa, yollar için 40mil'i tercih ediyorum ancak yer yoksa 25mil'e kadar azalttığım da oluyor.

Çizimdeki bazı yolları biraz kenara kaydırdım yada birbirinden uzaklaştırdım. Daha sonra entegrenin altındaki yolları 25mil diğer yolları 40mil olacak biçimde değiştirdim. Küçük küçük birden fazla değişiklik yaptığım için ekran görüntüsü koymadım sadece baskı devrenin yollar kalınlaştırıldıktan sonraki halini ekledim.




Yol kalınlıklarını değiştirmek için iki yol olduğundan bahsetmiştim fakat bunun için daha önce bahsettiğim SPECCTRA gerekiyor. SPECCTRA ayrı bir baskı devre programı. PCAD'in dışarıdan bu programı çağırmak için arabirimi bulunuyor. SPECCTRA kuruluysa Autorouter olarak seçilir. İlk defa kurulduğunda SPECCTRA'nın yolunun Autorouters arabirim penceresinde ayarlanması gerekiyor. Penceredeki Command Line düğmesine bastıktan sonra programın yolunu girmek yeterli. System Log ve Extra Options'da bir hata olduğundan düzgün biçimde ayarlanamıyor. Onu olduğu gibi bıraktım. OK diyip bunları geçtikten sonra Do Wizard düğmesine basıp çıkan pencerede Auto Create DO File demek gerekiyor. DO dosyası SPECCTRA'nın bakırlı yolları oluştururken kullanacağı parametreleri içeriyor. Ben bu pencereye OK diyip sonra Autorouter penceresinde Edit as Text düğmesine basarak parametreleri düzenlemeyi tercih ediyorum. Benim ilgilendiğim iki tane parametre var. Birincisi Grid Wire. Bu PCAD'in Routing Grid parametresiyle aynı, yani yanyana iki yol arasındaki en kısa mesafenin uzunluğu. rule pcb (width 10.0) parametresi de ikinci parametre; bakırlı yolların kalınlığını belirliyor. Bu değeri arttırınca bakırlı yolları biraz daha yaklaştırmak gerekiyor dolayısıyla Grid Wire'ı azaltmak gerekiyor. Width olarak 25..40 arası, Grid Wire'da 20..25 arası fena değil. DO dosyasını düzenledikten sonra Save'e basıp kaydediyorum ve Start'a basıyorum. Bazı durumlarda SPECCTRA çalışmayabiliyor. Bu SPECCTRA'nın yada PCAD arabiriminin uzun dosya adlarını düzgün desteklememesinden kaynaklanıyor. SPECCTRA, DSN uzantılı bir dosyada hata veriyorsa sekiz karakterden uzun dosya adlarını kontrol etmek gerekiyor hatta dosyayı kök dizinine taşıyıp oradan çalıştırmak kesin sonuç veriyor. SPECCTRA düzgün çalışınca Autorouter'lar arasında seçim soruyor. Ben genelde Interactive Router'ı tercih ediyorum ama aralarında belirgin bir fark göremedim. SPECCTRA işlemini yapıp sonlanıyor ve dosyanın bitmiş biçimi PCAD'e yollanıyor.

SPECCTRA'nın Autorouter'ı bazı yönlerden PCAD'den daha güçlü. Özellikle tek katmanlı baskı devrelerde genellikle parametrelerini düzenleyince PCAD'den daha iyi yol çiziyor ama PCAD çift katmanlı baskı devrelerde çok daha güçlü. Aslında çift katman baskı devrelerde PCAD'in stratejisi yatay yolları alttan dikey yolları da üstten geçirmek. Böylece her katmanda mümkün olduğu kadar birbirine paralel yollar kalıyor. (Bu arada bunları yazarken birşey daha fark ettim. Üst taraftaki LED'i 90 derece çevirince yollar daha kolay belirleniyor. Bundan sonraki ekran görüntülerinde çevirilmiş LED'i kullanacağım.) SPECCTRA daha başarılı olsa da PCAD'deki gibi elle müdahale edilmesi gereken anlamsızca çizilmiş yollar kalabiliyor. SPECCTRA'ya yolları çizdirip elle biraz üzerinden geçtikten sonra aşağıdaki baskı devreyi elde ettim.


Herşey hazır gibi. Bundan sonra son küçük değişiklikler kaldı. Birincisi, devrenin girişine hangi ucun artı hangisinin eksi ve besleme geriliminin ne kadar olduğunu yazmak. Bu, devreye sonradan baktığınız zaman nereye kaç volt vermek yada multimetreyle nereden kaç volt okumak gerektiğini bilmek için çok gerekli. Onun haricinde ben devrenin boş bir köşesine adımı ve devreyi çizdiğim tarihi yazmayı seviyorum. Yıllar sonra bakıp ne zaman nasıl birşey tasarladığımı görmek hoşuma gidiyor. Bunları eklemek için yazı ekleme gerecini kullanmak gerek. Bir de bence en eğlenceli olan kısım baskı devreye bakır alanlar eklemek. Demek istediğim özellikle alıcı yada verici gibi devrelerde vardır. Baskı devre üzerindeki bakırlı alanlar sadece yollar geçecek şekilde yukarıdaki resimde olduğu gibi açılmaz. Onun yerine yolların sadece kenarları bakırdan ayrılır, boş alanlarda toprağa yada hiçbiryere bağlı olmayan bakırlar bırakılır. Bu hem bana güzel geliyor hem de devreyi demir3klorüre atınca erime zamanını azaltıyor. Benim gibi sabırsızsanız tercih edilebilir. Bunu yapmak için sol tarafta yazıyla çizgi arasında Place Copper Pour gereci var. Onu seçiyorum. Top katmanındayken en başta baskı devrenin sınırlarını çizgilerle belirlediğim gibi plaketin kenarlarından biraz daha içeriye bir yere Copper Pour ile benzer bir kare çizip sınırları belirliyorum. Sağ tuşla tıklayınca anlamsız bir kare oluşacak. Sonra fare imleciyle kareye çift tıklayıp Properties'den Connectivity sekmesinde NET00001'i (yani toprak) ve Style sekmesinden de Poured ile Pattern'de istediğim bir deseni seçiyorum (bence çaprazlı güzel). Backoff parametresi kalacak bakırla yollar arasında ne kadar mesafe olacağı belirleniyor. Çok yakın olmamasında yarar var. Island Removal sekmesinde istenirse belli bir alandan küçük kalmış, içerilerde kalan yada yollardan ötürü seçilen Net'e bağlantısı yapılamamış adacıklar oluşmaması sağlanabiliyor. OK dedikten sonra boş alanlardaki bakırlar bırakılıyor. İstenirse hiçbir yere bağlı olmayan bakır alanlar da bırakılabilir. Şekilde adacıklara bağlı mavi bağlantılar yollardan dolayı hiçbiryere bağlanamamış adacıklara bağlı. Bunların oluşması sorun değil.

Herşey hazır.

Şimdi bunun çıktısını almak lazım. File menüsünden Print'i seçince maalesef herşey hallolmuyor. Setup Print Jobs'a basıp hangi katmanda nelerin kağıda basılacağını seçmek gerekiyor. En üstteki Print Job Name'e herhangi bir ad yazın. Bakırlı katman için Top katmanını seçin. Baskı devrenin sınırlarını da eklemek için CTRL'ye basılı tutarak Board katmanı da seçilmelidir. En sağdaki Display Options'da Pads ve Pad/Via Holes seçili bulunmalıdır. Çift katmanlı devreler için Vias seçeneği de seçilmesi gerekir. Bu haliyle Add düğmesine tıklanır ve bir baskı işi oluşturulur. Kağıda yada PNP kağıdına baskı alınacaksa bu hali yeterlidir. Asetata baskı alıp Positive20 ile çalışılacaksa Display Options'da Mirror'u da seçmek gerekebilir. Ayrıca bakırsız taraf için devre elemanlarının sembolleri, değerleri hatta şekilleri yani Top Silk katmanı basılacaksa ayrı bir çıktı almak gerekir. Bu nedenle başka bir Print Job Name daha verilir ve bu sefer Top Silk, Board katmanları seçilir. Ref Des, Type, Value vb. gerekli değerler seçilir. Çift taraflı devrenin alt katmanı için de ayrı iş tanımlamak gerekir. Close düğmesine bastıktan sonra Print Preview ile baskı kontrol edilebilir yada Generate Printouts ile seçilen işler varsayılan yazıcıya yollanır. (Başka yazıcıyı Print Setup ile değiştirin.) File menüsünde görüleceği üzere PCAD'in Gerber yada Drill çıktısı da var yani CNC tezgaha doğrudan çıktı yollamak da mümkün.

Biraz uzun bir yazı oldu. Bir CAD programının bildiğim kadarını etraflıca anlatmaya çalıştım artık ne kadar başarabildimse. Bundan sonra bir ara zamanım olursa çizilmiş baskı devrenin nasıl üretileceğini anlatacağım.

6 Temmuz 2012 Cuma

Bir başka PIC

Sayıca en fazla satın aldığım devre elemanlarını sıraladığımda muhtemelen birinci sırada her işe koşulan BC548 sonrasında LEDler ve daha önemlisi üçüncü sırada PIC16F84A gelir. Başlıkta kastettiğim aslında PC'lerin programlanabilir kesme denetleyicileri (Programmable Interrupt Controller) yerine Microchip firmasının ürettiği ve açılımı Peripheral Interface Controller olan mikrodenetleyici serisi. PC'lerin PIC'lerine dair birşeyler daha sonra da ekleyeceğim.

PIC serisi mikrodenetleyicilerin adını birçok kimse duymuştur. Mikrodenetleyiciler, kabaca sade yapıya sahip mikroişlemcilerin aksine üzerlerinde paralel ve seri I/O portları, ADC/DAC gibi arabirimleri hazır olarak gelen ve entegrenin içerisinde Timer, RAM/ROM gibi ıvır zıvırların da olduğu işlemciler. Bana hep mikroişlemciyle PLC arasında kalmış entegreler olarak gelmiştir. Siz programınızı geliştirip EEPROM'a aktarıyorsunuz. Devreye takıp elektriği verince kodu çalışmaya başlıyor.

16F84A denetleyicisi yurtdışında artık tükenmek üzere olan bir denetleyici. Bunun yerini ucuza maledilen hem de daha yetenekli ve pin uyumlu 16F628 modeli alıyor [ http://www.finitesite.com/d3jsys/16F628.html ] ancak 16F84A için internette hala deli gibi amatör tasarımlar bulabilmek olanaklı.

16F serisiyle tanışmam yaklaşık on sene öncesine rastlasa da son bir senedir aktif olarak kullanıyorum. Aslında bunun nedeni ilk aldığımdaki programlayıcının çalışmayıp beni deli etmesiydi. Bu nedenle programlayıcılara ileride biraz değineceğim. Bundan önce tesadüfen gördüğüm ve yanda resmini eklediğim hazır kitten bahsedeyim. Bunu piyasadaki dükkanlarda bulabilirsiniz. Ben üzerinde çok fazla tersine mühendislik gerçekleştirdiğim için kendim tasarlamış kadar hakimim ancak ticari bir ürün olduğundan detaylarının tamamını vermeyeceğim.

Uzun bir aradan sonradan programlayıcısı yüzünden beni kendine küstüren 16F84 denetleyicisiyle barışmaya karar verip bu kiti aldım. Her kit alışımdaki gibi heyecanla eve geldim. Devre elemanlarını yerleştirip lehimlemeye başladım. (Kitin hazır lehimlenmişi de satılıyor ancak ben kendim kurduklarımı tercih ediyorum.) Herşey bittiğinde kesin lehimlerken yaktım dediğim transistörlerin hiçbirini yakmadığımı, devrenin sorunsuz çalıştığını görünce önce sevindim. Devreyi çalıştırdım; zamanı kurup geri sayımı başlattım; süre dolduğunda röle çekti. Hepsi bu kadar. (Ya ne olacaktı?) Her kiti yaptıktan sonra, satın alıp eve gelirkenki heyecanın tam tersi orantılı bir hayalkırıklığı yaşıyorum, çünkü yapılacakları yaptım herşey bitti. Oynayacak bir şey yok çünkü amaç belli.

Bir kaç gün sonra bari kodu inceleyeyim diyip kendi programlayıcımı yapmaya koyuldum. Elimde iki farklı programlayıcı şeması vardı. Biri JDM Programmer olarak bilinen ve benim de zamanında kendisini yada çok benzerini satın aldığım model, diğeri de görece çok daha basit ve beslemesi dışarıda olduğundan gereksiz kablo kalabalığı yaratan başka bir model. Birinci modelde sanıyorum elektrik beslemesi, seri port üzerinden gelen akımın bir kondansatörde depolanıp 5V'a yakın bir zener üzerinden entegreye verilmesiyle sağlanıyor, böylece dışarıdan bir besleme gerekmiyor.

İkinci model basit olduğundan önce onu protoboard'a kurdum. Besleme katını yapmaya üşendiğimden beslemeyi doğrudan adaptörden aldım. Devreyi bağladıktan sonra donanım denetlemesinde programlayıcıyı görüyordu ancak programlarken on sene önce olanlar tekrar oluyordu. Neyse diyip ikinci programlayıcıyı kurdum. Sonuç yine aynı. Derken birşeyi fark ettim; ilk denemede adaptörü 9V'a ayarlamışım ama entegrenin besleme gerilimi 5V. Dolayısıyla büyük olasılıkla PIC'i daha okuyamadan yaktım. Bu arada PIC'lerde Code Protect (CP) diye bir özellik var. CP'yi set ederek yazdığınızda kodunuz okunamıyor. Büyük olasılıkla benim kod da öyleydi ama artık yanmış zaten ne önemi vardı ki.

Bu sırada kullandığım yazılımdan şüphelendiğimden programlayıcıyla birlikte üç ayrı yazılımı denedim. Bu yazılımlar sizin yazıp derleyiciyle ikili koda dönüştürdüğünüz dosyaları alıp seri port üzerinden entegrenin EEPROM'una aktarıyorlar. Seri portu kullandıklarından bir sıkıntı daha var: Windows NT tabanlı sistemlerde donanıma doğrudan erişemediklerinden çok yavaş çalışıyorlar ve hatta çalışmıyorlar. Bu nedenle bütün bu işleri yapabilmek için biryerlerden P2 sistem bulup (anakartında ISA slotu bile var.) Windows 98 kurdum. Bu üç programların adları şöyle:
  1. IC-Prog: Daha önceden de bunu kullanmıştım. Basit bir kullanımı var üstelik dökümanlarında JDM programmer'i tanıyabildiğini söylüyor.
  2. WinPIC: Piyasadaki bir çok programlama devresini tanıyor ve yaygın olarak kullanılıyor.
  3. pgm84: JDM Programmer'in tasarlayan adamın pascal'da geliştirdiği açık kaynak kodlu yazılım. Programın komut satırı parametrelerini anlamak için kaynak kodunu incelemem gerekti ama başarılı buldum. [ http://www.jdm.homepage.dk/newpic.htm adresinde bulunabilir ancak ben tavsiye etmiyorum. ]
Entegreleri yaktığım için gidip boş bir tane daha 16F84A satın aldım. JDM programmer hala protoboard'da kuruluydu. pgm84 ile sağdan soldan bulduğum basit bir hex dosyasını yazdım. Sonuç: Başarılı. Ancak hala IC-Prog'da sorunlar çıkıyordu. Bundan sonra JDM'in elemanlarını alıp tekrar poşetine kaldırdım. İlk tasarıma geri dönüp, besleme katını düzgünce yaptım. Üstelik bu olaydan sonra kullandığım bütün 16F84 devreleri için aynı yada çok benzeri bir besleme katı kullandım. Programlayıcıyı bitirip IC-Prog ile denedim; sorunsuz çalıştı. Bahsettiğim programlayıcının şemasını aşağıya da ekledim. Yalnız şemada bir YANLIŞLIK yapılmış, buna dikkat edin: LM7805'in GND bacağı 3 değil 2, yani ortadaki bacak; Vout da 2. değil 3. bacak.



LM7805'in doğru pin şemasını şuradan bulabilirsiniz. Google resimlerde aratınca zaten binlercesi çıkıyor.

JDM'in programlayıcı devresi, yukarıda verdiğim bağlantıda var. Doğrudan bağlantı şu şekilde: http://www.jdm.homepage.dk/newpic22.gif

Bundan sonra 16F84A'nın assembly'sini öğrenip birşeyler geliştirebilirdim. Bozduğum zamanlayıcıyla başlamak zaten kafamdaydı. Ancak zamanlayıcıyı nasıl tamir ettiğimden daha sonra bahsedeyim.


1 Temmuz 2012 Pazar

Byte, Word ve Alignment Fault

Intel'in çığır açan 8080 ve 8086 işlemcileri hatta onun öncülü gelişmiş ALU 4004 işlemcisi piyasaya sürüldüğünde kimse olayın bu yazıları yazdığımız Pentium'lara varacağını tam olarak öngörememişti. O zamanlar henüz 4004'ler için bir nibble yani 4 bit bir word'u oluşturmak için yeterliydi. 8008 ve 8080'lerle birlikte word 8bit'e yani bir byte'a ve 8086 ile birlikte de bir word 16 bite çıktı.

Word yani CPU Word kelime anlamı olarak mikroişlemcinin bir kerede işleyebileceği en büyük veri miktarı. Yani bir 8086 işlemcinin bir word'unun 16 bit olması demek veri yolunun (data bus) 16 bit olması, yazmaçlarının (register) 16 bit olması ve bir işlemci çevriminde örneğin mov word ptr ax, [7F00h] komutuyla adresleme yoluna (address bus) 7F00h'yı sürmesi, MEMR bacağını set etmesi (daha doğrusu nMEMR'yi resetlemesi) ve veriyoluna o adresteki word'un okunarak o word içindeki bitlerin AX'e tutturulması anlamına geliyor. İşlemci 7F00h ve 7F01h'yı bir çevrimde okuyabiliyor. Ancak yine de mov byte ptr al,[7F01h] ile 7F01h adresindeki byte'a da erişebiliyorduk.

Zaman geçtikçe word kavramı kendi anlamını yitirdi yada byte kavramının altında kaldı demek daha doğru olur. 80386'lara eklenen 32 bitlik genişleme yazmaçlarla birlikte word 32bit'e çıkarıldı. Pentium'larda word hala 32 bitti ancak MMX'lerle birlikte garip bazı genişlemeler sayesinde word 64bitmiş gibi işlemler yaptırabiliyorduk. Veri yolu hala 32 bit olsa da CISC mimarisi sayesinde bellek okuma/yazma süreleri birden fazla işlemci çevrimine (cycle) dağıtılarak bir komutla 64 bitlik verilerin işlenebilmesi olanaklı oluyordu. Aslında bir bakıma word hala 32 bit olsa da 64 bitmiş gibi gösteriliyordu.

Önce nispeten yakın zamanda gelen x64 yada x86_64 mimarisiyle birlikte AMD gerçek anlamda word'u 64 bite çıkardı. Elbette adı üzerinde, bu mimariler varolan 32bitlik x86 mimarisine eklenen bir yama biçimindeki genişlemelerdi. Bana kalırsa artık geriye doğru uyumluluk kavramı uyumluluğun getirdiği avantajlar yanında sürekli eski komut setini desteklemenin getirdiği maliyeti kaldıramıyordu. Yani geriye doğru uyumluluğu yok sayarak geliştirilecek yenikomut setli yeni mimari hızlanmanın önünü açabilecekti. Bu da zaten IA64 yani Itanium mimarisine karşılık geliyor. x86_64'un hala masaüstü makinalarında olmasının nedeni bütün kodları yada en azından bütün derleyicileri bir anda IA64'e göre yazmanın zorluğundan kaynaklanıyor. Ancak yüksek performans piyasasında IA64 işlemciler şimdiden x86'ların yerini almaya başlıyor.

Peki neden bu kadar hardcore işlemci mimarisinden girdim? Çünkü taa 80386 zamanında işlemci word'u 32 bit olsa bile hala aldığımız RAM'leri megabayt üzerinden alıyorduk. Sene oldu 2012 ama hala RAM'ler word üzerinden değil de byte üzerinden satılıyor. Aslında aldığımız 32MB RAM işlemci için boş 8Megaword'luk boş alan içerdiğini düşününce insan biraz kazıklanmış hissetmiyor değil. Diğer taraftan hemen yukarıda 7F01h adresindeki byte'a 8086'larda iki türlü erişilebileceğinden bahsetmiştim. Adreslemeyi byte byte yaptığımız halde bir anda 2 byte'a birden erişmek Intel mühendislerine biraz gereksiz gelmiş olacak ki bellek erişimini hızlandırmak adına yanılmıyorsam Pentium'lardan itibaren adresleme veri yolunun en düşük anlamlı 3 bitini iptal ettiler. Yani Pentium'larda A0, A1 ve A2 artık bulunmuyordu. Sizin 8086'nızda çalıştırdığınız masum mov byte ptr al, [7F01h] komutu Pentium'larla birlikte artık mov dword ptr eax, [7F00h] olarak çalışıyor ve sonrasında gereksiz kısımlar atılarak gereken kısımlar AL'ye yazılıyordu. Bu arada dword yani "double word"ün altını çizmek lazım. Seneler içerisinde word kavramı da karışıklık olmasın diye 16bit'te sabitlenmiş ve 32bitlik word, double word olarak adlandırılmaya başlanmıştı. 64bit'eyse qword diyecektik. Tabi genişletilmiş adresleme yolu sayesinde korumalı modda 00007F00h adresini kullanıyorduk.

Buraya kadar herşey aslında normal gibi ancak zurnanın zırt dediği yer işlemciye mov dword ptr eax, [7F01h] verdiğimiz zaman ortaya çıkıyor. Bu durumda işlemci şunu yapmaya çalışacak:






Ancak bunu yaparken artık 7F01h'ya doğrudan erişemiyor. Dolayısıyla 7F00h'dan okuyup bunu EAX'in gerekli kısımlarına yazacak. Sonra diğer çevrimde 7F04h'ya erişip oradan gerekli olan verileri okuyacak ve yine EAX'in gereken kısımlarına yazacak. Dolayısıyla normalde bir çevrimde tamamlanması gereken okuma iki çevrimde tamamlanacak. Elbette korumalı modda araya girecek denetlemeleri ve kesmeleri saymıyorum. Ancak erişim 4ün katı olan yada başka bir deyişle sonunda üç tane sıfır olan bellek adresine yapılacak olsaydı tek bir çevrimde okuma yada yazma olanaklı olacaktı. Bu da performansı düşüren bir durum. Günümüzde derleyiciler size sormaya gerek bile duymadan bellekte ayırdığınız bütün verileri dördün katlarına gelecek biçimde hizalarlar. Zaten bu olaya hizalama denmesinin nedeni de bu.

Intel mühendisleri bununla da kalmadılar. Eğer EFLAGS'ın AC (Alignment Check) ve CR0'ın AM (Alignment Mask) bitlerini set ettiğiniz zaman size Alignment Fault adındaki istisnayı (exception) atarlar. 80286'nın exception belgelerine baktığınız zaman alıştığımız sıfıra bölme, tuzak kapısı, NMI vb. haricinde 8-15 arasını ayrılmış olarak görüyoruz. 16 yani 10h'dan sonrasını BIOS Video, Disk vb. kesme hizmet programlarının olduğunu biliyoruz. Ancak daha sonradan eklenen bu Alignment Fault kesmesi 17 yani 11h'yı kullanıyor. Bu durum biraz kafa karıştırıcı.

İşletim sistemleri performans açısından bu kesmeye asılıp performans denetlemesi yapabilir ve bu şekilde kullanıcıyı uyarabilir hatta mavi ekran bile çıkartabilirler. Daha önce de dediğim gibi normalde basit bir malloc() fonksiyonu çağırıldığında işletim sistemi dördün katı olan bir adres sağlar. Derleyici de ayırılan dizinin elemanlarını dördün katlarında bulunacak biçimde adreslemeye çalışır. Yine de bazen derleyicinin yapabileceği bir şey kalmayabilir: Örneğin 5 byte'lık bir struct tanımladıktan sonra bu struct üzerinden malloc() çağırırsanız. Böyle durumlarda icc kullanarak derleme yaptığınız zaman UNIX sistemler kullanıcıyı program çalışması esnasında uyarıyorlar.

Son olarak bütün bunları bir yere bağlamak gerekirse; SuperLU kütüphanesini hem x86_64 mimarili Intel Xeon işlemcide hem de Itanium2 işlemcili makinalarda derleyip çalıştırdım. Her ikiside sorunsuz derlendiği halde kurulum testlerinde Itanium makinada hizalama uyarısı verdi:

pstest(17541): unaligned access to 0x600000000003733c, ip=0x4000000000099230

Dikkat edilirse erişilen adres dördün katı ancak erişim yapan makina 64bit. Yani erişilen adresin sekizin katı olması gerekiyor. Aynı hatayı x86_64 makinada vermiyor. Üstelik büyük boyutlu denemelerde programın çalışma süresi yaklaşık dörtte bir daha uzun sürüyor. Programları 64bit makinalar için yazarken, araştırınca Intel icc için basit derleyici komutlarıyla nasıl qword'luk hizalama yaptırabileceğinizi belirtiyor ancak sözkonusu program SuperLU gibi büyük ve başkasının yazdığı bir program olduğunda düzeltme yapmak can sıkıcı uzunlukta olabilir.