Notice: Undefined variable: ub in /home/ictrclub/blog_ictr/wp-content/plugins/advanced-page-visit-counter/public/class-advanced-page-visit-counter-public.php on line 148

Notice: Undefined variable: ub in /home/ictrclub/blog_ictr/wp-content/plugins/advanced-page-visit-counter/public/class-advanced-page-visit-counter-public.php on line 160
ARM Cortex-M MCU uzerinde Atomik Islemler - Blog

ARM Cortex-M MCU uzerinde Atomik Islemler

Ziyaretci:4843

Atomik Islemler

Bugun ki yazimizda ARM islemcilerde bulunan atomik islemler yani interrupt veya baska bir kaynaktan (multi-thread, multi-processor) kesilemeyen/etkilenmeyen islerin nasil yapilabilecegine bakacagiz.

Atomik Islem Nedir ?

Basitce atomik islem demek herhangi bir sekilde kesilmeden devam edebilen ve/veya islemin etkilenmeden yuruyebilecegi tarzda herhangi bir dis kaynaga ihtiyac duymaksizin yapilan islemlere denir.

ARM Mimarilerinde Atomik Degiskenlere Giris

Ornegin ARM mimarisinde tek islemcili bir sayiya asagida ki gibi bir atama yapalim.

https://godbolt.org/z/jdPfrW9e6

Yukarida paylastigim linkte gorulebilecegi gibi x = 5 operasyonu icin derleyici soyle bir kod uretmekte.

ARM Assembly konusuna hakim olmayanlar icin basitce r3 registerina 5 yazip, sonrasinda bu degeri tek bir instruction (str: store) degiskenin icerisine yazmakta yani 1 cekirdekli bir MCU da bu islem sirasinda int. alinamayacagi icin (inst. yurutme sirasinda islemci interrupt alamaz…) bu islem atomiktir diyebiliriz. Peki birden cok islemciniz varsa evet artik yavasca atomik degiskenlerin farkliligina yavas yavas yaklasmaya basladik 🙂

Bugune kadar bir cok islemci mimarisi bu handikapi cozebilmek adina assembly komutlarina ekleme yapmistir x86 mimarisinde LOCK komutu ile isleminizi atomik hale getirebilirsiniz. Nitekim x86 CISC mimari bir islemci oldugu icin tek instruction da istediginiz degiskeni diger corelardan izole ederek okuyup, degistirebilirsiniz.

Fakat gelelim ARM mimarisine, ARM mimarisi RISC tabanli yani komplike olmayan bir komut setine sahip oldugu icin mimariyi tasarlayanlar dogrudan hafiza uzerinde islem yapmamiza izin vermemektedir. Yani,

pseudo-assembly bir kod ile anlatacak olursak

Yani bir degiskeni arttirabilmek adina once degiskeni islemci icindeki registera (yazmac) cekip sonrasinda registerda arttirip sonra tekrar yerine koyabiliriz. Bu surecte tek yapmak istedigimiz x degiskenini 1 arttirmak, peki araya interrupt girerse o zaman kodumuz neye donusecek ona bakalim.

Hayalimiz x degiskenini 1 arttirmak idi fakat gelen interrupttada 1 arttirildi fakat biz ezerek tekrardan 6 yaptik yani bu akista hayalimiz islem sonunda 7 gormek iken 6 ile basbasa kaldik. Peki cozumlerimiz ne olabilir ?

1- x’i arttirirken tum interruptlari kapatmak ?

2- x’e bizden baskasi erismis ise tekrar okuyup arttirmak ?

Interruptlari Devre Disi Birakmak

Bahsi gecen akista interruptlari devre disi birakip x degiskenini arttirmak tek cekirdekli bir islemcide kesin bir cozum olacaktir. Bu islemi yapabilmek adina 2 adet instruction (komut) daha eklersek asagida ki gibi degiskenimizin atomik olmasini garanti edebiliriz. Peki devamli surette tum akisimizda bu degiskeni takip edip eristigimiz her yere interrupt koymaya calismaya deger mi ? Ya da multicore (cok islemcili) bir ortamda calisiyorsaniz ne yapilacak, siz asenkron oldugunuz icin diger islemciyi bu erisim sirasinda durdurmaya mi calisacaksiniz ? Tabii ki her sey tercih meselesi lakin daha kolayini bir sonraki alt basligimizda inceleyecegiz.

Erisim Kontrollu Atomik Degisken Olusturma

ARM icin linked access komutlari bulunmaktadir. Bu komutlar en yalin haliyle LDREX, STREX, CLREX komutlaridir.

LDREX: LOAD exclusive
STREX: STORE exclusive
CLREX: Clear exclusives

Bu komutlarin ozelligi ise su sekildedir ve birlikte kullanilirlar.

Burada ki store komutumuz STREX degisik ozellikte bir komuttur, diger store komutlarinin aksine yuklemeyi dener peki neye gore dener ?

Erisim Kontrolculeri

Islemci paketimizin icerisinde local ve global access (erisim) monitorleri bulunur. Bu monitorlerin yaptigi temel yukarida ki kodda bulunan erisimleri kontrol etmeye yarar. Yani asagida ki gibi calisir.

Global ve local access monitorleri sadece cok cekirdekli islemcilerde bulunurken, tek cekirdekli islemcilerde yalnizca local access monitoru bulunur.

Gercek Bir Erisime Hazir Olun!!!

1- LDREX Rx, [Rn] : Rn adresini belirli bir range (adres araligi) icerisinde monitorde exclusive olarak isaretle… (Range tamamen implemantasyona ozeldir yani MCU ureticisi belirler)
2- STREX Rd, Rx, [Rn]: isaretlenen bolgenin exclusive ozelligini bozan olmadiysa Rx i yukle. Islemin sonucunu Rd registerina yukle

Peki yukleme islemi basarili olup olmamasi nereden anlasilir ?

Ornek olarak Cortex M4 mimarini ele alalim. Bu mimaride genellikle tek cekirdekli islemci setleri kullanilmaktadir.

https://godbolt.org/z/s1xxfT8sq

Cortex M mimarisine ozel olarak Cortex A dan farkli olarak interrupt durumunda herhangi bir aksiyon alinmadan CLREX komutu calistirilir bu komut local monitorde ki tum exclusive erisimleri “Open Access” olarak isaretler.  Yeni yukarida ki dongumuzde en basa donup tekrar bir okuma yapip islemi yeniden yapmak durumunda kaliriz.

Cok cekirdekli islemcilerde ise monitor sayisi artar ve corelar arasi monitor olan global access monitoru de devreye girer. Eger baska bir cekirdek bizim adresimize erisim saglamissa tekrardan ayni donguye gireriz.

PlantUML Syntax:</p>
<p>Thread1 –[#black]> Monitor : Ayni adrese erisim istegi, monitorde adres mevcut mu ?<br />
Monitor –[#red]>Memory : Adrese erisim<br />
Interrupt –[#blue]> Monitor : Ayni adrese erisim istegi, monitorde adres mevcut mu ?<br />
Monitor –[#red]>Memory : Adrese erisim</p>
<p>

Artik gelelim C ile bu isleri yapmaya yani anlattigimiz kismi gerceklestirmeye…

C11 Standardi ile Gelen _Atomic

C11 standardi ile gelen _Atomic anahtar kelimesi, derleyicimizin bizlere yaptigi yegane guzelliklerden biri 🙂

Yukarida anlattigimiz tum bu donguyu asagida ki gibi kurabiliriz.

Assembly Ciktisi

Assembly ciktisinda goruldugu uzere func isimli tasklarda kosabilen fonksiyonumuz interrupt degiskeni degistirdigi zaman tekrardan degiskeni okuyarak azaltmaya calisiyor.

Diyelim ki bir interrupttan uretilen sayilar olsun ve 2 farkli threadde kosan kodumuz bunu karsilikli olarak tuketmeye calissin.

Assembly Ciktisi

Yukarida ki yapida interrupt 1 arttirilan bir degisken yardimiyla 2 thread birbirlerinin ayagina dolanmadan istenilen miktarda calisacaktir. Yani 10 kez interrupt aldiysak, 2 threadden cagrilan yerler toplamda sadece 10 kez calismasini garanti altina almis olduk…

https://blog.ictr.club/stack-unwind-cortex-m/

https://community.arm.com/support-forums/f/architectures-and-processors-forum/10361/ldrex-strex-on-the-m3-m4-m7

https://developer.arm.com/documentation/ddi0403/latest

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir