ASM kullanıcılarını C'ye alıştırma turları

Başlatan bunalmis, 31 Ekim 2011, 17:57:22

z

Bu başlık da daha önceleri açtığımız BASIC kullanıcılarını C'ye alıştırma turları na benzer şekilde ilerleyecektir.

Amacımızın Keil ile ARM işlemcilere C kod yazmak olduğunu unutmayın.

Ancak bu kez katılımcı sayısı konusuna sınırlama getirmeyeceğim.

https://www.picproje.org/index.php/topic,35980.msg257667.html#msg257667 başlığındaki konuları tekrardan anlatmayacağım.

Tartışmaya katılacak ASM ci arkadaşların ASM kodla örnek vermeleri yerine, hangi işlemleri yapmak istediklerini yazarak sormalarını, ve buna cevaben C kodlarını yazacağımızı hatırlatayım.

Örneğin  A ve B adındaki 8 bitlik değişkenlerimde saklanan iki sayıyı toplayıp sonucu 16 bitlik X değişkenine yazmak istiyorum dediklerinde

char A,B;
int X;
           
           // A ve B nin değer aldıklarını varsayın

           X= A+B; örneğini vereceğiz.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhendisbey

#1
ASM'de register olarak kullandığımız 8 bitlik saklayıcılar (A. satırdan B. satıra şeklinde), C de neye tekabul ediyor değişkene mi?

C de CPU registerleriyle normalde işimiz olmaz.

C de değişkenler tanımlar ve işlemleri doğrudan bu değişkenler üzerinde yaparız.

Bir de C de bit düzeyinde işlem yapmak mümkün mü? Yani 3. bitin 1 olduğunu anlamak için sadece 3. biti nasıl öğrenebiliriz?

Eğer işlemcinizde bit bazında işlem yapan asm komutlar yoksa siz ne yapardınız? C de de aynısını yaparız.

Eğer işlemcinin bir bazında işlem yapan komutlar varsa C'de de bu anlamda komutlar vardır.

Örneğin ASM yazımınızda B.1, 8 bitlik değişkenin 1 nolu biti demek ise muhtemelen C de de B.1 yada benzerı yazım geçerli olacaktır.

Fakat en kötü ihtimal  if ((B>>3)&1) komutu, B nin 3.biti 1 ise karşılaştırmayı doğru kılacaktır.

Buradaki 3 kez sağa kaydırma, ARM işlemcide tek clock da yapılacağından zaman kaybı olmayacaktır.

(ARM işlemcinin Ram ve çevre birimi registerlerinin bazılarına bit bazında da erişilebilir.)
(Sadece I/O Portlara mı  yoksa hepsine mi araştıralım)



Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

Klein

Aslında C'de doğrudan bit işleyen komutlar yok. Ama bu sorunu struct, union yapısı ile çözebiliriz.

union{
unsigned char structbyte;
struct{
    unsigned char bit_1 : 1;
    unsigned char bit_2 : 1;
    unsigned char bit_3 : 1;
    unsigned char bit_4 : 1;
    unsigned char bit_5 : 1;
    unsigned char bit_6 : 1;
    unsigned char bit_7 : 1;
    unsigned char bit_8 : 1;
  };
} test;

bu şekilde bir tanımlama ile bit kullanımı mümkün.
test.bit_1 = 0 , test.bit_2 = 1; 
ya da test.structbyte = 78;

IAR derleyicisi bu şekildeki bit operasyonları için  işlemcinin komut setindeki bit operatörlerini kullanıyor. Belki derleyiciye göre değişiyordur.

muhendisbey

hocam bunalmış hocamızın dediğini anladım ama sizin dediğiniz yöntemden tek bir satırı anlayamadım açıklayabilir misiniz?
Bir de bunalmış hocam işlemcide bit düzeyinde işlem varsa yada yoksa diye birşey belirtmiş. Böyle bir işlemci var mı ki bit düzeyinde işlem yapmasın?
Bu soruyu sorma amacım birçok kişi C de yazarken yazılımın çok şiştiğinden bahsetmiş forumlarda, bit düzeyinde yapılan işlemin hem düşük güç kontrolü açısından hem de yazılım boyutu açısından ekonomikliği bulunmakta. C kullanırken buna nasıl dikkat edebilirim maksadındaydı.

Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

Veli B.

ARM ailesinde bazı işlemciler "bit banding " olarak geçen bir manipulasyon desteği sunuyor(ör Cortex-M3/-M4) . Bit Banding piclerde ki BSF BCF gibi.
Örneğin ben Cortex M0 kullanıyorum ve Bit Banding desteklemiyor. Bu durumda Klein Üstadımın bahsettiği gibi aynı alanı gösteren bir union ve hedefi gösteren bir Struct ile alias oluşturup hedefin istediğimiz yerine ateş edebiliyoruz.

Üst seviye Cortexler için "Bit Banding" olarak aratırsanız detay bilgi bir haylice var. ARM da bununla ilgili bir makale de vardı sanırım.

z

#5
Alıntı yapılan: muhendisbey - 01 Kasım 2011, 23:43:49
hocam bunalmış hocamızın dediğini anladım ama sizin dediğiniz yöntemden tek bir satırı anlayamadım açıklayabilir misiniz?
Bir de bunalmış hocam işlemcide bit düzeyinde işlem varsa yada yoksa diye birşey belirtmiş. Böyle bir işlemci var mı ki bit düzeyinde işlem yapmasın?
Bu soruyu sorma amacım birçok kişi C de yazarken yazılımın çok şiştiğinden bahsetmiş forumlarda, bit düzeyinde yapılan işlemin hem düşük güç kontrolü açısından hem de yazılım boyutu açısından ekonomikliği bulunmakta. C kullanırken buna nasıl dikkat edebilirim maksadındaydı.

Elbette yazılımla bit manuplasyonuna gerek duyan daha açık ifade ile donanımsal olarak bit işleme komutları olmayan işlemciler var.
Mesela, bit bazında işlem yapan makine komutları, PIC ve 8051 de var fakat, 8086 ve DSP lerde yok. CM3 işlemcilerin register üzerinde bit maniplasyonu yapan komutları var.
---------------------------
Mesela 8 bitlik bir portun 0. bitine 1 yüklemek için bit erişim komutu olmayan bir işlemci kullanıyorsan

porta daha önceden yüklenmiş olan veriyi tespit edip (bu portu okumak olabilir) ardından sonucu 0x01 ile OR layıp gerisin geriye porta yazabilirsin.

Aynı şekilde 0. biti o yapmak istiyorsan portu okuyup 0xFE ile AND leyip gerisin geriye porta yazabilirsin.

Eğer işlemcinin zaten bitmanuplasyon komutları varsa ya da erişmek istediğin alan Bit Band özelliğinde ise o zaman yukarıdaki uzun yönteme gerek kalmaz.

Derleyicinin hangisini tercih edeceğini hatta bu tercihi kendisi yapabilirmi yoksa biz mi zorlayacağız konusunu bilmiyorum. En kısa zamanda bu konuyu araştırıp örnekle açıklamak istiyorum.

Çok iyi düşünülerek yazılmış ASM programların çok iyi düşünülerek C ile yazılmış programlardan daha kısa ve hızlı olacağı konusunda sanırım hemfikiriz. Ancak ARM dünyasına geçtiğimizde bu işlemciyi genellikle büyük projelerde kullanmak isteriz.

Bu durumda amaç, kısa kod yazmak yerine projeyi gerçeklemek olmalıdır. Özellikle ve özellikle, hızlı koşmasının çok da şart olmadığı rutinleri C ile kodlama fikrini benimsemekte fayda var.

Çok optimize sonuç verecek ASM yazım, fazlasıyla zahmetli ve mevcut seçenekleri kimi zaman tek tek yazıp elemeyi gerektirdiğinden, mecbur kalmadıkça tercih edilmemelidir.



Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

#6
Bit Banding

CM4 işlemcimizde çevrebirimlerinin registerleri ile SRAM alanı üzerinde bit işlemleri yapılabilmekte. (Ancak bu işlemlerin doğrudan işlemci ile yapılması gerekiyor. DMA ile yapamıyoruz.) Word olarak erişilen alanı ister word data yükleyerek değiştirebiliyoruz istersek bit banding yaparak. (Word alias konusuna bir ara değinelim, unutturmayın)

Hedef alanda bir biti değiştirmek için Bu bitin bit band alanındaki adresini hesaplamamız gerekiyor.
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)

Örneğin RAM'ın ilk adresi olan 0x20000000 da 2.biti (0 dahil sayarsak 0,1,2) 1 yapalım.

Bit_Band_Base = 0x22000000,  Byte_Offset = 0x0000 * 0x32,  Bit_Number = 2

Bit_Word_Addr=0x22000000 + 0*32 + 2*4 =0x22000008

Bunu test etmek için aşağıdaki programı Keilde deneyin. A ve P değişkenlerini Watch1 de gözleyin.

#include "STM32F4xx.h"
unsigned short A;

void SystemInit()
{
}

unsigned short* Bit_Adr(int Wadr,char BitNum)
{
      return((unsigned short*)(0x22000000 + ((Wadr - 0x20000000)<<5) + (BitNum<<2)));
}

int main()
{
unsigned short* P;
     A=0;
     P=Bit_Adr((int)&A,2);
    *P=1;
   
}

Yukarıdaki program A=0 ataması ardından Anın 2.bitini set etmektedir.  Basit bir bit manuplasyonu için fazlaca uzun bir işlem mi dersiniz? 
Devam edeceğiz.
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

z

#7
Memoryde  MyTarget adındaki 16 bitlik adresde bit manuplasyonu yapmak için;

P pointerimize  P=((unsigned short*)(0x22000000 + ((MyTarget - 0x20000000)<<5))); yükleyelim.   P bizim MyTarget adresinde 0. biti referans gösterir.  n.pozisyondaki biti set etmek istersek word pointera 2*n eklemek ( adresi 4*n byte ilerletmek) yeterli olacaktır.   

#include "STM32F4xx.h" unsigned short A;

void SystemInit()
{
}   

unsigned short* Bit_Adr(int Wadr,char BitNum)
{
    return((unsigned short*)(0x22000000 + ((Wadr - 0x20000000)<<5) + (BitNum<<2)));
}   


int main()
{
unsigned short* P; 

     A=0;
     P=Bit_Adr((int)&A,0);


    *(P+0x000)=1;      // 0. Biti set et
    *(P+0x002)=1;      // 1. Biti set et 
    *(P+0x004)=1;      // 2. Biti set et 
    *(P+0x006)=1;      // 3. Biti set et 
    *(P+0x008)=1;      // 4. Biti set et 
    *(P+0x00A)=1;      // 5. Biti set et 
    *(P+0x00C)=1;      // 6. Biti set et 
    *(P+0x00E)=1;      // 7. Biti set et 
    *(P+0x010)=1;      // 8. Biti set et 
    *(P+0x012)=1;      // 9. Biti set et 
    *(P+0x014)=1;      //10. Biti set et 
    *(P+0x016)=1;      //11. Biti set et 
    *(P+0x018)=1;      //12. Biti set et 
    *(P+0x01A)=1;      //13. Biti set et 
    *(P+0x01C)=1;      //14. Biti set et 
    *(P+0x01E)=1;      //15. Biti set et 
    *(P+0x020)=1;      //16. Biti set et   (!!! MyTarget'i takip eden adrese duhul ettik !!!)
    *(P+0x022)=1;      //17. Biti set et 
    *(P+0x024)=1;      //18. Biti set et 
    *(P+0x026)=1;      //19. Biti set et 
    *(P+0x028)=1;      //20. Biti set et 
    *(P+0x02A)=1;      //21. Biti set et 
    *(P+0x02C)=1;      //22. Biti set et 
    *(P+0x02E)=1;      //23. Biti set et 
    *(P+0x030)=1;      //24. Biti set et 
// .....
// .....     
}   

Şayet her bir bit değişkenin adresini sabitlersek bu durumda pointer üzerinde toplama işlemi yapmaya gerek kalmaz ve

Bit değişkenlerimiz A0,A1,A2,A3... B0,B1,B2,B3... gibi isimler alabilir.

Bunların herbirisinin adresi belli olduğundan;

B1=A1;  B7=A6 & B3; vs vs işlemler, klasik yazılımla yapılacak bit manüplasyon işlemlerine kıyasla  son derece hızlı yapılacaktır.

(Yukarıdaki örnek programı aynen kullansanız dahi Keil çok optimize kodlar üretmektedir)
Bana e^st de diyebilirsiniz.   www.cncdesigner.com

taneryilmaz

merhab abunalmış hocam bu konuya ben de dahil olmak istiyorum . burada siz ben den bir program isteseniz ben de asm sini yazsam   sonra sizde  C ye çevirseniz olur mu ?

z

Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhendisbey

C de alt program nasıl yazılır? ve bu alt programlar ana programa nasıl dahil edilir?
bunun için 200ms lik gecikmeyi ana program içinde kullanmaya örnek verebilir misiniz?

Bir diğeri tablo alt program, bunu nasıl C de yaparız?
Bunun için de seven segment display 0-9 sayıcı örneği verebilir misiniz?
Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

z

#11
Alt program dediginiz sey C deki fonksiyolar.

Ornegin CALL TOPLA gibi bir asm satirini C'de

TOPLA(); diye kullaniriz.

-------------------

200ms lik gecikme rutinini eger asm de zaman kaybeden kodlari calistirarak gercekliyorsaniz C de de bunu

for(i=0;i<10000;i++); gibi i nin volatile ekiyle tanimlandigi kodla yada benzeri ile gerceklestiririz.

Isin icine CPU clk frekansini da dahil edip 10000 gibi bir sayiyi CPU CLK degerine gore modifiye eden fonksiyonu  yazmak da mumkundur.

Eger 200ms yi timer ile yaptirdiysaniz C de mantik ayni.

--------------------

Tablolari C de array olarak tanimlariz. Eger amaciniz bir tabloya fonksyonlarin adreslerini yerlestirmek ve bir indise gore bu fonksyonlari cagirmak ise
fonksiyon adreslerini array icine yazmaniz yeterli. Bu konuda ornegi bir baska mesajimda verecegim.


Bana e^st de diyebilirsiniz.   www.cncdesigner.com

muhendisbey

Hocam UART ile iletişim kurmak istesek, buna uygun porta göre bağlantımız yapılmış olsun. Mesela iletmek istediğim bir metin olsun "bunalmis" mesela bunu nasıl göndeririz? Sıfırdan kütüphane oluşturmak mı gerekir, yoksa bunu sağlayacak yapı Keil içerisinde var mı?
Bunu şu açıdan da soruyorum bluetooth üzerinden porta çıkış vermeye uğraşıyorum.
Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

muhendisbey

Bir de yazmayı unutmuşum yukarıda diğer mesajda yanıtlayacağınız sorumu cevaplayabilirseniz memnun olurum.
Zulmü alkışlayamam, zalimi asla sevemem; Gelenin keyfi için geçmişe kalkıp sövemem.

yamak

Hocam şimdi ben C de program yazarken bir değişken tanımlıyorum bu değişkenlerle işlem yaparken aslında arm işlemcimizin r0-r12 registerları ile işlem yapıyoruz değil mi?Eğer durum böyle ise değişken tanımladığımız bu r0-r2 registerlarının arasından hangisi ile işlem yapılacağı nasıl belirleniyo.Bir de bir çevre-birimine ait bir register a bir değer atayacağımız zaman ilk olarak r0-r12 registerlarına kaydedilip daha sonra mı o registera kaydoluyo yoksa direkt olarak mı kaydediliyo.