Windows.  Viruslar.  Noutbuklar.  Internet.  Idora.  Utilitalar.  Haydovchilar

GBA ASM - 2-kun: ARM assembler haqida ba'zi ma'lumotlar - WASM.RU arxivi

ARM - GBA protsessorini ishlab chiqaruvchi kompaniya. ARM protsessorlari RISC protsessorlari (INTEL protsessorlaridan farqli o'laroq). RISC qisqartmasi Reduced Instruction Set Computers (CISC - Kompleks...) degan ma'noni anglatadi. Garchi bu protsessorlarda ko'p ko'rsatmalar bo'lmasa ham (bu yaxshi), ARM ko'rsatmalari(va, ehtimol, boshqa RISC protsessorlari, men bilmayman) juda ko'p turli maqsadlarda va RISC protsessorlarini ular kabi kuchli qiladigan kombinatsiyalar.

Registrlar

Boshqa ARM protsessorlari haqida bilmayman, lekin GBA-da ishlatiladigan registrda 16 ta registr mavjud va Intel protsessorlaridan (va boshqalardan) farqli o'laroq, barcha registrlardan xavfsiz foydalanish mumkin (odatda). Registrlar quyidagicha:

r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15

Voy-buy! Juda ko'p! Men tartibda tushuntiraman.

ro: xohlaganingizni qiling!

r2 dan r12 gacha: bir xil

r13: Ba'zi ARM tizimlarida r13 stek ko'rsatkichidir (INTEL protsessorlarida SP). Men r13 GBAda bir xil rol o'ynashiga ishonchim komil emas, men faqat stek bilan ishlashda ehtiyot bo'lishingizni ogohlantirishim mumkin.

r14: chaqirilgan protseduralar uchun qaytish manzilini o'z ichiga oladi. Agar siz ulardan foydalanmasangiz, unda siz u bilan xohlagan narsani qilishingiz mumkin.

r15: Dastur hisoblagichi va bayroqlar, IP bilan bir xil (Intel'dagi Instruction Pointer). Uning Intel IP registridan farqi shundaki, siz boshqa registrlar kabi unga bepul kirishingiz mumkin, lekin uni o'zgartirish boshqaruvni kodning boshqa bo'limiga o'tkazishga olib kelishini va bayroqlarni o'zgartirishini unutmang.

Keling, bir oz matematika bilan shug'ullanamiz ... 16 minus 3 (odatda) bizga 13 ta registrni beradi. Bu ajoyib emasmi? Tinchlaning.

Endi siz registrlar nima ekanligini qiziqtirgan bo'lishingiz mumkin. Registrlar - bu protsessor tarkibiga kiruvchi va haqiqiy manzilga ega bo'lmagan, faqat nomlari bilan ma'lum bo'lgan maxsus xotira sohalari. Registrlar 32 bitli. Har qanday assembly tilida deyarli hamma narsa registrlardan foydalanadi, shuning uchun siz ularni qarindoshlaringiz kabi bilishingiz kerak.

ARM assembler ko'rsatmalari

Birinchidan, shuni aytmoqchimanki, mening fikrimcha, ARM assemblerni kim o'ylab topsa, u dahodir.

Ikkinchidan, men yaxshi do'stim CMP bilan tanishtirmoqchiman. Unga salom ayting, ehtimol, u ham sizning do'stingizga aylanadi. CMP solishtirish (taqqoslash) degan ma'noni anglatadi. Ushbu ko'rsatma registr va raqamni, ro'yxatga olish va ro'yxatdan o'tishni yoki registr va xotira joylashuvini solishtirishi mumkin. Keyin, taqqoslashdan so'ng, CMP taqqoslash natijasini bildiradigan holat bayroqlarini o'rnatadi. Esingizda bo'lsa, r15 ro'yxatida bayroqlar mavjud. Ular taqqoslash natijasi haqida xabar berishadi. CMP yo'riqnomasi ushbu bayroqlarning qiymatini belgilash uchun maxsus ishlab chiqilgan va boshqa hech narsa emas.

Bayroqlar quyidagi holatlarni o'z ichiga olishi mumkin:

    EQ Teng / Teng

    NE Teng emas

    VS oVerflow to'plami

    VC oVerflow Clear

    SAlom Oliy / Yuqori

    LS Past yoki bir xil / Pastda yoki bir xil

    PL PLus / Plus

    MI MINus / Minus

    CS tashish to'plami

    CC Carry Clear

    GE Kattaroq yoki Teng / Kattaroq yoki teng

    GT kattaroq / ko'proq

    LE Kamroq yoki Teng / Kamroq yoki teng

    LT dan kam / kamroq

    Z - nol / nol

    NZ nol emas / nol emas

Bu holatlar ARM assemblerida juda muhim rol o'ynaydi.

QAYD: bayroqlar faqat shartlarni saqlaydi (Teng, Kamroq va hokazo). Ular endi muhim emas.

Shart qo‘shimchalari

Siz allaqachon B (filial) ko'rsatmasini ko'rgansiz. B ko'rsatmasi shartsiz o'tish deb ataladigan narsani bajaradi (masalan, Basic-dagi GoTo yoki INTEL-dagi JMP). Ammo u qo'shimchaga ega bo'lishi mumkin (yuqorida sanab o'tilganlardan biri), keyin u bayroqlarning holati unga mos kelishini tekshiradi. Agar yo'q bo'lsa, unda sakrash buyrug'i oddiygina bajarilmaydi. Shunday qilib, agar siz r0 registrining r4 registriga teng ekanligini tekshirib, label34 deb nomlangan yorliqga o'tmoqchi bo'lsangiz, quyidagi kodni yozishingiz kerak bo'ladi:

    CMP r0, r4; Assemblerdagi izohlar nuqta-verguldan keyin keladi (;)

    BEQ label34; B - sakrash ko'rsatmasi va EQ - qo'shimcha ma'no

    ; "Agar teng bo'lsa"

QAYD: Goldroad Assembler’da yorliqlarga (() qo‘shilishi shart emas va satrda yorliq nomidan boshqa hech narsa bo‘lmasligi kerak.

QAYD II: CMP va BEQ ni yozing bosh harflar bilan shart emas, bu faqat siz uchun aniqroq qilish uchun.

Endi siz bayroqlarning holatiga qarab qanday o'tishni bilasiz, lekin siz bilmagan narsa shundaki, siz bayroqlarning holatiga qarab hamma narsani qilishingiz mumkin, shunchaki istalgan ko'rsatmaga kerakli qo'shimchani qo'shing!

Bundan tashqari, bayroqlarning holatini o'rnatish uchun CMP dan foydalanish shart emas. Agar siz, masalan, bayroqlarni o'rnatish uchun SUB (Ajratish) buyrug'ini xohlasangiz, ko'rsatmalarga "S" qo'shimchasini qo'shing ("Bayroqlarni o'rnatish" degan ma'noni anglatadi). Agar siz qo'shimcha CMP ko'rsatmasi bilan bayroqlar holatini o'rnatishni xohlamasangiz, bu foydalidir, shuning uchun siz buni qilishingiz va natija nolga teng bo'lsa, sakrashingiz mumkin:

    SUBS r0,r1,0x0FF; Bajarish natijasiga ko'ra bayroqlarni o'rnatadi

    ; ko'rsatmalar

    ldrZ r0,=0x0FFFF ; r0 registrini 0x0FFFF bilan faqat davlat bo'lsa yuklaydi

    bayroqlar nolga teng.

Ko‘rib chiqish

Bugun biz (bir oz ko'proq) registrlar haqida bilib oldik. Shuningdek, biz bayroqlarning holatiga qarab bajarilishi (yoki bajarilmasligi) mumkin bo'lgan ARM ko'rsatmalarining moslashuvchanligi haqida bilib oldik. Bugun biz ko'p narsani o'rgandik.

Ertaga biz GBA ekranida rasmni ko'rsatish uchun bugun olingan ARM assembler bilimlaridan foydalanamiz.

Mumkin bo'lmagan narsa faqat iloji bo'lmaguncha shunday bo'ladi / Jan-Lyuk Pikar, kapitan. , USS Enterprise/. Mayk H, trans. Aquila

Agar siz Raspbian taqsimotidan foydalansangiz operatsion tizim Raspberry Pi uchun sizga ikkita yordamchi dastur kerak bo'ladi, xususan (assembler tilining manba kodini ikkilik kodga o'zgartiruvchi assembler) va ld (natijani ishlab chiqaruvchi bog'lovchi). bajariladigan fayl). Ikkala yordamchi dastur ham paketda dasturiy ta'minot binutils , shuning uchun ular allaqachon tizimingizda mavjud bo'lishi mumkin. Albatta, sizga yaxshi matn muharriri ham kerak bo'ladi; Men har doim dastur ishlab chiqish uchun Vim-dan foydalanishni tavsiya qilaman, lekin u yuqori kirish to'sig'iga ega, shuning uchun Nano yoki boshqa matn muharriri grafik interfeys ham ajoyib ishlaydi.

Boshlashga tayyormisiz? Quyidagi koddan nusxa oling va uni myfirst.s fayliga saqlang:

Global _start _start: mov r7, #4 mov r0, #1 ldr r1, =string mov r2, #stringlen swi 0 mov r7, #1 swi 0 .data string: .ascii "Ciao!\n" stringlen =. -string

Ushbu dastur shunchaki "Ciao!" ekranga o'ting va agar siz x86 protsessorlari bilan ishlash uchun assembly tilidan foydalanish bo'yicha maqolalarni o'qigan bo'lsangiz, foydalanilgan ko'rsatmalarning ba'zilari sizga tanish bo'lishi mumkin. Ammo shunga qaramay, x86 va ARM arxitekturalarining ko'rsatmalari o'rtasida juda ko'p farqlar mavjud, ularni manba kodining sintaksisida ham aytish mumkin, shuning uchun biz uni batafsil tahlil qilamiz.

Ammo bundan oldin shuni ta'kidlash kerakki, berilgan kodni yig'ish va natijada olingan ob'ekt faylini bajariladigan faylga bog'lash uchun siz quyidagi buyruqdan foydalanishingiz kerak:

As -o myfirst.o myfirst.s && ld -o myfirst myfirst.o

Endi siz ./myfirst buyrug'i yordamida yaratilgan dasturni ishga tushirishingiz mumkin. Ehtimol, bajariladigan fayl juda ko'p ekanligini payqadingiz oddiy o'lcham taxminan 900 bayt - agar siz C dasturlash tilidan va puts() funksiyasidan foydalansangiz, ikkilik fayl hajmi taxminan besh baravar katta bo'lar edi!

Raspberry Pi uchun o'z operatsion tizimingizni yaratish

Agar siz x86 assembly tilini dasturlash bo'yicha ushbu turkumdagi oldingi maqolalarni o'qigan bo'lsangiz, ehtimol siz o'z operatsion tizimingizni birinchi marta ishga tushirganingizni eslaysiz, u holda ekranda hech qanday xatoliksiz xabar paydo bo'ladi. Linux yordami yoki boshqa operatsion tizim. Shundan so'ng biz uni oddiy interfeys qo'shish orqali yaxshiladik buyruq qatori va diskdan dasturlarni yuklash va ishga tushirish mexanizmi, kelajakka poydevor qo'yadi. Bu juda qiziq, lekin unchalik qiyin bo'lmagan ish edi, asosan tashqi yordam tufayli BIOS proshivka- u ekran, klaviatura va floppi diskni o'quvchiga kirish uchun soddalashtirilgan interfeysni taqdim etdi.

Raspberry Pi bo'lsa, endi sizning ixtiyoringizda bo'lmaydi foydali funktsiyalar BIOS, shuning uchun siz qurilma drayverlarini o'zingiz ishlab chiqishingiz kerak bo'ladi, bu o'z-o'zidan ekranda chizish va o'z dasturlarini bajarish mexanizmini amalga oshirish bilan solishtirganda qiyin va qiziq emas. Shu bilan birga, Internetda batafsil tavsiflangan bir nechta qo'llanmalar mavjud dastlabki bosqichlar Raspberry Pi yuklash jarayoni, GPIO pinlariga kirish mexanizmining xususiyatlari va boshqalar.

Bunday hujjatlardan biri bu Kembrij universitetining Baking Pi (www.cl.cam.ac.uk/projects/raspberrypi/tutorials/os/index.html) nomli hujjatidir. Bu, asosan, LEDlarni yoqish, ekrandagi piksellarga kirish, klaviaturadan kiritishni qabul qilish va hokazolar uchun montaj tili bilan ishlash usullarini tavsiflovchi qo'llanmalar to'plamidir. O'qiyotganingizda, siz ko'p narsalarni bilib olasiz apparat Raspberry Pi va qo'llanmalar ushbu bitta taxtali kompyuterlarning asl modellari uchun yozilgan, shuning uchun ular A+, B+ va Pi 2 kabi modellarga tegishli bo'lishiga kafolat yo'q.

Agar siz C dasturlash tilini afzal ko'rsangiz, http://tinyurl.com/qa2s9bg manzilida joylashgan va o'zaro kompilyatorni o'rnatish va oddiy operatsion tizimni yaratish jarayoni tavsifini o'z ichiga olgan Valvers resursidagi hujjatga murojaat qilishingiz kerak. yadrosi va foydali OSDev resursining Wiki bo'limida joylashgan, Raspberry Pi da asosiy OS yadrosini yaratish va ishga tushirish haqida ma'lumot olish uchun http://wiki.osdev.org/Raspberry_Pi_Bare_Bones ga qarang.

Yuqorida aytib o'tilganidek, eng katta muammo Ushbu holatda turli Raspberry Pi apparat qurilmalari uchun drayverlarni ishlab chiqish zarurati: USB boshqaruvchisi, SD karta uyasi va boshqalar. Axir, hatto eslatib o'tilgan qurilmalar uchun kod ham o'n minglab qatorlarni olishi mumkin. Agar siz hali ham Raspberry Pi uchun o'zingizning to'liq xususiyatli operatsion tizimingizni ishlab chiqmoqchi bo'lsangiz, www.osdev.org saytidagi forumlarga tashrif buyurib, kimdir allaqachon ushbu qurilmalar uchun drayverlarni ishlab chiqqanligini so'rang va iloji bo'lsa, ularni yadroingiz uchun moslashtiring. operatsion tizim, bu sizning vaqtingizni katta miqdorda tejaydi.

Hammasi qanday ishlaydi

Kodning birinchi ikki qatori protsessor ko'rsatmalari emas, balki assembler va bog'lovchi ko'rsatmalaridir. Har bir dasturda _start deb nomlangan aniq belgilangan kirish nuqtasi bo'lishi kerak va bizning holatlarimizda u kodning eng boshida edi. Shunday qilib, biz bog'lovchiga kodni bajarish birinchi ko'rsatma bilan boshlanishi kerakligini va hech qanday qo'shimcha harakatlar talab qilinmasligini ma'lum qilamiz.

Yordamida quyidagi ko'rsatmalar r7 registriga 4 raqamini qo'yamiz. (Agar siz ilgari assembler tili bilan ishlamagan bo'lsangiz, shuni bilishingiz kerakki, registr to'g'ridan-to'g'ri markaziy protsessorda joylashgan xotira joyidir. Ko'pgina zamonaviy tillarda markaziy ishlov berish birliklari millionlab yoki milliardlab hujayralarga nisbatan kam sonli registrlarni amalga oshirdi tasodifiy kirish xotirasi, lekin registrlar ajralmas hisoblanadi, chunki ular tezroq ishlaydi.) ARM arxitektura chiplari ishlab chiquvchilarga ko'p sonli registrlar beradi. umumiy maqsad: Dizayner r0 dan r15 gacha bo'lgan 16 tagacha registrlardan foydalanishi mumkin va bu registrlar x86 arxitekturasida bo'lgani kabi hech qanday tarixiy cheklovlar bilan bog'lanmaydi, bunda registrlarning ba'zilari ma'lum vaqtlarda ma'lum maqsadlar uchun ishlatilishi mumkin.

Shunday qilib, mov ko'rsatmasi xuddi shu nomdagi x86 ko'rsatmasiga juda o'xshash bo'lsa-da, siz hali ham 4 raqami yonidagi xesh belgisiga e'tibor berishingiz kerak, bu keyingi narsa xotira manzili emas, balki butun son qiymati ekanligini ko'rsatadi. Bunday holda, biz satrimizni chop etish uchun Linux yadrosi yozish tizimi chaqiruvidan foydalanmoqchimiz; Tizim qo'ng'iroqlaridan foydalanish uchun yadrodan o'z ishini so'rashdan oldin registrlarni kerakli qiymatlar bilan to'ldirishingiz kerak. Tizim qo'ng'irog'i raqami r7 reestriga joylashtirilishi kerak, 4 raqami esa yozish tizimi qo'ng'iroq raqamidir.

Quyidagi mov ko'rsatmasi bilan "Ciao!" qatori yoziladigan fayl tutqichini, ya'ni standart chiqish oqimi tutqichini r0 registriga joylashtiramiz. Chunki bu holda oqim ishlatiladi standart chiqish, uning standart deskriptori registrga joylashtiriladi, ya'ni 1. Keyinchalik, biz chiqarmoqchi bo'lgan satrning manzilini ldr ko'rsatmasi ("registrga yuklash" ko'rsatmasi; keyingi narsa manzil emas, balki yorliq ekanligini ko'rsatadigan tenglik belgisiga e'tibor bering) yordamida r1 registriga joylashtirishimiz kerak. Kod oxirida, ya'ni ma'lumotlar bo'limida biz ushbu qatorni ASCII belgilar ketma-ketligi ko'rinishida e'lon qilamiz. "Yozish" tizim chaqiruvidan muvaffaqiyatli foydalanish uchun biz operatsion tizim yadrosiga chiqish satrining uzunligini ham aytishimiz kerak, shuning uchun biz stringlen qiymatini r2 registriga qo'yamiz. (Stringning qiymati boshlang'ich manzildan satrning oxirgi manzilini ayirish yo'li bilan hisoblanadi.)

Yoniq bu daqiqa biz barcha registrlarni kerakli ma'lumotlar bilan to'ldirdik va nazoratni o'tkazishga tayyormiz Linux yadrosi. Buning uchun biz swi ko'rsatmasidan foydalanamiz, uning nomi "dasturiy ta'minot uzilishi" degan ma'noni anglatadi, u OS yadro maydoniga o'tadi (x86 arxitekturasidagi maqolalardagi int yo'riqnomasi bilan deyarli bir xil). OT yadrosi r7 registrining mazmunini tekshiradi, undagi 4 butun qiymatini topadi va shunday xulosaga keladi: "Demak, chaqiruvchi dastur satrni chop qilmoqchi." Shundan so'ng, u boshqa registrlarning mazmunini tekshiradi, satrni chop etadi va dasturimizga boshqaruvni qaytaradi.

Shunday qilib, biz ekranda "Ciao!" Yo'qligini ko'ramiz, shundan so'ng biz dasturni to'g'ri bajarishni to'xtata olamiz. Biz bu muammoni r7 registriga chiqish tizimi qo'ng'iroq raqamini joylashtirish va so'ngra dasturiy ta'minotni uzish bo'yicha ko'rsatma raqami nolga qo'ng'iroq qilish orqali hal qilamiz. Va bu hammasi - OS yadrosi dasturimizni bajarishni tugatadi va biz buyruqlar qobig'iga qaytamiz.

Vim (chapda) ajoyib matn muharriri assembler tilida kod yozish uchun - sintaksisni ta'kidlash uchun fayl bu tildan ARM arxitekturasi uchun http://tinyurl.com/psdvjen saytida mavjud.

Maslahat: Assambleyalar tili bilan ishlaganda, sharhlarni o'tkazib yubormaslik kerak. Biz foydalanmadik katta miqdor ushbu maqoladagi sharhlar kod jurnal sahifalarida iloji boricha kamroq joy egallashi uchun (shuningdek, biz har bir ko'rsatmalarning maqsadini batafsil bayon qilganimiz uchun). Ammo kodi birinchi qarashda aniq ko'rinadigan murakkab dasturlarni ishlab chiqishda siz ARM assembly tili sintaksisini qisman unutganingizdan va bir necha oydan keyin rivojlanishga qaytganingizdan keyin qanday ko'rinishi haqida doimo o'ylashingiz kerak. Siz kodda ishlatiladigan barcha fokuslar va yorliqlarni unutishingiz mumkin, shundan so'ng kod to'liq gobbledygook kabi ko'rinadi. Yuqorida aytilganlarning barchasiga asoslanib, siz kodingizga iloji boricha ko'proq sharhlar qo'shishingiz kerak, hatto ulardan ba'zilari hozir juda aniq ko'rinsa ham!

Teskari muhandislik

Ikkilik faylni assembler tili kodiga aylantirish ham ba'zi hollarda foydali bo'lishi mumkin. Ushbu operatsiyaning natijasi odatda o'qilishi mumkin bo'lgan yorliq nomlari va sharhlarisiz unchalik yuqori sifatli kod emas, ammo bu sizning kodingizda assembler tomonidan amalga oshirilgan o'zgarishlarni o'rganish uchun foydali bo'lishi mumkin. Birinchi ikkilik faylni qismlarga ajratish uchun quyidagi buyruqni bajaring:

Objdump -d myfirst

Ushbu buyruq ikkilik faylning bajariladigan kod qismini qismlarga ajratadi (lekin ma'lumotlar bo'limi emas, chunki u ASCII matnini o'z ichiga oladi). Agar siz qismlarga ajratish natijasida olingan kodni ko'rsangiz, undagi ko'rsatmalar asl koddagi ko'rsatmalar bilan deyarli bir xil ekanligini sezasiz. Disassemblerlar, asosan, virus yoki oddiy yopiq manbali dastur kabi faqat ikkilik kod shaklida mavjud bo'lgan dasturning xatti-harakatlarini o'rganish kerak bo'lganda qo'llaniladi. manba kodi, kimning xatti-harakatiga taqlid qilmoqchisiz. Shu bilan birga, siz har doim o'rganilayotgan dastur muallifi tomonidan qo'yilgan cheklovlarni eslab qolishingiz kerak! Ikkilik dastur faylini qismlarga ajratish va natijada olingan kodni loyiha kodiga shunchaki nusxalash, albatta, yomon fikrdir; shu bilan birga, dasturning ishlash printsipini o'rganish uchun olingan koddan to'liq foydalanishingiz mumkin.

Subprogrammalar, tsikllar va shartli bayonotlar

Endi biz oddiy dasturlarni loyihalash, yig‘ish va bog‘lashni bilganimizdan so‘ng, yanada murakkabroq narsaga o‘tamiz. Quyidagi dastur satrlarni chop etish uchun pastki dasturlardan foydalanadi (ular tufayli biz kod bo'laklarini qayta ishlatishimiz va registrlarni ma'lumotlar bilan to'ldirish bo'yicha xuddi shunday operatsiyalarni bajarishdan o'zimizni saqlab qolishimiz mumkin). Ushbu dastur foydalanuvchi "q" ga kirgunga qadar satrni chiqarishga imkon beruvchi asosiy voqea tsiklini amalga oshiradi. Kodni o'rganing va ko'rsatmalarning maqsadini tushunishga harakat qiling (yoki taxmin qiling!), lekin biror narsani tushunmasangiz, tushkunlikka tushmang, chunki birozdan keyin biz ham uni batafsil ko'rib chiqamiz. ARM assembler tilidagi @ belgilari izohlarni ta'kidlashini unutmang.

Global _start _start: ldr r1, =string1 mov r2, #string1len bl print_string loop: mov r7, #3 @ read mov r0, #0 @ stdin ldr r1, =char mov r2, #2 @ ikki belgi swi 0 ldr r1, =char ldrb r2, cmp r2, #113 @ "q" beq uchun ASCII kodi bajarildi ldr r1, =string2 mov r2, #string2len bl print_string b tsikli bajarildi: mov r7, #1 swi 0 print_string: mov r7, #4 mov r0, #1 swi 0 bx lr .data string1: .ascii "Chiqish uchun q kiriting!\n" string1len = . - string1 string2: .ascii "Bu q emas edi...\n" string2len = - string2 char: .word 0

Bizning dasturimiz yozish tizimi chaqiruvining keyingi bajarilishi uchun tegishli registrlarga satr boshiga va uning uzunligiga ko'rsatgich qo'yish bilan boshlanadi, shundan so'ng darhol kodda quyida joylashgan print_string pastki dasturiga o'tadi. Ushbu o'tishni amalga oshirish uchun bl ko'rsatmasi qo'llaniladi, uning nomi "filial va havola" ("manzilni saqlaydigan filial") degan ma'noni anglatadi va uning o'zi joriy manzilni kodda saqlaydi, bu esa keyinchalik unga qaytish imkonini beradi. bx ko'rsatmasi yordamida. Print_string tartibi oddiygina boshqa registrlarni to'ldiradi, bu esa OS yadro maydoniga o'tishdan va keyin bx ko'rsatmasi yordamida saqlangan kod manziliga qaytishdan oldin birinchi dasturimiz kabi yozish tizimi chaqiruvini amalga oshiradi.

Qo'ng'iroq kodiga qaytsak, biz halqa deb nomlangan yorliqni topishimiz mumkin - yorliqning nomi allaqachon biz unga birozdan keyin qaytishimizni ko'rsatmoqda. Lekin birinchi navbatda biz klaviatura yordamida foydalanuvchi kiritgan belgini o'qish uchun read (3-raqamli) deb nomlangan boshqa tizim chaqiruvidan foydalanamiz. Shunday qilib, biz r7 registriga 3 qiymatini va r0 registriga 0 qiymatini (standart kiritish dastagi) qo'yamiz, chunki biz fayl ma'lumotlarini emas, balki foydalanuvchi kiritishini o'qishimiz kerak.

Keyinchalik, biz r1 registrida OS yadrosi tomonidan o'qilgan va joylashtirilgan belgini saqlamoqchi bo'lgan manzilni joylashtiramiz - bizning holatlarimizda bu ma'lumotlar bo'limining oxirida tasvirlangan char xotira maydoni. (Aslida, bizga mashina so'zi, ya'ni ikkita belgini saqlash uchun xotira maydoni kerak, chunki u Enter tugmachasining kodini ham saqlaydi. Assambleya tili bilan ishlashda xotiraning to'lib ketishi ehtimolini doimo yodda tutish kerak. hududlar, chunki sizning yordamingizga kelishga tayyor yuqori darajadagi mexanizmlar yo'q!).

Asosiy kodga qaytsak, biz saqlamoqchi bo'lgan ikkita belgiga mos keladigan r2 registrida 2 qiymati joylashtirilganini ko'ramiz va keyin o'qish operatsiyasini bajarish uchun yadro maydoniga o'tamiz. Foydalanuvchi belgi kiritadi va Enter tugmasini bosadi. Endi biz belgining nima ekanligini tekshirishimiz kerak: r1 registriga xotira maydonining manzilini (ma'lumotlar bo'limidagi char) joylashtiramiz va keyin ldrb ko'rsatmasi yordamida baytni xotira maydonidagi qiymat bilan ko'rsatilgan xotira maydonidan yuklaymiz. bu ro'yxatga olish.

Bu holda kvadrat qavslar ma'lumotlar registrning o'zida emas, balki bizni qiziqtirgan xotira sohasida saqlanganligini ko'rsatadi. Shunday qilib, r2 registrida endi ma'lumotlar bo'limidagi char xotirasi maydonidan bitta belgi mavjud va bu foydalanuvchi kiritgan aniq belgidir. Bizning keyingi vazifamiz r2 registrining mazmunini ASCII jadvalining 113-belgisi bo'lgan "q" belgisi bilan solishtirish bo'ladi (www.asciichart.com saytida joylashgan belgilar jadvaliga qarang). Endi taqqoslash amalini bajarish uchun cmp ko‘rsatmasidan foydalanamiz, so‘ngra r2 registridagi qiymat 113 bo‘lsa, bajarilgan yorlig‘iga o‘tish uchun “teng bo‘lsa shox” degan ma’noni anglatuvchi beq ko‘rsatmasidan foydalanamiz. Agar bunday bo‘lmasa. , keyin biz ikkinchi qatorimizni chop etamiz, shundan so'ng b ko'rsatmasi yordamida tsiklning boshiga o'tamiz.

Nihoyat, bajarilgan belgidan so'ng, biz OS yadrosiga birinchi dasturdagi kabi dasturni to'xtatmoqchi ekanligimizni aytamiz. Ushbu dasturni ishga tushirish uchun uni birinchi dastur uchun berilgan ko'rsatmalarga muvofiq yig'ish va bog'lash kifoya.

Shunday qilib, biz juda ko'p miqdordagi ma'lumotlarni eng siqilgan shaklda ko'rib chiqdik, ammo yuqoridagi kod bilan tajriba o'tkazib, materialni o'zingiz o'rgansangiz yaxshi bo'ladi. Yo'q eng yaxshi yo'l boshqa birovning kodini o'zgartirish va erishilgan effektni kuzatishni o'z ichiga olgan tajribalar o'tkazishdan ko'ra dasturlash tilini bilish. Endi siz o'qiydigan oddiy ARM assembler tili dasturlarini ishlab chiqishingiz mumkin foydalanuvchi kiritish va tsikllar, taqqoslash operatsiyalari va kichik dasturlar yordamida ma'lumotlarni chiqarish. Agar siz bugungacha assembler tiliga duch kelmagan bo'lsangiz, umid qilamanki, ushbu maqola tilni siz uchun biroz tushunarli qildi va bu faqat bir nechta iste'dodli ishlab chiquvchilar uchun mo'ljallangan mistik hunarmandchilik degan mashhur stereotipni yo'q qilishga yordam berdi.

Albatta, maqolada ARM arxitekturasi uchun assembly tilidan foydalanishga oid ma'lumotlar aysbergning faqat uchi. Ushbu dasturlash tilidan foydalanish har doim juda ko'p nuanslar bilan bog'liq va agar siz ular haqida keyingi maqolalardan birida yozishimizni istasangiz, bu haqda bizga xabar bering! Shu bilan birga, dasturlarni yaratish texnikasini o'rganish uchun juda ko'p materiallarga ega ajoyib manbaga tashrif buyurishni tavsiya qilamiz Linux tizimlari, http://tinyurl.com/nsgzq89 manzilida joylashgan ARM arxitekturali markaziy protsessorli kompyuterlarda bajariladi. Baxtli dasturlash!

"Assembleya maktabi" turkumidagi oldingi maqolalar:

1. Haqiqiy vaqt hisoblagichi yoqilgan bo'lishi kerak (1); Soat manbasini tanlash biti o'chiriladi (2), agar soatni belgilash asosiy soat generatori tomonidan ta'minlanmasa.

2. Bir yoki ikkala uzilish hodisasini tanlash bitlari (3) o'rnatilishi kerak. Va qaysi hodisalar uzilish so'rovini ishga tushirishi tanlanadi (5).

3. Interrupt hodisasi maskalari (4, 7) ko'rsatilishi kerak.

2.5 ARM7 ni assemblerda dasturlash haqida

ARM7 ko'rsatmalar to'plami (1.4-bo'lim) faqat 45 ta ko'rsatmalarni o'z ichiga oladi, ular turli xil adreslash usullari, shartli maydonlar va modifikatorlar tufayli juda murakkab. Assembler dasturi og'ir va

Bilan o'qish qiyin. Shuning uchun, assembler ARM7 arxitekturasi uchun dasturlashda kamdan-kam qo'llaniladi.

Shu bilan birga, til yuqori daraja C dasturchidan ko'plab me'moriy xususiyatlarni yashiradi. Dasturchi yadro rejimini tanlash, stek uchun xotira ajratish va uzilishlarni qayta ishlash kabi protseduralarga deyarli tegmaydi. Ushbu protseduralarni o'rganish uchun assembler tilida kamida bitta oddiy dastur yozish foydalidir.

Bundan tashqari, C dan foydalanganda ham, siz hali ham assembler tiliga murojaat qilishingiz kerak.

1. Nazorat qilinishi kerak C kompilyatori optimallashtirish paytida muhim buyruqlarni keraksiz deb hisoblagan holda ularni chiqarib tashlagan-yo'qligini nazorat qiladi. Kompilyator optimallashtirishning etarli emasligi sababli nisbatan oddiy operatsiya uchun juda samarasiz kod ishlab chiqaradimi? Kompilyator haqiqatda ma'lum bir algoritm samaradorligini oshirish uchun mo'ljallangan apparat resurslaridan foydalanishiga ishonch hosil qilish uchun.

2. Xatolar yoki istisnolar sabablarini qidirishda (2.4.1-bo'lim).

3. Ishlash yoki xotira iste'moli nuqtai nazaridan mutlaqo maqbul bo'lgan kodni olish uchun (2.2.20, 3.1.5-bo'limlar).

Assemblerda dastur yozishning asosiy usullarini ko'rib chiqamiz

Bilan Maqsad mikrokontroller tomonidan bajarilgan barcha kodlarni vositachiliksiz ko'rsatishdir. C kompilyatori.

Assemblerga asoslangan loyihani yaratish tartibi C dasturlari bilan deyarli bir xil (2.3.1-2.3.3-bo'limlar). Faqat ikkita istisno mavjud:

a) manba matn fayliga *.S kengaytmasi beriladi;

b) bu ​​yerda STARTUP.S fayli dasturga ulanmagan deb taxmin qilinadi.

2.5.1 Assemblerda dasturlar yozishning asosiy qoidalari

Assembler dasturining matni odatda to'rtta ustunda formatlanadi. Aytishimiz mumkinki, har bir satr to'rtta maydondan iborat, ya'ni: teglar, operatsiyalar, operandlar, sharhlar. Maydonlar bir-biridan yorliq belgilari yoki bo'shliqlar bilan ajratiladi.

Asosiy sohalar operatsiyalar va operandlardir. Amaldagi amallar va ularning sintaksisi (1.4.2) jadvalda keltirilgan.

Yorliq - bu buyruq manzilining ramziy belgisi. Hamma joyda yorliq o'rniga yorliq oldidagi buyruq manzili almashtiriladi. Ko'pincha teglar boshqaruvni uzatish buyruqlarida qo'llaniladi. Har bir yorliq noyob bo'lishi va ixtiyoriy bo'lishi kerak. Ko'pgina boshqa versiyalardan farqli o'laroq, RealView assemblerda teglar ikki nuqta (":") bilan tugamaydi.

Izohlar ixtiyoriy ravishda satr oxiriga joylashtiriladi va nuqtali vergul (“;”) bilan ajratiladi.

Oddiy misol keltiraylik.

2.5.2 Pseudo-buyruqlar

RealView assembler psevdo-ko'rsatmalar deb ataladigan narsalarni qo'llab-quvvatlaydi. Pseudo-buyruq - bu mnemonik, bu aslida protsessorning ko'rsatmalar to'plamiga mos kelmaydi, lekin bir yoki (kamdan-kam hollarda) bir nechta ko'rsatmalar bilan almashtiriladi. Pseudo-buyruqlar makrolarning bir turi bo'lib, sintaksisni soddalashtirish uchun xizmat qiladi. Qo'llab-quvvatlanadigan psevdo-buyruqlar ro'yxati (2.5.1) jadvalda keltirilgan.

2.5.3 Yig'ilish bo'yicha ko'rsatmalar

Buyruqlardan farqli o'laroq, direktivalar mikrokontroller xotirasiga yuklangan bajariladigan kodni yaratmaydi. Direktivlar faqat assembler uchun ko'rsatmalar bo'lib, ular bajariladigan kodning shakllanishini nazorat qiladi;

Tez-tez ishlatiladigan RealView 4 assembler direktivalarini ko'rib chiqaylik.

EQU konstantasini nomlang

Konstantaga Ism ramziy belgisini beradi, bu doimiyning sinonimiga aylanadi. Asosiy maqsad - nazorat registrlarining nomlarini kiritish,

AREA nomi, parametrlari

Berilgan Ism bilan xotira maydonini belgilaydi. Parametrlardan foydalanib, siz xotira maydonining maqsadini belgilaysiz, masalan, DATA (ma'lumotlar) yoki CODE (kod). Belgilangan hududning manzillari tanlangan manzilga bog'liq. KOD maydoni 0x00000000 manzilidan boshlab, DATA maydoni - 0x40000000 manzilida joylashgan. Dasturda RESET deb nomlangan KOD maydoni bo'lishi kerak. Dastur xotirasiga joylashtirilgan konstantalar CODE, READONLY parametrlari juftligi bilan bo'limda e'lon qilinishi kerak.

Dasturga kirish nuqtasini ko'rsatadi, uning "boshlanishi" ni ko'rsatadi. Bunday direktivlardan biri har doim dasturda bo'lishi kerak. Odatda AREA RESET, CODE direktivasidan so'ng darhol joylashtiriladi.

2.5.1-jadval – RealView 4 assembler tomonidan qo'llab-quvvatlanadigan psevdo-ko'rsatmalar

Mnemonik belgi

Operatsiya

Haqiqiy amalga oshirish

va sintaksis

ADR (shart.)

reestrga

Kompyuterdan doimiyni qo'shish yoki ayirish

QO'SHISH yoki SUB buyruqlari

ADRL(Shart)

reestrga

Kompyuterni o'z ichiga olgan ikki marta qo'shish yoki SUB

(kengaytirilgan manzil diapazoni)

ASR(Cond) (S)

Arifmetik o'ngga siljish

ASR(Cond) (S)

siljish operand

LDR (shart.)

reestrga

adreslash (kompyuter + darhol ofset)

Konstantani joylashtirish

dastur xotirasida

LDR(indeks manzilidan -

tion. Kompyuter ofset vazifasini bajaradi.

LSL(shartli)(S)

Mantiqiy siljish chapga

LSL(shartli)(S)

siljish operand

LSR(Cond) (S)

Mantiqiy o'ngga siljish

LSR(Cond) (S)

siljish operand

POP (Cond)

Registrlarni stekdan tiklash

Qayta tiklash

registrlar

jamoa

LDMIA R13!,(...)

PUSH (Cond)

Saqlash

registrlar

jamoa

STMDB R13!,(...)

ROR(shartli)(S)

O'ngga tsiklik siljish

ROR(shartli)(S)

siljish operand

RRX(Shart.)(S)

To'g'ridan-to'g'ri aylanish

1 raqamga o'tkazish

siljish operand

SPACE hajmini nomlang

Muayyan o'lchamdagi ma'lumotlarni saqlash uchun xotirani zahiralaydi. Ism ajratilgan joyning manzili bilan sinonimga aylanadi. Manzil maydonining birligi ushbu direktivani ham doimiy, ham RAM uchun ishlatishga imkon beradi. Asosiy maqsad RAMda (DATA sohasida) global o'zgaruvchilarni yaratishdir.

Yorliq DCB/DCW/DCD doimiy

Dastur xotirasida "Flash" ma'lumotlari (raqamli doimiylar). Yorliq ma'lumotlar yoziladigan manzil bilan sinonimga aylanadi. Turli xil direktivalar (DCB, DCW va DCD) ma'lumotlar uchun xizmat qiladi turli o'lchamlar: bayt, 16 bitli so'z, 32 bitli so'z (mos ravishda).

Fayl tugashining belgisi sifatida xizmat qiladi. Ushbu direktivadan keyingi barcha matn assembler tomonidan e'tiborga olinmaydi.

2.5.4 Makroslar

Makros - bu ba'zi bir umumiy operatsiyalarni bajaradigan oldindan belgilangan dastur fragmenti. Boshqaruv uzatish buyruqlari yordamida chaqiriladigan kichik dasturlardan farqli o'laroq, makrolardan foydalanish unumdorlikni pasaytirmaydi, lekin dastur xotirasi sarfini kamaytirmaydi. Chunki har safar makros chaqirilganda assembler butun matnni dasturga joylashtiradi.

Makrosni e'lon qilish uchun quyidagi konstruktsiyadan foydalaning

$ Parametr1, $ Parametr2, ...

Parametrlar so'l matnga har safar kirganingizda uni o'zgartirishga imkon beradi. Makrosning ichida (tanasida) parametrlar oldingi "$" belgisi bilan ham ishlatiladi. Makrosning tanasidagi parametrlar o'rniga qo'ng'iroq paytida ko'rsatilgan parametrlar almashtiriladi.

Makro shunday deb ataladi:

Nomi Parametr1, Parametr2, ...

Vaziyatni tekshirish va dallanishni tashkil qilish mumkin.

AGAR "$Parameter" == "Qiymat"

Iltimos, ushbu dizaynga olib kelmasligini unutmang dasturiy ta'minotni tekshirish mikrokontroller sharoitlari. Vaziyat bajariladigan kodni yaratish jarayonida assembler tomonidan tekshiriladi.

Shunday qilib, biz yaratdik yangi loyiha, asosiy sozlamalarni yakunladik, biz assemblerda oddiy dastur yozmoqchi bo'lgan faylni yaratdik va loyihaga ulandik.

Keyin nima? Keyin, aslida, siz Cortex-M3 yadrosi tomonidan qo'llab-quvvatlanadigan thumb-2 buyruqlar to'plamidan foydalanib dastur yozishingiz mumkin. Qo'llab-quvvatlanadigan buyruqlar ro'yxati va tavsifini chaqirilgan hujjatda topish mumkin Cortex-M3 umumiy foydalanuvchi qo'llanmasi(bob Cortex-M3 ko'rsatmalar to'plami), uni Keil uVision 5-dagi loyiha menejeridagi Kitoblar yorlig'ida topish mumkin. Bosh barmoq-2 buyruqlari haqida batafsil ma'lumot ushbu maqolaning quyidagi qismlaridan birida yoziladi, ammo hozircha STM32 uchun dasturlar haqida gapiraylik. umumiy.

Boshqa har qanday assembler dasturi singari, STM32 dasturi to'g'ridan-to'g'ri mashina kodlariga tarjima qilinadigan buyruqlar va psevdo-buyruqlardan, shuningdek, mashina kodlariga tarjima qilinmagan, ammo xizmat ko'rsatish maqsadlarida ishlatiladigan turli xil ko'rsatmalardan iborat (dasturni belgilash, konstantalar nomlariga ramziy belgilar belgilash va h.k.)

Masalan, maxsus direktiv dasturni alohida bo'limlarga bo'lish imkonini beradi - MUDDAT. U quyidagi sintaksisga ega: AREA Bo'lim_Nomi (, turi) (, attr) …, Qayerda:

  1. Bo'lim_nomi- bo'lim nomi.
  2. turi- bo'lim turi. Ma'lumotlarni o'z ichiga olgan bo'lim uchun DATA turi ko'rsatilishi kerak va buyruqlarni o'z ichiga olgan bo'lim uchun KOD turi ko'rsatilishi kerak.
  3. attr- qo'shimcha atributlar. Masalan, faqat o'qish yoki o'qish atributlari bo'lim qaysi xotirada joylashishi kerakligini ko'rsatadi, align=0..31 atributi bo'limni xotirada qanday tekislash kerakligini ko'rsatadi, noinit atributi xotira maydonlarini ajratish uchun ishlatiladi, ular uchun kerak bo'lmaydi. ishga tushirilishi yoki nolga tenglashtirilgan (bu atributdan foydalanilganda bo'lim turini ko'rsatish shart emas, chunki u faqat ma'lumotlar bo'limlari uchun ishlatilishi mumkin).

Direktiv EQU Ehtimol, hamma uchun yaxshi ma'lum, chunki u har qanday assemblerda mavjud va turli konstantalarga, xotira kataklariga va hokazolarga ramziy nomlar berish uchun mo'ljallangan. U quyidagi sintaksisga ega: Ism EQU raqam va kompilyatorga barcha belgilar duch kelganligini aytadi Ism raqam bilan almashtirilishi kerak raqam. Aytaylik, agar shunday bo'lsa raqam xotira katagining manzilidan foydalaning, keyin kelajakda bu katakka manzil bo'yicha emas, balki ekvivalent ramziy belgilar yordamida kirish mumkin ( Ism).

Direktiv OLISH Fayl nomi nomli fayldan dasturga matn kiritadi Fayl nomi. Bu AVR uchun assemblerda kiritish direktivasining analogidir. U, masalan, olib tashlash uchun ishlatilishi mumkin alohida fayl turli registrlarga ramziy nomlar berish uchun direktivalar. Ya'ni barcha nomlash topshiriqlarini alohida faylga joylashtiramiz, so'ngra bu ramziy nomlar dasturda qo'llanilishi uchun GET direktivasi bilan ushbu faylni dasturimizga kiritamiz.

Albatta, yuqorida sanab o'tilganlarga qo'shimcha ravishda, turli xil ko'rsatmalar mavjud, to'liq ro'yxat bobda topish mumkin Direktivlarga havola hujjat Assembler foydalanuvchi uchun qo'llanma, uni Keil uVision 5 da quyidagi yo'lda topish mumkin: tab Kitoblar loyiha menejeri -> Asboblar foydalanuvchi uchun qo'llanma -> Foydalanuvchi qo‘llanmasini tanlashni yakunlang -> Assembler foydalanuvchi uchun qo'llanma.

Dasturdagi aksariyat buyruqlar, psevdo-buyruqlar va direktivalar quyidagi sintaksisga ega:

(yorliq) SIMBOL (ifoda) (, ifoda) (, ifoda) (; izoh)

(yorliq) - yorliq. Bu yorliqdan keyingi buyruqning manzilini aniqlash uchun kerak. Yorliq ixtiyoriy element bo'lib, faqat buyruq manzilini bilish zarur bo'lganda foydalaniladi (masalan, ushbu buyruqqa o'tish uchun). Yorliqdan oldin bo'sh joy bo'lmasligi kerak (ya'ni u satrning birinchi pozitsiyasidan boshlanishi kerak) va yorliq nomi faqat harf bilan boshlanishi mumkin.

SYMBOL - buyruq, psevdo-buyruq yoki ko'rsatma. Buyruq, yorliqdan farqli o'laroq, aksincha, satr boshidan boshlab, hatto undan oldin yorliq bo'lmasa ham, biroz chekinishga ega bo'lishi kerak.

(expr) (,expr) (,expr) - operandlar (registrlar, konstantalar...)

; - chegaralovchi. Bu chegaralovchidan keyingi satrdagi barcha matn izoh sifatida qabul qilinadi.

Xo'sh, endi, va'da qilinganidek, eng oddiy dastur:

AREA START , KOD , FAQAT O‘QILISh dcd 0x20000400 dcd Dastur_start KIRISH Dastur_boshlanishi b Dastur_boshlanishi END

AREA START, CODE, FAQAT O‘QILADI dcd 0x20000400 dcd Dastur_start KIRISh Dastur_boshlanishi b Dastur_boshlanishi END

Ushbu dasturda bizda faqat bitta bo'lim bor, u START deb ataladi. Ushbu bo'lim flesh xotirada joylashgan (chunki u uchun faqat o'qish atributi ishlatiladi).

Ushbu bo'limning dastlabki 4 baytida stekning yuqori qismining manzili (bizning holimizda 0x20000400), ikkinchi 4 baytda esa kirish nuqtasi manzili (bajariladigan kodning boshlanishi) mavjud. Keyinchalik kodning o'zi keladi. Eng oddiy misolimizda bajariladigan kod Program_start yorlig'iga so'zsiz o'tish, ya'ni xuddi shu buyruqni qayta bajarish uchun bitta buyruqdan iborat.

Flashda faqat bitta bo'lim bo'lgani uchun dasturimiz uchun scatter faylida uning nomini (ya'ni START) Birinchi_Bo'lim_Nomi sifatida ko'rsatishimiz kerak bo'ladi.

Bunday holda, biz aralashgan ma'lumotlar va buyruqlarga egamiz. Stackning yuqori qismining manzili va kirish nuqtasi (ma'lumotlar) manzili to'g'ridan-to'g'ri kod bo'limida dcd direktivalari yordamida yoziladi. Albatta, siz shunday yozishingiz mumkin, lekin bu juda yoqimli emas. Ayniqsa, agar biz faqat qayta o'rnatish vektorini emas, balki butun uzilishlar va istisnolar jadvalini (bu juda uzun bo'lib chiqadi) tasvirlasak. Kodni keraksiz ma'lumotlar bilan aralashtirib yubormaslik, balki uzilish vektorlari jadvalini alohida bo'limga yoki undan ham yaxshiroq - alohida faylga joylashtirish ancha chiroyli. Xuddi shunday, stekni ishga tushirish alohida bo'limga yoki hatto faylga joylashtirilishi mumkin. Masalan, biz hamma narsani alohida bo'limlarga joylashtiramiz:

AREA STACK, NOINIT, READWRITE SPACE 0x400 ; 400 baytni o'tkazib yuborish Stack_top ; va yorliq qo'ying AREA RESET, DATA, READONLY dcd Stack_top ; teg manzili Stack_top dcd Program_start ; yorliq manzili Program_start AREA DASTURI, KOD, FAQAT O'QILIShI KIRISH ; kirish nuqtasi (bajariladigan kodning boshlanishi) Program_start ; dasturni boshlash belgisi b Program_start END

Xo'sh, xuddi shu dastur (bu hali ham foydali narsa qilmaydi), lekin endi u ancha aniq ko'rinadi. Ushbu dastur uchun scatter faylida RESET nomini First_Section_Name sifatida belgilashingiz kerak, shunda bu bo'lim flesh-xotirada birinchi bo'lib joylashadi.

CISC protsessorlari bitta buyruqda ancha murakkab operatsiyalarni, shu jumladan xotira kataklari tarkibidagi arifmetik va mantiqiy operatsiyalarni bajaradi. CISC protsessor ko'rsatmalari turli uzunliklarga ega bo'lishi mumkin.

Aksincha, RISC nisbatan ega oddiy tizim operatsiya turi bo'yicha aniq bo'linish bilan buyruqlar:

  • xotira bilan ishlash (xotiradan registrlarga o'qish yoki registrlardan xotiraga yozish),
  • registrlarda ma'lumotlarni qayta ishlash (arifmetik, mantiqiy, ma'lumotlarning chapga/o'ngga siljishi yoki registrda bit aylanishi),
  • boshqa manzillarga shartli yoki shartsiz o'tish buyruqlari.

Qoida tariqasida (lekin har doim ham emas va faqat dastur kodi kontroller kesh xotirasiga kirsa) bitta buyruq bir protsessor siklida bajariladi. ARM protsessor buyrug'ining uzunligi qat'iy belgilangan - 4 bayt (bir kompyuter so'zi). Darhaqiqat, zamonaviy ARM protsessori boshqa ish rejimlariga, masalan, ko'rsatma uzunligi 2 baytga aylanganda THUMB rejimiga o'tishi mumkin. Bu kodni yanada ixcham qilish imkonini beradi. Biroq, biz ushbu maqolada ushbu rejimni ko'rib chiqmaymiz, chunki u Amber ARM v2a protsessorida qo'llab-quvvatlanmaydi. Xuddi shu sababga ko'ra, biz Jazelle (Java kodini bajarish uchun optimallashtirilgan) kabi rejimlarni ko'rib chiqmaymiz va NEON buyruqlarini - bir nechta ma'lumotlar bilan ishlash buyruqlarini ko'rib chiqmaymiz. Axir biz sof ARM ko'rsatmalar tizimini o'rganmoqdamiz.

ARM protsessor registrlari.

ARM protsessorida bir nechta registrlar to'plami mavjud bo'lib, ulardan faqat 16 tasi dasturchi uchun mavjud. Ish rejimiga qarab bir nechta protsessor ish rejimlari mavjud, tegishli registrlar banki tanlanadi. Ushbu ish rejimlari:

  • dastur rejimi (USR, foydalanuvchi rejimi),
  • nazoratchi rejimi yoki operatsion tizim rejimi (SVC, supervayzer rejimi),
  • uzilishni qayta ishlash rejimi (IRQ, uzilish rejimi) va
  • "shoshilinch uzilish" ishlov berish rejimi (FIRQ, tez uzilish rejimi).

Ya'ni, masalan, uzilish sodir bo'lganda, protsessorning o'zi uzilishni qayta ishlash dasturining manziliga boradi va avtomatik ravishda registr banklarini "o'zgartiradi".

Eski versiyalarning ARM protsessorlari, yuqoridagi ish rejimlariga qo'shimcha ravishda, qo'shimcha rejimlarga ega:

  • Bekor qilish (xotiraga kirish istisnolarini boshqarish uchun ishlatiladi),
  • Aniqlanmagan (dasturiy ta'minotda soprotsessorni amalga oshirish uchun ishlatiladi) va
  • operatsion tizim tizimining imtiyozli vazifa rejimi.

Amber ARM v2a protsessorida bu qo'shimcha uchta rejim mavjud emas.

Amber ARM v2a uchun registrlar to'plami quyidagicha ifodalanishi mumkin:

r0-r7 registrlari barcha rejimlar uchun bir xil.
r8-r12 registrlari faqat USR, SVC, IRQ rejimlari uchun keng tarqalgan.
Register r13 - bu stek ko'rsatkichi. U barcha rejimlarda o'ziga xosdir.
Register r14 - pastki dasturdan qaytish registrlari ham barcha rejimlarda farq qiladi.
Register r15 - bajariladigan ko'rsatmalarga ko'rsatgich. Bu barcha rejimlar uchun umumiydir.

Ko'rinib turibdiki, FIRQ rejimi eng izolyatsiya qilingan, u o'zining eng ko'p registrlariga ega. Bu juda muhim bo'lgan uzilishlarni stekda registrlarni saqlamasdan, vaqtni yo'qotmasdan qayta ishlash uchun amalga oshiriladi.

r15 ni ro'yxatdan o'tkazishga alohida e'tibor berilishi kerak, shuningdek, kompyuter (Dastur hisoblagichi) sifatida ham tanilgan - bajariladigan buyruqlar uchun ko'rsatgich. Uning mazmuni ustida turli arifmetik va mantiqiy amallarni bajarishingiz mumkin, shu bilan dasturning bajarilishi boshqa manzillarga o'tadi. Biroq, Amber tizimida amalga oshirilgan ARM v2a protsessori uchun ushbu registrning bitlarini talqin qilishda ba'zi nozikliklar mavjud.

Gap shundaki, ushbu protsessorda r15 (kompyuter) registrida bajariladigan buyruqlar uchun haqiqiy ko'rsatgichga qo'shimcha ravishda quyidagi ma'lumotlar mavjud:

Bitlar 31:28 - arifmetik yoki mantiqiy operatsiya natijasi uchun bayroqlar
Bitlar 27 - uzilish IRQ niqobi, bit o'rnatilganda uzilishlar o'chiriladi.
Bitlar 26 - FIRQ uzilish maskasi, bit o'rnatilganda tez uzilishlar o'chiriladi.
Bits 25:2 - dastur ko'rsatmalariga haqiqiy ko'rsatgich faqat 26 bitni oladi.
Bitlar 1:0 - joriy rejim protsessorning ishlashi.
3 - nazoratchi
2 - uzilish
1 - Tez uzilish
0 - foydalanuvchi

Eski ARM protsessorlarida barcha bayroqlar va xizmat bitlari alohida registrlarda joylashgan Joriy dastur holati registri(cpsr) va Saved Program Status Register (spsr), kirish uchun alohida maxsus buyruqlar mavjud. Bu dasturlar uchun mavjud manzil maydonini kengaytirish maqsadida amalga oshiriladi.

ARM assemblerni o'zlashtirishdagi qiyinchiliklardan biri bu ba'zi registrlarning muqobil nomlaridir. Shunday qilib, yuqorida aytib o'tilganidek, r15 bir xil kompyuterdir. Bundan tashqari, r13 mavjud - bu bir xil sp (Stack Pointer), r14 - lr (Link Register) - protseduradan qaytish manzili registri. Bundan tashqari, r12 bir xil IP (Intra-Procedure -call scratch Registri) C kompilyatorlari tomonidan stekdagi parametrlarga kirish uchun maxsus usulda qo'llaniladi. Bunday muqobil nomlash ba'zan boshqa birovning dastur kodiga qaraganingizda chalkash bo'ladi - bu ikkala registr belgilari ham o'sha erda topiladi.

Kodni bajarish xususiyatlari.

Ko'p turdagi protsessorlarda (masalan, x86) shart bo'yicha faqat boshqa dastur manziliga o'tish mumkin. ARM bilan bunday emas. Har bir ARM protsessor buyrug'i shartli ravishda bajarilishi yoki bajarilmasligi mumkin. Bu sizga dastur orqali o'tishlar sonini kamaytirishga va shuning uchun protsessor quvuridan samaraliroq foydalanishga imkon beradi.

Axir, quvur liniyasi nima? Endi dastur kodidan bitta protsessor ko'rsatmasi tanlandi, oldingisi allaqachon dekodlanmoqda va oldingisi allaqachon bajarilmoqda. Bu Amber A23 protsessorining 3 bosqichli quvur liniyasi bo'lib, biz Mars Rover2Mars Rover2 platasi uchun loyihamizda foydalanamiz. Amber A25 protsessorining modifikatsiyasi 5 bosqichli quvur liniyasiga ega, u yanada samaraliroq. Lekin, bitta katta BUT bor. O'tish buyruqlari protsessorni quvur liniyasini tozalashga va uni to'ldirishga majbur qiladi. Shunday qilib, yangi buyruq tanlandi, lekin hali dekodlash uchun hech narsa yo'q va bundan tashqari, darhol bajariladigan hech narsa yo'q. Kodni bajarish samaradorligi tez-tez o'tish bilan kamayadi. IN zamonaviy protsessorlar Quvurni to'ldirishni qandaydir tarzda optimallashtiradigan o'tishni bashorat qilishning barcha mexanizmlari mavjud, ammo bizning protsessorimizda bunday yo'q. Qanday bo'lmasin, ARM har bir buyruqni shartli ravishda bajarishga imkon berish uchun oqilona edi.

ARM protsessorida har qanday turdagi ko'rsatmalarda ko'rsatmalarning bajarilishi shartining to'rt biti ko'rsatma kodining eng yuqori to'rt bitida kodlangan:

Protsessorda jami 4 ta holat belgisi mavjud:
. Salbiy - operatsiya natijasi salbiy,
. Nol - natija nolga teng,
. Tashish - imzosiz raqamlar bilan operatsiyani bajarishda sodir bo'lgan tashish,
. oVerflow - imzolangan raqamlar bilan operatsiyani bajarishda to'lib ketish yuz berdi, natija registrga to'g'ri kelmaydi)

Ushbu 4 bayroq ko'plab mumkin bo'lgan shartlar kombinatsiyasini hosil qiladi:

Kod Suffiks Ma'nosi Bayroqlar
4"h0 ek Teng Z to'plami
4"h1 yo'q Teng emas Z aniq
4"h2 cs/s O'rnatish to'plami / imzosiz yuqori yoki bir xil C to'plami
4"h3 cc/lo Aniq / imzosiz pastga olib boring C aniq
4"h4 mil Minus/salbiy N to'plam
4"h5 pl Plyus/musbat yoki nol N aniq
4"h6 va boshqalar To'lib ketish V to'plami
4"h7 vc To'lib ketish yo'q V aniq
4"h8 salom Imzosiz yuqoriroq C to'plami va Z toza
4"h9 ls Imzosiz pastroq yoki bir xil C toza yoki Z to'plami
4 "ga ge Kattaroq yoki teng imzolangan N == V
4" hb lt dan kamroq imzolangan N!= V
4" hc GT dan kattaroq imzolangan Z == 0,N == V
4 "HD le Kamroq yoki teng imzolangan Z == 1 yoki N != V
4" u al Har doim (shartsiz)
4" soat - Yaroqsiz holat

Endi bu ARM protsessor ko'rsatmalarini o'rganishda yana bir qiyinchilikka olib keladi - ko'rsatmalar kodiga qo'shilishi mumkin bo'lgan ko'plab qo'shimchalar. Misol uchun, Z bayrog'i o'rnatilgan bo'lsa, qo'shish - bu addeq buyrug'i sifatida add + suffix eq . Agar N=0 bayroq blpl + pl qo'shimchasi sifatida bo'lsa, pastki dasturga o'ting.

Bayroqlar (Salbiy, nol, tashish, oVerflow) arifmetika yoki uchun har doim ham bir xil o'rnatilmaydi mantiqiy operatsiyalar, aytaylik, x86 protsessorida sodir bo'ladi, lekin faqat dasturchi xohlasa. Buning uchun mnemonika buyrug'iga yana bir qo'shimcha mavjud: "s" (buyruq kodida u 20-bit bilan kodlangan). Shunday qilib, qo'shish buyrug'i bayroqlarni o'zgartirmaydi, lekin adds buyrug'i bayroqlarni o'zgartiradi. Yoki shartli qo'shish buyrug'i ham bo'lishi mumkin, lekin u bayroqlarni o'zgartiradi. Masalan: addgts. Shartli bajarish va bayroqlarni o'rnatish uchun turli qo'shimchalar bilan buyruq nomlarining mumkin bo'lgan kombinatsiyalarining soni ARM protsessorining yig'ish kodini juda o'ziga xos va o'qishni qiyinlashtirishi aniq. Biroq, vaqt o'tishi bilan siz bunga ko'nikasiz va ushbu matnni tushunishni boshlaysiz.

Arifmetik va mantiqiy operatsiyalar (ma'lumotlarni qayta ishlash).

ARM protsessori turli arifmetik va mantiqiy amallarni bajarishi mumkin.

Haqiqiy to'rt bitli operatsiya kodi (Opcode) protsessor ko'rsatmalari bitlarida mavjud.

Har qanday operatsiya registrning mazmuni va shifter_operand deb ataladigan narsada amalga oshiriladi. Amaliyot natijasi registrga joylashtiriladi. To'rt bitli Rn va Rd protsessorning faol bankidagi registrlarning indekslari.

I 25 bitga qarab shifter_operand raqamli konstanta sifatida yoki operandning ikkinchi registrining indeksi va hatto ikkinchi operand qiymati bo'yicha siljish operatsiyasi sifatida ko'rib chiqiladi.

Assembler buyruqlarining oddiy misollari quyidagicha ko'rinadi:

r0,r1,r2 @ qo'shing r1 va r2 registrlari qiymatlari yig'indisini r0 registriga joylashtiring
sub r5,r4,#7 @ farqni (r4-7) r5 registriga joylashtiring

Amalga oshirilgan operatsiyalar quyidagicha kodlangan:

4"h0 va Mantiqiy VA Rd:= Rn VA shifter_operand
4"h1 e yoki Mantiqiy eksklyuziv YOKI Rd:= Rn XOR shifter_operand
4"h2 sub Arifmetik ayirma Rd:= Rn - shifter_operand
4"h3 rsb Arifmetik teskari ayirish Rd:= shifter_operand - Rn
4"h4 qo'shish Arifmetik qo'shish Rd:= Rn + shifter_operand
4"h5 adc Arifmetik qo'shish va tashish bayrog'i Rd:= Rn + shifter_operand + Carry Flag
4"h6 sbc tashish Rd bilan arifmetik ayirish:= Rn - shifter_operand - EMAS(Carry Flag)
4"h7 rsc tashish Rd bilan arifmetik teskari ayirish:= shifter_operand - Rn - EMAS(Carry Flag)
4"h8 tst Mantiqiy VA, lekin natijani saqlamasdan, faqat bayroqlar Rn VA shifter_operand S bit har doim o'rnatiladi
4"h9 teq Mantiqiy eksklyuziv OR, lekin natijani saqlamasdan, faqat Rn EOR shifter_operand bayroqlari o'zgartiriladi
S bit har doim o'rnatiladi
4"ha cmp Taqqoslash, aniqrog'i, natijani saqlamasdan arifmetik ayirish, faqat Rn bayroqlari o'zgaradi - shifter_operand S bit har doim o'rnatiladi
4"hb cmn Natijani saqlamasdan teskari, to'g'rirog'i arifmetik qo'shishni solishtirish, faqat bayroqlar Rn + shifter_operand S bit har doim o'zgaradi
4"hc orr Mantiqiy OR Rd:= Rn YOKI shifter_operand
4"hd mov Rd qiymatini nusxalash:= shifter_operand (birinchi operand yo'q)
4"he bic Reset bit Rd:= Rn VA EMAS (o'zgartiruvchi_operand)
4"hf mvn Teskari qiymatni nusxalash Rd:= shifter_operand EMAS (birinchi operand yo'q)

Barrel o'tkazgich.

ARM protsessorida har qanday arifmetik yoki mantiqiy amaldan oldin operandlardan birini ma’lum miqdordagi bitlar bilan siljitish yoki aylantirish imkonini beruvchi maxsus “barrel o‘zgartiruvchi” sxema mavjud. Bu protsessorning juda qiziqarli xususiyati bo'lib, u sizga juda samarali kod yaratish imkonini beradi.

Masalan:

@9 ga ko'paytirish sonni 8 ga ko'paytirishdir
@ chapga 3 bit va boshqa raqamga siljitish orqali
r0, r1, r1, lsl #3 @ r0= r1+(r1) qo‘shing<<3) = r1*9

@ 15 ga ko'paytirish 16 minus sonni ko'paytirishdir
rsb r0, r1, r1, lsl #4 @ r0= (r1<<4)-r1 = r1*15

@ 4 baytlik so'zlardan iborat jadvalga kirish, bu erda
@r1 - jadvalning asosiy manzili
@r2 - jadvaldagi elementning indeksi
ldr r0,

Mantiqiy chapga siljish lsl dan tashqari, mantiqiy o'ngga siljish lsr va arifmetik o'ngga siljish ham mavjud (belgini saqlaydigan siljish, siljish bilan bir vaqtda chapda eng muhim bit ko'paytiriladi).

Bundan tashqari, ror bitlarining aylanishi ham mavjud - bitlar o'ngga, chiqarilganlari esa chapga suriladi.
C bayrog'i orqali bir bit siljish mavjud - bu rrx buyrug'i. Registr qiymati bir bitga o'ngga siljiydi. Chap tomonda C bayrog'i registrning eng muhim bitiga yuklanadi.

Shishish qat'iy belgilangan doimiy raqam bilan emas, balki uchinchi operand registrining qiymati bo'yicha amalga oshirilishi mumkin. Masalan:

r0, r1, r1, lsr r3 @ qo'shing, bu r0 = r1 + (r1>>r3);
r0, r0, r1, lsr r3 @ qo'shing, bu r0 = r0 + (r1>>r3);

Shunday qilib shifter_operand biz assembler buyruqlarida tasvirlangan narsadir, masalan, "r1, lsr r3" yoki "r2, lsl #5".

Eng qizig'i shundaki, operatsiyalarda smenalardan foydalanish hech qanday xarajat qilmaydi. Ushbu siljishlar (odatda) qo'shimcha soat davrlarini talab qilmaydi, bu tizimning ishlashi uchun juda yaxshi.

Raqamli operandlardan foydalanish.

Arifmetik yoki mantiqiy amallar faqat registrning mazmunidan emas, balki ikkinchi operand sifatida raqamli doimiydan ham foydalanishi mumkin.

Afsuski, bu erda bitta muhim cheklov mavjud. Barcha buyruqlar 4 bayt (32 bit) qattiq uzunlikka ega bo'lganligi sababli, undagi "har qanday" raqamni kodlash mumkin bo'lmaydi. Operatsion kodida 4 bitni bajarish sharti kodi (Cond), operatsiya kodining o'zi uchun 4 bit (Opcode), so'ngra 4 bit - qabul qiluvchi registri Rd va yana 4 bit - birinchi operand registrini egallaydi. Rn, shuningdek, turli xil bayroqlar I 25 (faqat operatsiya kodidagi raqamli doimiyni bildiradi) va S 20 (operatsiyadan keyin bayroqlarni o'rnatish). Hammasi bo'lib shifter_operand deb ataladigan mumkin bo'lgan doimiy uchun atigi 12 bit qoldi - biz buni yuqorida ko'rdik. 12 bit raqamlarni faqat tor diapazonda kodlashi mumkinligi sababli, ARM protsessorini ishlab chiquvchilar doimiyni quyidagicha kodlashga qaror qilishdi. Shift_operandning o'n ikki biti ikki qismga bo'linadi: to'rt bitli aylanish ko'rsatkichi encode_imm va haqiqiy sakkiz bitli imm_8 raqamli qiymati.

ARM protsessorida konstanta 32 bitli son ichidagi sakkiz bitli son sifatida aniqlanadi, juft bitlar soni bilan o'ngga aylantiriladi. Ya'ni:

imm_32 = imm_8 ROR (encode_imm *2)

Bu juda qiyin bo'lib chiqdi. Ma'lum bo'lishicha, assembler buyruqlarida har bir doimiy sondan foydalanish mumkin emas.

Yozishingiz mumkin

r0, r2, #255 @ konstantasini kasr shaklida qo'shing
r0, r3, # 0xFF @ doimiyni o'n oltilik tizimga qo'shing

chunki 255 8 bit oralig'ida. Bu buyruqlar quyidagicha kompilyatsiya qilinadi:

0: e28200ff r0, r2, #255 qo'shing; 0xff
4: e28300ff r0, r3, # 255 qo'shing; 0xff

Va hatto yozishingiz mumkin

r0, r4, #512 qo'shing
r0, r5, 0x650000 qo'shing

Kompilyatsiya qilingan kod quyidagicha ko'rinadi:

0: e2840c02 r0, r4, #512 qo'shing; 0x200
4: e2850865 r0, r5, #6619136 qo'shing; 0x650000

Bunday holda, 512 raqamining o'zi, albatta, baytga to'g'ri kelmaydi. Ammo keyin biz uni 32'h00000200 o'n oltilik shaklida tasavvur qilamiz va bu 2 o'ngga 24 bitga kengaytirilganligini ko'ramiz (1 ror 24). Aylanish koeffitsienti 24 dan ikki baravar kichik, ya'ni 12. Shunday qilib, shifter_operand = ( 4’hc , 8'h02 ) chiqadi - bular buyruqning o'n ikkita eng kam ahamiyatli bitlari. Xuddi shu narsa 0x650000 raqamiga ham tegishli. Uning uchun shifter_operand = (4'h8, 8'h65).

Siz yoza olmasligingiz aniq

r0, r1, # 1234567 qo'shing

yoki yozolmaysiz

mov r0, #511

chunki bu erda raqamni imm_8 va encode_imm - aylanish omili shaklida ifodalash mumkin emas. Assembler kompilyatori xatoga yo'l qo'yadi.

Konstantani shifter_operand ga to'g'ridan-to'g'ri kodlash mumkin bo'lmaganda nima qilish kerak? Biz har xil nayranglar qilishimiz kerak.
Masalan, siz avval 512 raqamini bepul registrga yuklashingiz va keyin bittasini ayirishingiz mumkin:

mov r0, #511
sub r0,r0,#1

Muayyan raqamni registrga yuklashning ikkinchi usuli - uni xotirada joylashgan maxsus ajratilgan o'zgaruvchidan o'qish:

ldr r7, my_var
.....
my_var: .word 0x123456

Uni yozishning eng oson yo'li quyidagicha:

ldr r2,=511

Bunday holda ("=" belgisiga e'tibor bering), agar doimiy imm_8 va encode_imm sifatida ifodalanishi mumkin bo'lsa, shifter_operand ning 12-bitiga sig'ishi mumkin bo'lsa, montaj kompilyatori avtomatik ravishda ldr ni mov ko'rsatmalariga kompilyatsiya qiladi. Ammo agar raqamni bu tarzda ifodalab bo'lmasa, kompilyatorning o'zi ushbu doimiy uchun dasturda xotira katakchasini zahiraga oladi va o'zi bu xotira katakchasiga nom beradi va buyruqni ldr ga kompilyatsiya qiladi.

Bu men yozgan narsa:

ldr r7, my_var
ldr r8,=511
ldr r8,=1024
ldr r9,=0x3456
........
My_var: .word 0x123456

Kompilyatsiyadan keyin men buni oldim:

18: e59f7030 ldr r7, ; 50
1c: e59f8030 ldr r8, ; 54
20: e3a08b01 mov r8, # 1024; 0x400
24: e59f902c ldr r9, ; 58
.............
00000050 :
50: 00123456 .word 0x00123456
54: 000001ff .word 0x000001ff
58: 00003456 .word 0x00003456

E'tibor bering, kompilyator kompyuter registriga (aka r15) nisbatan xotira manzilini ishlatadi.

Xotira katakchasini o'qish va xotiraga registr yozish.

Yuqorida yozganimdek, ARM protsessori faqat registrlar mazmunida arifmetik yoki mantiqiy amallarni bajarishi mumkin. Operatsiyalar uchun ma'lumotlar xotiradan o'qilishi va operatsiyalar natijasi xotiraga qayta yozilishi kerak. Buning uchun maxsus buyruqlar mavjud: o'qish uchun ldr (ehtimol "LoaD Register" birikmasidan) va yozish uchun str (ehtimol "Store Register").

Faqat ikkita jamoa borga o'xshaydi, lekin aslida ular juda ko'p farqlarga ega. L 20, W 21, B 22, U 23, P 24, I 25 yordamchi bayroq bitlari borligini bilish uchun Amber ARM protsessorida ldr / str buyruqlari qanday kodlanganiga qarang va ular o'ziga xos harakatni aniqlaydi. buyruq:

  • Bit L 20 yozish yoki o'qishni aniqlaydi. 1 - ldr, o'qing, 0 - str, yozing.
  • B 22 bit 32 bitli so'z yoki 8 bitli baytni o'qish/yozishni aniqlaydi. 1 bayt operatsiyasini bildiradi. Bir bayt registrda o'qilganda, registrning eng muhim bitlari nolga qaytariladi.
  • Bit I 25 Ofset maydonidan foydalanishni aniqlaydi. Agar I 25 ==0 bo'lsa, u holda Offset raqamli ofset sifatida talqin qilinadi, uni registrdan asosiy manzilga qo'shish yoki olib tashlash kerak. Ammo qo'shish yoki ayirish U 23 bitiga bog'liq.

(Cond) - operatsiyani bajarish sharti. Mantiqiy/arifmetik buyruqlar bilan bir xil tarzda talqin qilinadi - o'qish yoki yozish shartli bo'lishi mumkin.

Shunday qilib, montaj matnida siz shunday yozishingiz mumkin:

ldr r1, @ r1 registriga r0 registridagi manzildagi so'zni o'qing
ldrb r1, @ r1 registriga r0 registridagi manzilda baytni o'qiydi
ldreq r2, @ shartli so'zlarni o'qish
ldrgtb r2, @ shartli baytni o'qish
ldr r3, @ r4 registridagi manzilga nisbatan 8-manzildagi so'zni o'qing
ldr r4, @ r5 registridagi manzilga nisbatan -16 manzilidagi so'zni o'qing

Ushbu matnni tuzgandan so'ng, siz ushbu buyruqlarning haqiqiy kodlarini ko'rishingiz mumkin:

0: e5901000 ldr r1,
4: e5d01000 ldrb r1,
8: 05912000 ldreq r2,
c: c5d12000 ldrbgt r2,
10: e5943008 ldr r3,
14: e5154010 ldr r4,

Yuqoridagi misolda men faqat ldr dan foydalanmoqdaman, lekin str xuddi shu tarzda ishlatiladi.

Indeksdan oldingi va indeksdan keyin qayta yozish xotirasiga kirish rejimlari mavjud. Ushbu rejimlarda xotiraga kirish ko'rsatkichi buyruq bajarilishidan oldin yoki keyin yangilanadi. Agar siz C dasturlash tilini yaxshi bilsangiz, u holda siz (( *psource++;) yoki ( a=*++ manba;). ARM protsessori ushbu xotiraga kirish rejimini amalga oshiradi. O'qish buyrug'i bajarilganda bir vaqtning o'zida ikkita registr yangilanadi - qabul qiluvchi registr xotiradan o'qilgan qiymatni oladi va ko'rsatkich registridagi qiymat xotira katagiga oldinga yoki orqaga siljiydi.

Bu buyruqlarni yozish, menimcha, biroz mantiqsiz. Ko'nikish uchun uzoq vaqt kerak bo'ladi.

ldr r3, ! @psrc++; r3 = *psrc;
ldr r3, , #4 @ r3 = *psrc; psrc++;

Birinchi ldr buyrug'i avval ko'rsatkichni oshiradi, keyin o'qiydi. Ikkinchi buyruq avval o'qiydi, keyin ko'rsatgichni oshiradi. psrc ko'rsatkichining qiymati r0 registrida joylashgan.

Yuqorida ko'rib chiqilgan barcha misollar buyruq kodidagi I 25 bit qayta o'rnatilganda edi. Lekin u hali ham o'rnatilishi mumkin! Keyin Ofset maydonining qiymati raqamli konstantani emas, balki operatsiyada ishtirok etuvchi uchinchi registrni o'z ichiga oladi. Bundan tashqari, uchinchi registrning qiymati hali ham oldindan o'zgartirilishi mumkin!

Bu erda mumkin bo'lgan kod o'zgarishlariga misollar:

0: e7921003 ldr r1, @ o'qish manzili - r2 va r3 registrlari qiymatlari yig'indisi
4: e7b21003 ldr r1, ! @ bir xil, lekin r2 o'qilgach, r3 dan qiymatga ortadi
8: e6932004 ldr r2, , r4 @ avval r3 manzilida o'qish bo'ladi, keyin r3 r4 ga ortadi.
c: e7943185 ldr r3, @ o'qish manzili r4+r5*8
10: e7b43285 ldr r3, ! @ o'qish manzili r4+r5*32, o'qilgandan so'ng r4 ushbu manzil qiymatiga o'rnatiladi
14: e69431a5 ldr r3, , r5, lsr #3 @ r4 ni o‘qish uchun manzil, r4 buyrug‘i bajarilgandan so‘ng r4+r5/8 ga o‘rnatiladi.

Bu ARM v2a protsessoridagi o'qish/yozish buyruqlarining o'zgarishlari.

ARM protsessorlarining eski modellarida bu xilma-xil buyruqlar yanada ko'proq.
Buning sababi, protsessor, masalan, nafaqat so'zlarni (32 bitli raqamlar) va baytlarni, balki yarim so'zlarni (16 bit, 2 bayt) o'qish imkonini beradi. Keyin ldr / str buyruqlariga yarim so'zdan "h" qo'shimchasi qo'shiladi. Buyruqlar ldrh yoki strh kabi ko'rinadi. Yarim so'zlarni yuklash uchun buyruqlar ham mavjud ldrsh yoki bayt ldrsb imzolangan raqamlar sifatida talqin qilinadi. Bunday hollarda yuklangan so'z yoki baytning eng muhim biti qabul qiluvchi registridagi butun so'zning eng muhim bitlariga ko'paytiriladi. Misol uchun, 0xff25 yarim so'zini maqsad registridagi ldrsh buyrug'i bilan yuklash 0xffffff25 ga olib keladi.

Ko'p o'qish va yozish.

Ldr /str buyruqlari xotiraga kirish uchun yagona buyruqlar emas. ARM protsessorida blokli uzatishni amalga oshirish imkonini beruvchi buyruqlar ham mavjud - siz bir vaqtning o'zida bir nechta ketma-ket so'zlarning mazmunini xotiradan va bir nechta registrlardan yuklashingiz mumkin. Shuningdek, siz bir nechta registrlarning qiymatlarini ketma-ket xotiraga yozishingiz mumkin.

Blokni uzatish buyrug'i mnemonikasi ldm (LoaD Multiple) yoki stm (Store Multiple) ildizidan boshlanadi. Ammo keyin, odatdagidek, ARMda, qo'shimchalar bilan hikoya boshlanadi.

Umuman olganda, buyruq quyidagicha ko'rinadi:

op(cond)(rejim) Rd(, {Register list} !}

Suffiks (Cond) tushunarli, bu buyruqni bajarish sharti. Suffiks (rejim) uzatish rejimi, bu haqda keyinroq. Rd - o'qish yoki yozish uchun xotiradagi asosiy manzilni aniqlaydigan registr. Undov belgisi registrdan keyin Rd o'qish/yozish operatsiyasidan keyin u o'zgartirilishini bildiradi. Xotiradan yuklangan yoki xotiraga sahifalangan registrlar ro'yxati (Registrlar ro'yxati).

Registrlar ro'yxatida ko'rsatilgan jingalak qavslar vergul yoki diapazon sifatida ajratiladi. Masalan:

stm r0,(r3,r1, r5-r8)

Xotira tartibsiz yoziladi. Ro'yxat oddiygina qaysi registrlar xotiraga yozilishini ko'rsatadi va bu. Buyruq kodi registrlar ro'yxati uchun ajratilgan 16 bitni o'z ichiga oladi, bu protsessor bankidagi registrlar soniga to'g'ri keladi. Bu sohadagi har bir bit operatsiyada qaysi registr ishtirok etishini bildiradi.

Endi o'qish/yozish rejimi haqida. Bu yerda chalkashlik uchun joy bor. Gap shundaki, bir xil harakat uchun turli rejim nomlaridan foydalanish mumkin.

Agar biz kichik lirik chekinadigan bo'lsak, unda biz ... stek haqida gapirishimiz kerak. Stack - bu LIFO tipidagi ma'lumotlarga kirish usuli - Oxirgi kiruvchi birinchi chiqish (wiki) - oxirgi kiruvchi, birinchi chiqadi. Stek dasturlashda protseduralarni chaqirishda va funksiyalarni kiritishda registrlar holatini saqlashda va chiqishda ularni tiklashda, shuningdek chaqirilgan protseduralarga parametrlarni o'tkazishda keng qo'llaniladi.

Kim o'ylagan bo'lsa, to'rt turdagi xotira steklari mavjud.

Birinchi tur - to'liq pasayish. Bu stek ko'rsatkichi egallangan stek elementiga ishora qilganda va stek kamayib borayotgan manzillar tomon o'sadi. Stekga so'z qo'yish kerak bo'lganda, avval stek ko'rsatkichi kamayadi (Decrement Before), so'ngra so'z stek ko'rsatgichining manziliga yoziladi. Kompyuter so'zini stekdan olib tashlash kerak bo'lganda, so'z stek ko'rsatgichining joriy qiymatidan foydalanib o'qiladi, keyin ko'rsatkich yuqoriga ko'tariladi (Increment After).

Ikkinchi tur - to'liq ko'tarilish. Stack pastga emas, balki kattaroq manzillar tomon o'sadi. Ko'rsatkich ham egallangan elementga ishora qiladi. Stakka so'z qo'yish kerak bo'lganda, avval stek ko'rsatkichi oshiriladi, keyin so'z ko'rsatkichga yoziladi (Increment Before). Stackdan olib tashlash kerak bo'lganda, siz avval stek ko'rsatkichini o'qiysiz, chunki u ishg'ol qilingan elementga ishora qiladi, keyin stek ko'rsatkichi kamayadi (Decrement After).

Uchinchi tur - bo'sh pasayish. To'liq pasayish holatidagi kabi stek pastga qarab o'sadi, lekin farq shundaki, stek ko'rsatkichi bo'sh hujayraga ishora qiladi. Shunday qilib, stekga so'z qo'yish kerak bo'lganda, darhol yozuv kiritiladi, keyin stek ko'rsatkichi kamayadi (Decrement After). Stackdan olib tashlashda ko'rsatgich birinchi navbatda oshiriladi, so'ngra o'qiladi (Increment before).

To'rtinchi tur - Bo'sh ko'tarilish. Umid qilamanki, hamma narsa aniq - stek yuqoriga qarab o'sadi. Stack ko'rsatkichi bo'sh elementga ishora qiladi. Stakka qo'yish stek ko'rsatgichining manziliga so'z yozishni va stek ko'rsatkichini oshirishni anglatadi (Increment After). Stackdan pop - stek ko'rsatkichini kamaytiring va so'zni o'qing (Decrement before).

Shunday qilib, stek ustida amallarni bajarayotganda, stek turiga qarab, ko'rsatkichni - (O'sish/Kamaytirish) xotiraga o'qish/yozishdan oldin yoki keyin (Before/After) oshirish yoki kamaytirish kerak. IN Intel protsessorlari, masalan, stek bilan ishlash uchun PUSH (stekga so'z qo'yish) yoki POP (stekdan so'zni chiqarish) kabi maxsus buyruqlar mavjud. ARM protsessorida maxsus ko'rsatmalar mavjud emas, lekin ldm va stm ko'rsatmalaridan foydalaniladi.

Agar siz stekni ARM protsessor ko'rsatmalari yordamida amalga oshirsangiz, quyidagi rasmni olasiz:

Nega bitta jamoaga turli nomlar berish kerak edi? Men umuman tushunmayapman ... Bu erda, albatta, ARM uchun stek standarti hali ham To'liq pasayishda ekanligini ta'kidlash kerak.

ARM protsessoridagi stek ko'rsatkichi sp yoki r13 registridir. Bu odatda kelishuv. Albatta, stm yozish yoki ldmni o'qish boshqa asosiy registrlar bilan ham amalga oshirilishi mumkin. Shu bilan birga, sp registrining boshqa registrlardan qanday farq qilishini eslab qolish kerak - u turli protsessor ish rejimlarida (USR, SVC, IRQ, FIRQ) har xil bo'lishi mumkin, chunki ularning o'z registr banklari mavjud.

Va yana bir eslatma. ARM yig'ish kodida shunday qatorni yozing surish(r0-r3), Albatta mumkin. Faqat haqiqatda bu bir xil jamoa bo'ladi stmfd sp!,(r0-r3).

Nihoyat, men montaj kodi va uning tuzilgan demontaj matniga misol keltiraman. Bizda ... bor:


stmfd sp!,(r0-r3)
stmdb sp!,(r0-r3)
surish (r0-r3)

@bu uchta ko'rsatmalar bir xil va xuddi shu narsani qiladi
pop(r0-r3)
ldmia sp!,(r0-r3)
ldmfd r13!,(r0-r3)

Stmfd r4,(r0-r3,r5,r8)
stmea r4!,(r0-r3,r7,r9,lr,kompyuter)
ldm r5, (r0, kompyuter)

Kompilyatsiyadan so'ng biz quyidagilarni olamiz:

0: e92d000f surish (r0, r1, r2, r3)
4: e92d000f surish (r0, r1, r2, r3)
8: e92d000f surish (r0, r1, r2, r3)
c: e8bd000f pop (r0, r1, r2, r3)
10: e8bd000f pop (r0, r1, r2, r3)
14: e8bd000f pop (r0, r1, r2, r3)
18: e904012f stmdb r4, (r0, r1, r2, r3, r5, r8)
1c: e8a4c28f stmia r4!, (r0, r1, r2, r3, r7, r9, lr, kompyuter)
20: e8958001 ldm r5, (r0, kompyuter)

Dasturlardagi o'tishlar.

O'tishlarsiz dasturlash mumkin emas. Har qanday dasturda kodning tsiklik bajarilishi, protsedura va funksiyalarni chaqirish, shuningdek kod bo'limlarini shartli bajarish mavjud.

Amber ARM v2a protsessorida faqat ikkita buyruq mavjud: b (Branch - filial, o'tish so'zidan) va bl (Branch with Link - qaytish manzilini saqlagan holda o'tish).

Buyruqning sintaksisi juda oddiy:

b (shart) belgisi
bl (shart) belgisi

Ko'rinib turibdiki, har qanday o'tish shartli bo'lishi mumkin, ya'ni dasturda "b" va "bl" ildizlaridan va shart qo'shimchalaridan (Cond) tuzilgan g'alati so'zlar bo'lishi mumkin:

beq, bne, bcs, bhs, bcc, blo, bmi, bpl, bvs, bvc, bhi, bls, bge, bgt, ble, bal, b

bleq, blne, blcs, blhs, blcc, bllo, blmi, blpl, blvs, blvc, blhi, blls, blge, blgt, blle, bla, bl

Turli xilligi ajoyib, shunday emasmi?

O'tish buyrug'i 24 bitli ofset ofsetini o'z ichiga oladi. O'tish manzili kompyuter ko'rsatkichining joriy qiymatining yig'indisi sifatida hisoblanadi va Ofset raqami chapga 2 bit siljiydi, imzolangan raqam sifatida talqin etiladi:

Yangi kompyuter = shaxsiy kompyuter + Ofset*4

Shunday qilib, o'tish diapazoni 32 MB oldinga yoki orqaga.

Qaytish manzilini bl saqlagan holda o'tish nima ekanligini ko'rib chiqaylik. Bu buyruq subprogrammalarni chaqirish uchun ishlatiladi. Ushbu buyruqning qiziqarli xususiyati shundaki, protsedurani chaqirishda protseduradan qaytish manzili Intel protsessorlaridagi kabi stekda emas, balki oddiy r14 registrida saqlanadi. Keyin, protseduradan qaytish uchun sizga xuddi shu Intel protsessorlari kabi maxsus ret buyrug'i kerak emas, lekin siz shunchaki r14 qiymatini kompyuteringizga nusxalashingiz mumkin. Endi r14 registrida nima uchun borligi aniq muqobil nom lr (Ro'yxatdan o'tish havolasi).

Keling, Amber SoC uchun salom-dunyo loyihasidan chiqish jarayonini ko'rib chiqaylik.

000004a0<_outbyte>:
4a0: e59f1454 ldr r1, ; 8fc< адрес регистра данных UART >
4a4: e59f3454 ldr r3, ; 900< адрес регистра статуса UART >
4a8: e5932000 ldr r2, ; joriy holatni o'qing
4ac: e2022020 va r2, r2, #32
4b0: e3520000 cmp r2, #0; UART band emasligini tekshiring
4b4: 05c10000 strbeq r0, ; UART ga faqat band bo'lmasa, belgi yozing
4b8: 01b0f00e movseq kompyuter, lr; agar UART band bo'lmasa, protseduradan shartli qaytish
4bc: 1afffff9 bne 4a8<_outbyte+0x8>; UART holatini tekshirish uchun pastadir

Menimcha, ushbu fragmentdagi sharhlardan ushbu protsedura qanday ishlashi aniq.

O'tish haqida yana bir muhim eslatma. Register r15 (kompyuter) oddiy arifmetik yoki mantiqiy operatsiyalarda maqsadli registr sifatida ishlatilishi mumkin. Shunday qilib, kompyuter, kompyuter, №8 qo'shish kabi buyruq boshqa manzilga o'tish uchun juda ko'rsatma.

O'tishlar haqida yana bir eslatma qilish kerak. Eski ARM protsessorlari ham mavjud qo'shimcha buyruqlar bx, blx va blj o'tishlari. Bular boshqa buyruqlar tizimi bilan kod bo'laklariga o'tish uchun buyruqlardir. Bx /blx ARM protsessorlarining 16-bitli THUMB kodiga o'tish imkonini beradi. Blj - bu Jazelle buyruqlar tizimining protsedura chaqiruvi (Java tilini qo'llab-quvvatlash ARM protsessorlari). Bizning Amber ARM v2a da bu buyruqlar mavjud emas.

Boshqa ARM protsessor ko'rsatmalari.

Agar xatolikni sezsangiz, matn qismini tanlang va Ctrl+Enter tugmalarini bosing
UMUSHISH: