ARM პროცესორის ინსტრუქციის ნაკრების შესწავლა. ARM პროცესორის ინსტრუქციების ნაკრების შესწავლა ARM ასამბლერის ინსტრუქციების მაგალითები

GBA ASM - დღე 2: ზოგიერთი ინფორმაცია ARM ასამბლერის შესახებ - არქივი WASM.RU

ARM არის კომპანია, რომელიც აწარმოებს GBA პროცესორს. ARM პროცესორები არის RISC პროცესორები (განსხვავებით INTEL პროცესორებისგან). RISC ნიშნავს შემცირებული ინსტრუქციების კომპლექტი კომპიუტერებს (CISC - კომპლექსი...). მიუხედავად იმისა, რომ ამ პროცესორებს არ აქვთ ბევრი ინსტრუქცია (რაც კარგია), ARM ინსტრუქციებს (და შესაძლოა სხვა RISC პროცესორებს, არ ვიცი) აქვთ მრავალი განსხვავებული დანიშნულება და კომბინაცია, რაც RISC პროცესორებს ისეთივე მძლავრს ხდის. .

რეგისტრირებს

სხვა ARM პროცესორების შესახებ არ ვიცი, მაგრამ GBA-ში გამოყენებულს აქვს 16 რეგისტრი და ინტელის (და სხვა) პროცესორებისგან განსხვავებით, ყველა რეგისტრის უსაფრთხოდ გამოყენება შესაძლებელია (ჩვეულებრივ). რეესტრები ასეთია:

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

ვაა! ბევრი! თანმიმდევრობით ავხსნი.

რო: გააკეთე რაც გინდა!

r2-დან r12-მდე: იგივე

r13: ზოგიერთ ARM სისტემაში, r13 არის სტეკის მაჩვენებელი (SP INTEL პროცესორებზე). დარწმუნებული არ ვარ, R13 თამაშობს თუ არა იგივე როლს GBA-ში, შემიძლია მხოლოდ გაგაფრთხილოთ, რომ ფრთხილად იყოთ სტეკთან მუშაობისას.

r14: შეიცავს მოწოდებული პროცედურების დაბრუნების მისამართს. თუ თქვენ არ იყენებთ მათ, მაშინ შეგიძლიათ გააკეთოთ ის, რაც გსურთ.

r15: პროგრამის მრიცხველი და დროშები, იგივე IP (Instruction Pointer in Intel-ში). ის განსხვავდება Intel-ის IP რეესტრისგან იმით, რომ თქვენ გაქვთ უფასო წვდომა მასზე, ისევე როგორც ნებისმიერ სხვა რეესტრში, მაგრამ გაითვალისწინეთ, რომ მისი შეცვლა გამოიწვევს კონტროლის გადატანას კოდის სხვა განყოფილებაში და დროშები შეიცვლება.

მოდით ცოტა მათემატიკა გავაკეთოთ... 16-ს გამოკლებული 3 (ჩვეულებრივ) გვაძლევს 13 რეგისტრს. მაგარია არა? დამშვიდდი.

ახლა თქვენ შეიძლება გაინტერესებთ რა არის რეალურად რეგისტრები. რეგისტრები მეხსიერების სპეციალური ადგილებია, რომლებიც პროცესორის ნაწილია და არ გააჩნიათ რეალური მისამართი, მაგრამ ცნობილია მხოლოდ მათი სახელებით. რეგისტრები არის 32 ბიტიანი. თითქმის ყველაფერი ნებისმიერ ასამბლეის ენაზე იყენებს რეგისტრებს, ასე რომ თქვენ უნდა იცოდეთ ისინი ისევე, როგორც თქვენი ახლობლები.

ARM ასამბლერის ინსტრუქციები

პირველ რიგში, მინდა დავიწყო იმით, რომ ჩემი აზრით, ვინც მოიფიქრა ARM ასამბლერი, არის გენიოსი.

მეორეც, მინდა წარმოგიდგინოთ ჩემი კარგი მეგობარი CMP. მიესალმე მას და იქნებ ისიც შენი მეგობარი გახდეს. CMP ნიშნავს CoMPare (შედარება). ამ ინსტრუქციას შეუძლია შეადაროს რეგისტრაცია და ნომერი, რეგისტრაცია და რეგისტრაცია, ან რეგისტრაცია და მეხსიერების მდებარეობა. შემდეგ, შედარების შემდეგ, CMP ადგენს სტატუსის დროშებს, რომლებიც გეტყვით შედარების შედეგს. როგორც გახსოვთ, რეგისტრაცია r15 შეიცავს დროშებს. ისინი აცხადებენ შედარების შედეგს. CMP ინსტრუქცია სპეციალურად შეიქმნა ამ დროშების მნიშვნელობის დასაყენებლად და სხვა არაფერი.

დროშები შეიძლება შეიცავდეს შემდეგ მდგომარეობებს:

    EQ თანაბარი / თანაბარი

    NE არ არის თანაბარი

    VS oVerflow კომპლექტი

    VC oVerflow გასუფთავება

    HI HIgher / Higher

    LS ქვედა ან იგივე / ქვემოთ ან იგივე

    PL PLus / Plus

    MI მინუს / მინუს

    CS Carry Set

    CC Carry Clear

    GE მეტი ან ტოლი / მეტი ან ტოლი

    GT უფრო მეტი ვიდრე / მეტი

    LE ნაკლები ან ტოლი / ნაკლები ან ტოლი

    LT ნაკლები / ნაკლები

    Z არის ნულოვანი / ნულოვანი

    NZ არ არის ნულოვანი / არა ნულოვანი

ეს სახელმწიფოები თამაშობენ ძალიან მნიშვნელოვან როლს ARM ასამბლერში.

შენიშვნა: დროშები ინახავს მხოლოდ პირობებს (ტოლი, ნაკლები და ა.შ.). ისინი აღარ არიან მნიშვნელოვანი.

მდგომარეობის სუფიქსები

თქვენ უკვე ნახეთ ინსტრუქცია B (ფილიალი). B ინსტრუქცია აკეთებს იმას, რასაც ეწოდება უპირობო ნახტომი (როგორიცაა GoTo Basic-ში ან JMP INTEL-ში). მაგრამ მას შეიძლება ჰქონდეს სუფიქსი (ერთ-ერთი ზემოთ ჩამოთვლილიდან), შემდეგ ის ამოწმებს ემთხვევა თუ არა მას დროშების მდგომარეობა. თუ არა, მაშინ გადახტომის ინსტრუქცია უბრალოდ არ არის შესრულებული. ასე რომ, თუ გსურთ შეამოწმოთ, არის თუ არა რეგისტრი r0 უდრის რეგისტრაციას r4 და შემდეგ გადადით ლეიბლზე, სახელად label34, მაშინ უნდა დაწეროთ შემდეგი კოდი:

    CMP r0, r4; ასამბლერში კომენტარები მოდის მძიმით (;)

    BEQ label34; B არის გადახტომის ინსტრუქცია და EQ არის სუფიქსის მნიშვნელობა

    ; "თუ თანაბარი"

შენიშვნა: Goldroad Assembler-ში, ეტიკეტებს არ სჭირდებათ თან ახლდეს ( და ხაზში არ უნდა იყოს არაფერი, გარდა ეტიკეტის სახელისა.

შენიშვნა II: არ არის აუცილებელი დაწეროთ CMP და BEQ დიდი ასოებით, ეს უბრალოდ თქვენთვის უფრო გასაგებად ხდება.

ახლა თქვენ იცით, როგორ გააკეთოთ გადასვლა დროშების მდგომარეობიდან გამომდინარე, მაგრამ რაც არ იცით არის ის, რომ დროშების მდგომარეობიდან გამომდინარე, შეგიძლიათ გააკეთოთ ყველაფერი, უბრალოდ დაამატეთ სასურველი სუფიქსი ნებისმიერ ინსტრუქციას!

ასევე, თქვენ არ გჭირდებათ CMP-ის გამოყენება დროშების მდგომარეობის დასაყენებლად. თუ გსურთ, მაგალითად, SUB (Subtract) ინსტრუქცია დროშების დასაყენებლად, დაამატეთ ინსტრუქციას სუფიქსი "S" (იგულისხმება "Set flags"). ეს სასარგებლოა, თუ არ გსურთ დროშების მდგომარეობის დაყენება დამატებითი CMP ინსტრუქციით, ასე რომ თქვენ შეგიძლიათ ამის გაკეთება და გადახტომა, თუ შედეგი იყო ნული, ასე:

    SUBS r0,r1,0x0FF ; აყენებს დროშებს შესრულების შედეგის მიხედვით

    ; ინსტრუქციები

    ldrZ r0,=0x0FFFF ; იტვირთება r0 რეგისტრი 0x0FFFF მხოლოდ იმ შემთხვევაში, თუ მდგომარეობა

    დროშები ნულის ტოლია.

მიმოხილვა

დღეს გავიგეთ (ცოტა მეტი) რეგისტრების შესახებ. ჩვენ ასევე გავიგეთ ARM ინსტრუქციების მოქნილობის შესახებ, რომელიც შეიძლება შესრულდეს (ან არ შესრულდეს) დროშების მდგომარეობიდან გამომდინარე. დღეს ბევრი რამ ვისწავლეთ.

ხვალ გამოვიყენებთ დღეს შეძენილ ARM ასამბლერის ცოდნას სურათის გამოსატანად GBA ეკრანზე.

რაღაც შეუძლებელი მხოლოდ ასეა, სანამ ის შესაძლებელი გახდება / ჟან-ლუკ პიკარი, კაპიტ. ,USS Enterprise/. მაიკ ჰ, ტრანს. აკვილა

CISC პროცესორები საკმაოდ რთულ ოპერაციებს ასრულებენ ერთ ინსტრუქციაში, მათ შორის არითმეტიკული და ლოგიკური ოპერაციები მეხსიერების უჯრედების შიგთავსზე. CISC პროცესორის ინსტრუქციებს შეიძლება ჰქონდეს განსხვავებული სიგრძე.

ამის საპირისპიროდ, RISC-ს აქვს შედარებით მარტივი ინსტრუქციის სისტემა, მკაფიო დაყოფით ოპერაციის ტიპის მიხედვით:

  • მეხსიერებასთან მუშაობა (მეხსიერებიდან რეგისტრებში კითხვა ან რეგისტრებიდან მეხსიერებაში ჩაწერა),
  • რეგისტრებში მონაცემების დამუშავება (არითმეტიკული, ლოგიკური, მონაცემების გადანაცვლება მარცხნივ/მარჯვნივ ან ბიტის როტაცია რეესტრში),
  • პირობითი ან უპირობო გადასვლის ბრძანებები სხვა მისამართებზე.

როგორც წესი (მაგრამ არა ყოველთვის და მხოლოდ იმ შემთხვევაში, თუ პროგრამის კოდი შედის კონტროლერის ქეში მეხსიერებაში), ერთი ინსტრუქცია შესრულებულია ერთი პროცესორის ციკლში. ARM პროცესორის ინსტრუქციის სიგრძე ფიქსირდება - 4 ბაიტი (ერთი კომპიუტერული სიტყვა). ფაქტობრივად, თანამედროვე ARM ​​პროცესორს შეუძლია გადავიდეს სხვა ოპერაციულ რეჟიმებზე, მაგალითად, THUMB რეჟიმში, როდესაც ინსტრუქციის სიგრძე ხდება 2 ბაიტი. ეს საშუალებას გაძლევთ გახადოთ კოდი უფრო კომპაქტური. თუმცა, ამ სტატიაში ჩვენ არ განვიხილავთ ამ რეჟიმს, რადგან ის არ არის მხარდაჭერილი Amber ARM v2a პროცესორში. ამავე მიზეზით, ჩვენ არ განვიხილავთ ისეთ რეჟიმებს, როგორიცაა Jazelle (ოპტიმიზირებულია Java კოდის შესასრულებლად) და არ განვიხილავთ NEON ბრძანებებს - ბრძანებებს ოპერაციებისთვის მრავალ მონაცემზე. ბოლოს და ბოლოს, ჩვენ ვსწავლობთ სუფთა ARM ინსტრუქციის სისტემას.

ARM პროცესორი რეგისტრირდება.

ARM პროცესორს აქვს რეგისტრების რამდენიმე კომპლექტი, რომელთაგან მხოლოდ 16 არის ხელმისაწვდომი პროგრამისტისთვის. არსებობს პროცესორის მუშაობის რეჟიმი, რომელიც დამოკიდებულია რეგისტრების შესაბამის ბანკზე. ეს ოპერაციული რეჟიმები:

  • განაცხადის რეჟიმი (USR, მომხმარებლის რეჟიმი),
  • ზედამხედველის რეჟიმი ან ოპერაციული სისტემის რეჟიმი (SVC, ზედამხედველი რეჟიმი),
  • შეწყვეტის დამუშავების რეჟიმი (IRQ, შეწყვეტის რეჟიმი) და
  • "გადაუდებელი შეფერხების" დამუშავების რეჟიმი (FIRQ, სწრაფი შეწყვეტის რეჟიმი).

ანუ, მაგალითად, როდესაც ხდება შეფერხება, თავად პროცესორი მიდის შეფერხების დამმუშავებლის პროგრამის მისამართზე და ავტომატურად „გამორთავს“ სარეგისტრაციო ბანკებს.

ძველი ვერსიების ARM პროცესორებს, ზემოაღნიშნული ოპერაციული რეჟიმების გარდა, აქვთ დამატებითი რეჟიმები:

  • შეწყვეტა (გამოიყენება მეხსიერებაზე წვდომის გამონაკლისების დასამუშავებლად),
  • განუსაზღვრელი (გამოიყენება პროგრამულ უზრუნველყოფაში კოპროცესორის დასანერგად) და
  • ოპერაციული სისტემის სისტემის პრივილეგირებული სამუშაო რეჟიმი.

Amber ARM v2a პროცესორს არ აქვს ეს დამატებითი სამი რეჟიმი.

Amber ARM v2a-სთვის, რეგისტრების ნაკრები შეიძლება წარმოდგენილი იყოს შემდეგნაირად:

რეგისტრები r0-r7 ერთნაირია ყველა რეჟიმისთვის.
რეგისტრები r8-r12 საერთოა მხოლოდ USR, SVC, IRQ რეჟიმებისთვის.
რეგისტრაცია r13 არის სტეკის მაჩვენებელი. ის თავისია ყველა რეჟიმში.
რეგისტრაცია r14 - დაბრუნების რეგისტრი ქვეპროგრამიდან ასევე განსხვავებულია ყველა რეჟიმში.
რეგისტრაცია r15 არის შესრულებადი ინსტრუქციების მაჩვენებელი. ის საერთოა ყველა რეჟიმისთვის.

ჩანს, რომ FIRQ რეჟიმი ყველაზე იზოლირებულია, მას აქვს ყველაზე მეტი საკუთარი რეგისტრი. ეს კეთდება ისე, რომ ზოგიერთი ძალიან კრიტიკული შეფერხება შეიძლება დამუშავდეს სტეკზე რეგისტრების შენახვის გარეშე, დროის დაკარგვის გარეშე.

განსაკუთრებული ყურადღება უნდა მიექცეს რეგისტრაციას r15, რომელიც ასევე ცნობილია როგორც pc (Program Counter) - შესრულებადი ბრძანებების მაჩვენებელი. თქვენ შეგიძლიათ შეასრულოთ სხვადასხვა არითმეტიკული და ლოგიკური მოქმედებები მის შინაარსზე, რითაც პროგრამის შესრულება გადავა სხვა მისამართებზე. თუმცა, სპეციალურად ARM v2a პროცესორისთვის, რომელიც დანერგილია Amber სისტემაში, არის გარკვეული დახვეწილობა ამ რეესტრის ბიტების ინტერპრეტაციაში.

ფაქტია, რომ ამ პროცესორში, რეესტრში r15 (pc), გარდა შესრულებადი ბრძანებების ფაქტობრივი მაჩვენებლისა, შეიცავს შემდეგ ინფორმაციას:

ბიტები 31:28 - დროშები არითმეტიკული ან ლოგიკური ოპერაციის შედეგისთვის
ბიტი 27 - შეწყვეტის IRQ ნიღაბი, შეფერხებები გამორთულია ბიტის დაყენებისას.
ბიტი 26 - FIRQ შეფერხების ნიღაბი, სწრაფი შეფერხებები გამორთულია ბიტის დაყენებისას.
ბიტი 25:2 - პროგრამის ინსტრუქციების რეალური მაჩვენებელი მხოლოდ 26 ბიტს იკავებს.
ბიტები 1:0 - მიმდინარე პროცესორის მუშაობის რეჟიმი.
3 - ზედამხედველი
2 - შეწყვეტა
1 - სწრაფი შეწყვეტა
0 - მომხმარებელი

ძველ ARM პროცესორებში, ყველა დროშა და სერვისის ბიტი განთავსებულია ცალკეულ რეესტრებში მიმდინარე პროგრამის სტატუსის რეგისტრაცია(cpsr) და შენახული პროგრამის სტატუსის რეესტრი (spsr), რომელთა წვდომისთვის არის ცალკე სპეციალური ბრძანებები. ეს კეთდება პროგრამებისთვის ხელმისაწვდომი მისამართების სივრცის გასაფართოებლად.

ARM ასამბლერის დაუფლების ერთ-ერთი სირთულე არის ზოგიერთი რეგისტრის ალტერნატიული სახელები. ასე რომ, როგორც ზემოთ აღინიშნა, r15 არის იგივე კომპიუტერი. ასევე არის r13 - ეს არის იგივე sp (Stack Pointer), r14 არის lr (Link Register) - დაბრუნების მისამართის რეგისტრი პროცედურადან. გარდა ამისა, r12 არის იგივე ip (Intra-Procedure -call scratch register), რომელსაც იყენებენ C შემდგენელები სპეციალური გზით სტეკის პარამეტრებზე წვდომისათვის. ასეთი ალტერნატიული დასახელება ზოგჯერ დამაბნეველია, როდესაც უყურებთ სხვისი პროგრამის კოდს - რეგისტრის ორივე აღნიშვნა იქ არის ნაპოვნი.

კოდის შესრულების მახასიათებლები.

მრავალი ტიპის პროცესორში (მაგალითად, x86), მხოლოდ სხვა პროგრამის მისამართზე გადასვლა შეიძლება შესრულდეს პირობით. ARM-ის შემთხვევაში ასე არ არის. ARM პროცესორის თითოეული ინსტრუქცია შეიძლება იყოს ან არ შესრულდეს პირობითად. ეს საშუალებას გაძლევთ მინიმუმამდე დაიყვანოთ პროგრამის მეშვეობით გადასვლების რაოდენობა და, შესაბამისად, უფრო ეფექტურად გამოიყენოთ პროცესორის მილსადენი.

ბოლოს და ბოლოს, რა არის მილსადენი? ერთი პროცესორის ინსტრუქცია ახლა არჩეულია პროგრამის კოდიდან, წინა უკვე დეკოდირებულია და წინა უკვე შესრულებულია. ეს არის Amber A23 პროცესორის 3-საფეხურიანი მილსადენის შემთხვევა, რომელსაც ვიყენებთ ჩვენს პროექტში Mars Rover2Mars Rover2 დაფისთვის. Amber A25 პროცესორის მოდიფიკაციას აქვს 5 საფეხურიანი მილსადენი, ის კიდევ უფრო ეფექტურია. მაგრამ, არის ერთი დიდი მაგრამ. გადახტომის ბრძანებები აიძულებს პროცესორს გაწმინდოს მილსადენი და შეავსოს იგი. ამრიგად, არჩეულია ახალი ბრძანება, მაგრამ ჯერ კიდევ არაფერია გასაშიფრი და, განსაკუთრებით, არაფერია დაუყოვნებლივ შესასრულებელი. კოდის შესრულების ეფექტურობა მცირდება ხშირი გადასვლებით. თანამედროვე პროცესორებს აქვთ ყველა სახის განშტოების პროგნოზირების მექანიზმები, რომლებიც გარკვეულწილად ოპტიმიზაციას უკეთებენ მილსადენის შევსებას, მაგრამ ჩვენს პროცესორს ეს არ აქვს. ნებისმიერ შემთხვევაში, ARM ბრძნული იყო, რომ შესაძლებელი ყოფილიყო თითოეული ბრძანების პირობითად შესრულება.

ARM პროცესორზე, ნებისმიერი ტიპის ინსტრუქციაში, ინსტრუქციის შესრულების პირობის ოთხი ბიტი დაშიფრულია ინსტრუქციის კოდის უმაღლეს ოთხ ბიტში:

პროცესორში სულ 4 მდგომარეობის დროშაა:
. უარყოფითი - ოპერაციის შედეგი იყო უარყოფითი,
. ნულოვანი - შედეგი არის ნული,
. Carry - ტარება მოხდა ოპერაციების შესრულებისას ხელმოუწერელი ნომრებით,
. oVerflow - გადინება მოხდა ხელმოწერილი ნომრებით ოპერაციის შესრულებისას, შედეგი არ ჯდება რეესტრში)

ეს 4 დროშა ქმნის მრავალი შესაძლო მდგომარეობის კომბინაციას:

კოდი სუფიქსი მნიშვნელობა დროშები
4"h0 ეკვ თანაბარი Z კომპლექტი
4"სთ1 ნე არა თანაბარი Z ნათელი
4"სთ2 cs/hs ატარეთ კომპლექტი / ხელმოუწერელი უფრო მაღალი ან იგივე C კომპლექტი
4"h3 cc/lo ატარეთ მკაფიო / ხელმოუწერელი ქვედა C ნათელი
4"h4 მი მინუს/უარყოფითი N კომპლექტი
4"h5 pl პლუს / დადებითი ან ნულოვანი N ნათელი
4"h6 vs გადინება V კომპლექტი
4"h7 ვკ არავითარი გადინება V ნათელი
4"h8 გამარჯობა ხელმოუწერელი უფრო მაღალი C კომპლექტი და Z წმინდა
4"h9 ls ხელმოუწერელი ქვედა ან იგივე C წმინდა ან Z კომპლექტი
4" ჰა ge ხელმოწერილია მეტი ან ტოლი N == V
4"ჰბ ხელმოწერილი ნაკლები N != V
4"hc GT ხელმოწერილი აღემატება Z == 0,N == V
4" HD ლე ხელმოწერილია ნაკლები ან თანაბარი Z == 1 ან N != V
4" ის ალ ყოველთვის (უპირობო)
4"ჰფ - არასწორი მდგომარეობა

ახლა ეს იწვევს სხვა სირთულეს ARM პროცესორის ინსტრუქციების სწავლაში - მრავალი სუფიქსი, რომელიც შეიძლება დაემატოს ინსტრუქციის კოდს. მაგალითად, დამატება იმ პირობით, რომ Z დროშა დაყენებულია არის ბრძანება addeq როგორც add + სუფიქსი eq. გადადით ქვეპროგრამაზე, თუ დროშა N=0 არის blpl, როგორც bl + სუფიქსი pl.

დროშები (უარყოფითი, ნულოვანი, ტარება, oVerflow)იგივე ყოველთვის არ არის მითითებული არითმეტიკული ან ლოგიკური ოპერაციების დროს, როგორც ეს ხდება, ვთქვათ, x86 პროცესორში, მაგრამ მხოლოდ მაშინ, როცა პროგრამისტს სურს. ამისათვის არის ბრძანების mnemonics კიდევ ერთი სუფიქსი: "s" (ბრძანების კოდში ის კოდირებულია ბიტით 20). ამრიგად, დამატების ბრძანება არ ცვლის დროშებს, მაგრამ adds ბრძანება ცვლის დროშებს. ან შეიძლება ასევე იყოს პირობითი დამატების ბრძანება, რომელიც ცვლის დროშებს. მაგალითად: addgts. ნათელია, რომ ბრძანებების სახელების შესაძლო კომბინაციების რაოდენობა სხვადასხვა სუფიქსებით პირობითი შესრულებისა და დროშების დასაყენებლად ხდის ARM პროცესორის შეკრების კოდს ძალიან თავისებურს და რთულად წასაკითხს. თუმცა დროთა განმავლობაში ეჩვევი და იწყებ ამ ტექსტის გაგებას.

არითმეტიკული და ლოგიკური ოპერაციები (Data Processing).

ARM პროცესორს შეუძლია შეასრულოს სხვადასხვა არითმეტიკული და ლოგიკური ოპერაციები.

ფაქტობრივი ოთხბიტიანი ოპერაციის კოდი (Opcode) შეიცავს პროცესორის ინსტრუქციის ბიტებს.

ნებისმიერი ოპერაცია ხორციელდება რეესტრის შიგთავსზე და ე.წ. shifter_operand. ოპერაციის შედეგი იდება რეესტრში. ოთხბიტიანი Rn და Rd არის რეგისტრების ინდექსები პროცესორის აქტიურ ბანკში.

I 25 ბიტიდან გამომდინარე, shifter_operand განიხილება როგორც რიცხვითი მუდმივი, ან როგორც ოპერანდის მეორე რეგისტრის ინდექსი, და კიდევ ცვლა ოპერაცია მეორე ოპერანდის მნიშვნელობაზე.

ასამბლერის ბრძანებების მარტივი მაგალითები ასე გამოიყურება:

დაამატეთ r0,r1,r2 @ ჩადეთ რეგისტრების r1 და r2 მნიშვნელობების ჯამი რეგისტრში r0
sub r5,r4,#7 @ მოათავსეთ სხვაობა (r4-7) რეგისტრში r5

შესრულებული ოპერაციები დაშიფრულია შემდეგნაირად:

4"h0 და ლოგიკური AND Rd:= Rn და shifter_operand
4"h1 eor ლოგიკური ექსკლუზიური OR Rd:= Rn XOR shifter_operand
4"h2 ქვე არითმეტიკული გამოკლება Rd:= Rn - shifter_operand
4"h3 rsb არითმეტიკული შებრუნებული გამოკლება Rd:= shifter_operand - Rn
4"h4 დაამატეთ არითმეტიკული დამატება Rd:= Rn + shifter_operand
4"h5 adc არითმეტიკული შეკრება პლუს ტარების დროშა Rd:= Rn + shifter_operand + Carry Flag
4"h6 sbc არითმეტიკული გამოკლება გადატანით Rd:= Rn - shifter_operand - NOT(Carry Flag)
4"h7 rsc არითმეტიკული საპირისპირო გამოკლება გადატანით Rd:= shifter_operand - Rn - NOT(Carry Flag)
4"h8 tst ლოგიკური AND, მაგრამ შედეგის შენახვის გარეშე, იცვლება მხოლოდ დროშები Rn და shifter_operand S ბიტი ყოველთვის დაყენებული
4"h9 teq ლოგიკური ექსკლუზიური OR, მაგრამ შედეგის შენახვის გარეშე, იცვლება მხოლოდ დროშები Rn EOR shifter_operand
S ბიტი ყოველთვის დაყენებულია
4"ჰა cmp შედარება, უფრო სწორად არითმეტიკული გამოკლება შედეგის შენახვის გარეშე, იცვლება მხოლოდ Rn დროშები - shifter_operand S ბიტი ყოველთვის მითითებულია
4"hb cmn შებრუნებული, უფრო სწორად არითმეტიკული მიმატების შედარება შედეგის შენახვის გარეშე, მხოლოდ დროშები Rn + shifter_operand S ბიტი ყოველთვის აყენებს ცვლილებას
4"hc orr ლოგიკური OR Rd:= Rn ან shifter_operand
4"hd mov კოპირების მნიშვნელობა Rd:= shifter_operand (პირველი ოპერანდი არ არის)
4"he bic გადატვირთეთ ბიტები Rd:= Rn AND NOT(shifter_operand)
4"hf mvn დააკოპირეთ ინვერსიული მნიშვნელობა Rd:= NOT shifter_operand (პირველი ოპერანდი არ არის)

ლულის გადამრთველი.

ARM პროცესორს აქვს სპეციალური "ლულის გადამრთველი" წრე, რომელიც საშუალებას აძლევს ერთ-ერთ ოპერანდს გადაიტანოს ან შემობრუნდეს გარკვეული რაოდენობის ბიტით ნებისმიერი არითმეტიკული ან ლოგიკური ოპერაციის წინ. ეს არის პროცესორის საკმაოდ საინტერესო თვისება, რომელიც საშუალებას გაძლევთ შექმნათ ძალიან ეფექტური კოდი.

მაგალითად:

@9-ზე გამრავლება არის რიცხვის 8-ზე გამრავლება
@ მარცხნივ გადაადგილებით 3 ბიტით პლუს სხვა რიცხვი
დაამატეთ r0, r1, r1, lsl #3 @ r0= r1+(r1<<3) = r1*9

@ გამრავლება 15-ზე არის გამრავლება 16-ზე გამოკლებული რიცხვი
rsb r0, r1, r1, lsl #4 @ r0= (r1<<4)-r1 = r1*15

@ წვდომა ცხრილზე 4 ბაიტიანი სიტყვით, სადაც
@r1 არის ცხრილის ძირითადი მისამართი
@r2 არის ცხრილის ელემენტის ინდექსი
ldr r0,

გარდა ლოგიკური მარცხნივ ცვლა lsl, ასევე არსებობს ლოგიკური ცვლა მარჯვნივ lsr და არითმეტიკული მარჯვნივ ცვლა asr (ნიშნის შენარჩუნების ცვლა, ყველაზე მნიშვნელოვანი ბიტი მრავლდება მარცხნივ ცვლასთან ერთად).

ასევე ხდება როის ბიტების ბრუნვა - ბიტები მოძრაობენ მარჯვნივ, ხოლო ამოღებული - მარცხნივ.
არის ერთი ბიტიანი ცვლა C დროშის მეშვეობით - ეს არის rrx ბრძანება. რეგისტრის მნიშვნელობა ერთი ბიტით არის გადატანილი მარჯვნივ. მარცხნივ, C დროშა იტვირთება რეესტრის ყველაზე მნიშვნელოვან ბიტში.

ცვლა შეიძლება განხორციელდეს არა ფიქსირებული მუდმივი რიცხვით, არამედ მესამე ოპერანდის რეგისტრის მნიშვნელობით. მაგალითად:

დაამატეთ r0, r1, r1, lsr r3 @ ეს არის r0 = r1 + (r1>>r3);
დაამატეთ r0, r0, r1, lsr r3 @ ეს არის r0 = r0 + (r1>>r3);

ასე რომ, shifter_operand არის ის, რასაც ჩვენ აღვწერთ ასამბლერის ბრძანებებში, მაგალითად, როგორც "r1, lsr r3" ან "r2, lsl #5".

ყველაზე საინტერესო ის არის, რომ ოპერაციებში ცვლილებების გამოყენება არ ღირს. ეს ცვლილებები (ჩვეულებრივ) არ საჭიროებს დამატებით საათის ციკლებს, რაც ძალიან კარგია სისტემის მუშაობისთვის.

რიცხვითი ოპერანდების გამოყენება.

არითმეტიკული ან ლოგიკური მოქმედებები შეიძლება გამოიყენონ არა მხოლოდ რეგისტრის შინაარსი, არამედ რიცხვითი მუდმივიც, როგორც მეორე ოპერანდი.

სამწუხაროდ, აქ არის ერთი მნიშვნელოვანი შეზღუდვა. ვინაიდან ყველა ბრძანებას აქვს ფიქსირებული სიგრძე 4 ბაიტი (32 ბიტი), შეუძლებელი იქნება მასში "ნებისმიერი" ნომრის დაშიფვრა. ოპერაციის კოდში 4 ბიტი უკვე დაკავებულია შესრულების პირობის კოდით (Cond), 4 ბიტი თავად ოპერაციის კოდისთვის (Opcode), შემდეგ 4 ბიტი - მიმღების რეგისტრი Rd და კიდევ 4 ბიტი - პირველი ოპერანდის რეგისტრი. Rn, პლუს სხვადასხვა დროშები I 25 (უბრალოდ ნიშნავს ციფრულ მუდმივას ოპერაციის კოდში) და S 20 (დროშების დაყენება ოპერაციის შემდეგ). საერთო ჯამში, დარჩენილია მხოლოდ 12 ბიტი შესაძლო მუდმივისთვის, ე.წ. shifter_operand - ეს ზემოთ ვნახეთ. ვინაიდან 12 ბიტს შეუძლია რიცხვების დაშიფვრა მხოლოდ ვიწრო დიაპაზონში, ARM პროცესორის დეველოპერებმა გადაწყვიტეს მუდმივის დაშიფვრა შემდეგნაირად. shifter_operand-ის თორმეტი ბიტი იყოფა ორ ნაწილად: ოთხბიტიანი ბრუნვის მაჩვენებელი encode_imm და რვა ბიტიანი ფაქტობრივი რიცხვითი მნიშვნელობა imm_8.

ARM პროცესორზე მუდმივი განისაზღვრება, როგორც რვა-ბიტიანი რიცხვი 32-ბიტიან რიცხვში, რომელიც ბრუნავს მარჯვნივ ბიტების ლუწი რაოდენობით. ანუ:

imm_32 = imm_8 ROR (encode_imm *2)

საკმაოდ სახიფათო აღმოჩნდა. გამოდის, რომ ყველა მუდმივი რიცხვის გამოყენება არ შეიძლება ასამბლერის ბრძანებებში.

შეგიძლიათ დაწეროთ

დაამატეთ r0, r2, #255 @ მუდმივი ათობითი ფორმით
დაამატეთ r0, r3, #0xFF @ მუდმივი თექვსმეტობით

ვინაიდან 255 არის 8 ბიტიან დიაპაზონში. ეს ბრძანებები შედგენილი იქნება შემდეგნაირად:

0: e28200ff დაამატეთ r0, r2, #255; 0xff
4: e28300ff დაამატეთ r0, r3, #255; 0xff

და შეგიძლია დაწერო კიდეც

დაამატეთ r0, r4, #512
დაამატეთ r0, r5, 0x650000

შედგენილი კოდი ასე გამოიყურება:

0: e2840c02 დაამატეთ r0, r4, #512; 0x200
4: e2850865 დაამატეთ r0, r5, #6619136; 0x650000

ამ შემთხვევაში, თავად ნომერი 512, რა თქმა უნდა, არ ჯდება ბაიტში. მაგრამ შემდეგ ჩვენ წარმოვიდგენთ მას თექვსმეტობით ფორმაში 32'h00000200 და ვხედავთ, რომ ეს არის 2 გაფართოებული მარჯვნივ 24 ბიტით (1 ror 24). ბრუნვის კოეფიციენტი ორჯერ ნაკლებია 24-ზე, ანუ 12-ზე. ასე რომ, გამოდის shifter_operand = ( 4’hc , 8’h02 ) - ეს არის ბრძანების თორმეტი ყველაზე ნაკლებად მნიშვნელოვანი ბიტი. იგივე ეხება რიცხვს 0x650000. მისთვის shifter_operand = (4'h8, 8'h65).

გასაგებია რომ ვერ წერ

დაამატეთ r0, r1, #1234567

ან ვერ წერ

mov r0, #511

ვინაიდან აქ რიცხვი არ შეიძლება იყოს წარმოდგენილი imm_8 და encode_imm - ბრუნვის ფაქტორის სახით. ასამბლერის შემდგენელი შეცდომას გაუშვებს.

რა უნდა გავაკეთოთ, როდესაც მუდმივი არ შეიძლება პირდაპირ კოდირდეს shifter_operand-ში? ჩვენ მოგვიწევს ყველა სახის ხრიკის გაკეთება.
მაგალითად, შეგიძლიათ ჯერ ჩატვირთოთ ნომერი 512 თავისუფალ რეესტრში და შემდეგ გამოაკლოთ ერთი:

mov r0, #511
ქვე r0,r0,#1

კონკრეტული ნომრის რეესტრში ჩატვირთვის მეორე გზა არის მისი წაკითხვა სპეციალურად დაჯავშნილი ცვლადიდან, რომელიც მდებარეობს მეხსიერებაში:

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

მისი დაწერის ყველაზე მარტივი გზა ასეთია:

ldr r2,=511

ამ შემთხვევაში (გაითვალისწინეთ "=" ნიშანი), თუ მუდმივი შეიძლება იყოს წარმოდგენილი, როგორც imm_8 და encode_imm , თუ ის ჯდება shifter_operand-ის მე-12 ბიტში, მაშინ ასამბლეის შემდგენელი ავტომატურად აკომპლექტებს ldr-ს mov ინსტრუქციაში. მაგრამ თუ რიცხვი ასე ვერ იქნება წარმოდგენილი, მაშინ შემდგენელი თავად იტოვებს მეხსიერების უჯრედს პროგრამაში ამ მუდმივისთვის და თავად მისცემს ამ მეხსიერების უჯრედს სახელს და აკომპლექტებს ბრძანებას ldr-ში.

აი ეს დავწერე:

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

შედგენის შემდეგ მივიღე ეს:

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

გაითვალისწინეთ, რომ შემდგენელი იყენებს მეხსიერების მისამართებს კომპიუტერის რეესტრთან შედარებით (aka r15).

მეხსიერების უჯრედის წაკითხვა და მეხსიერებაში რეგისტრის ჩაწერა.

როგორც ზემოთ დავწერე, ARM პროცესორს შეუძლია მხოლოდ არითმეტიკული ან ლოგიკური ოპერაციების შესრულება რეგისტრების შინაარსზე. ოპერაციების მონაცემები უნდა წაიკითხოს მეხსიერებიდან და ოპერაციების შედეგები კვლავ უნდა ჩაიწეროს მეხსიერებაში. ამისათვის არის სპეციალური ბრძანებები: ldr (ალბათ კომბინაციიდან "LoaD Register") წასაკითხად და str (ალბათ "Store Register") ჩაწერისთვის.

როგორც ჩანს, მხოლოდ ორი გუნდია, მაგრამ სინამდვილეში მათ ბევრი ვარიაცია აქვთ. უბრალოდ შეხედეთ როგორ არის კოდირებული ldr/str ბრძანებები Amber ARM პროცესორზე, რომ ნახოთ რამდენი დამხმარე ბიტია L 20, W 21, B 22, U 23, P 24, I 25 - და ისინი განსაზღვრავენ სპეციფიკურ ქცევას. ბრძანება:

  • ბიტი L 20 განსაზღვრავს ჩაწერას ან წაკითხვას. 1 - ldr, წაიკითხეთ, 0 - str, ჩაწერეთ.
  • ბიტი B 22 განსაზღვრავს 32-ბიტიანი სიტყვის ან 8-ბიტიანი ბაიტის წაკითხვას/ჩაწერას. 1 ნიშნავს ბაიტის ოპერაციას. როდესაც ბაიტი იკითხება რეესტრში, რეგისტრის ყველაზე მნიშვნელოვანი ბიტები აღდგება ნულამდე.
  • ბიტი I 25 განსაზღვრავს Offset ველის გამოყენებას. თუ I 25 ==0, მაშინ Offset ინტერპრეტირებულია, როგორც რიცხვითი ოფსეტი, რომელიც ან უნდა დაემატოს საბაზისო მისამართს რეესტრიდან ან გამოკლდეს. მაგრამ შეკრება ან გამოკლება დამოკიდებულია U 23 ბიტზე.

(კონდი) - პირობა ოპერაციის ჩატარებისთვის. ინტერპრეტირებულია ისევე, როგორც ლოგიკური/არითმეტიკული ბრძანებებისთვის - კითხვა ან წერა შეიძლება იყოს პირობითი.

ამრიგად, ასამბლეის ტექსტში შეგიძლიათ დაწეროთ მსგავსი რამ:

ldr r1, @ რეგისტრში r1 წაიკითხეთ სიტყვა მისამართზე r0 რეგისტრიდან
ldrb r1, @ რეგისტრში r1 წაიკითხეთ ბაიტი მისამართზე r0 რეესტრიდან
ldreq r2, @ პირობითი სიტყვის კითხვა
ldrgtb r2, @ პირობითი ბაიტის წაკითხვა
ldr r3, @ წაიკითხეთ სიტყვა მე-8 მისამართზე მისამართთან შედარებით r4 რეგისტრიდან
ldr r4, @ წაიკითხეთ სიტყვა მისამართზე -16 მისამართთან შედარებით r5 რეგისტრიდან

ამ ტექსტის შედგენის შემდეგ, შეგიძლიათ იხილოთ ამ ბრძანებების რეალური კოდები:

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

ზემოთ მოყვანილ მაგალითში მე მხოლოდ ldr-ს ვიყენებ, მაგრამ str გამოიყენება დაახლოებით იგივე გზით.

არსებობს წინასწარი და ინდექსის შემდგომ ჩაწერის მეხსიერების წვდომის რეჟიმები. ამ რეჟიმებში მეხსიერების წვდომის მაჩვენებელი განახლდება ინსტრუქციის შესრულებამდე ან მის შემდეგ. თუ იცნობთ C პროგრამირების ენას, მაშინ იცნობთ მაჩვენებლის წვდომის კონსტრუქციებს, როგორიცაა ( *წყარო ++;) ან ( a=*++ წყარო;). ARM პროცესორი ახორციელებს მეხსიერების წვდომის ამ რეჟიმს. წაკითხვის ბრძანების შესრულებისას, ორი რეგისტრი ერთდროულად განახლდება - მიმღების რეგისტრი იღებს წაკითხულ მნიშვნელობას მეხსიერებიდან და მაჩვენებლის რეესტრის მნიშვნელობა მეხსიერების უჯრედში გადაადგილდება წინ ან უკან.

ამ ბრძანებების დაწერა, ჩემი აზრით, გარკვეულწილად ალოგიკურია. შეგუებას დიდი დრო სჭირდება.

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

პირველი ldr ბრძანება ჯერ ზრდის მაჩვენებელს, შემდეგ კითხულობს. მეორე ბრძანება ჯერ კითხულობს, შემდეგ ზრდის მაჩვენებელს. psrc მაჩვენებლის მნიშვნელობა არის რეგისტრში r0.

ყველა ზემოთ განხილული მაგალითი იყო იმ შემთხვევისთვის, როდესაც ბრძანების კოდის I 25 ბიტი გადატვირთული იყო. მაგრამ ის მაინც შეიძლება დაინსტალირდეს! მაშინ Offset ველის მნიშვნელობა არ შეიცავს ციფრულ მუდმივას, არამედ ოპერაციაში მონაწილე მესამე რეგისტრს. უფრო მეტიც, მესამე რეესტრის ღირებულება ჯერ კიდევ შეიძლება წინასწარ გადაიტანოს!

აქ მოცემულია კოდის შესაძლო ვარიაციების მაგალითები:

0: e7921003 ldr r1, @ წაკითხვის მისამართი - მნიშვნელობების ჯამი რეგისტრებიდან r2 და r3
4: e7b21003 ldr r1, ! @ იგივე, მაგრამ წაკითხვის შემდეგ r2 გაიზრდება r3-დან მნიშვნელობით
8: e6932004 ldr r2, , r4 @ ჯერ იქნება წაკითხვა r3 მისამართზე და შემდეგ r3 გაიზრდება r4-ით
c: e7943185 ldr r3, @ წაიკითხეთ მისამართი r4+r5*8
10: e7b43285 ldr r3, ! @ read მისამართი r4+r5*32, წაკითხვის შემდეგ r4 დაყენდება ამ მისამართის მნიშვნელობაზე
14: e69431a5 ldr r3, , r5, lsr #3 @ მისამართი r4-ის წასაკითხად, ბრძანების შესრულების შემდეგ, r4 დაყენდება r4+r5/8

ეს არის წაკითხვის/ჩაწერის ბრძანებების ვარიაციები ARM v2a პროცესორში.

ARM პროცესორების ძველ მოდელებში ბრძანებების ეს მრავალფეროვნება კიდევ უფრო დიდია.
ეს გამოწვეულია იმით, რომ პროცესორი საშუალებას აძლევს, მაგალითად, წაიკითხოს არა მხოლოდ სიტყვები (32-ბიტიანი რიცხვები) და ბაიტები, არამედ ნახევრად სიტყვები (16 ბიტი, 2 ბაიტი). შემდეგ ldr / str ბრძანებებს ემატება სუფიქსი „h“, სიტყვიდან ნახევარი სიტყვა. ბრძანებები გამოიყურება როგორც ldrh ან strh. ასევე არსებობს ბრძანებები ნახევარი სიტყვების ჩატვირთვის ldrsh ან ბაიტი ldrsb ინტერპრეტირებული როგორც ხელმოწერილი რიცხვები. ამ შემთხვევაში, დატვირთული სიტყვასიტყვის ან ბაიტის ყველაზე მნიშვნელოვანი ბიტი მრავლდება მიმღების რეესტრში მთელი სიტყვის ყველაზე მნიშვნელოვან ბიტებზე. მაგალითად, ნახევარსიტყვის 0xff25 ჩატვირთვა ldrsh ბრძანებით დანიშნულების რეესტრში იწვევს 0xffffff25-ს.

მრავალი კითხვა და წერა.

ldr /str ბრძანებები არ არის ერთადერთი მეხსიერებაში წვდომისთვის. ARM პროცესორს ასევე აქვს ბრძანებები, რომლებიც საშუალებას გაძლევთ შეასრულოთ ბლოკის გადაცემა - შეგიძლიათ ჩატვირთოთ რამდენიმე თანმიმდევრული სიტყვის შინაარსი მეხსიერებიდან და რამდენიმე რეგისტრი ერთდროულად. თქვენ ასევე შეგიძლიათ ჩაწეროთ რამდენიმე რეგისტრის მნიშვნელობები თანმიმდევრულად მეხსიერებაში.

ბლოკის გადაცემის ბრძანება mnemonics იწყება root ldm (LoaD Multiple) ან stm (Store Multiple). მაგრამ შემდეგ, როგორც ყოველთვის ARM-ში, იწყება ისტორია სუფიქსებით.

ზოგადად, ბრძანება ასე გამოიყურება:

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

სუფიქსი (Cond) გასაგებია, ეს არის ბრძანების შესრულების პირობა. სუფიქსი (რეჟიმი) არის გადაცემის რეჟიმი, ამაზე მოგვიანებით. Rd არის რეგისტრი, რომელიც განსაზღვრავს მეხსიერების საბაზისო მისამართს წაკითხვის ან ჩაწერისთვის. ძახილის ნიშანი Rd რეგისტრის შემდეგ მიუთითებს, რომ ის შეიცვლება წაკითხვის/ჩაწერის ოპერაციის შემდეგ. რეგისტრების სია, რომლებიც იტვირთება მეხსიერებიდან ან გვერდში დევს მეხსიერებაში, არის (რეგისტრაციის სია).

რეგისტრების სია მითითებულია მძიმით ან დიაპაზონის სახით გამოყოფილი ხვეული ფრჩხილებით. მაგალითად:

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

მეხსიერება უწესრიგოდ ჩაიწერება. სია უბრალოდ მიუთითებს რომელი რეგისტრები ჩაიწერება მეხსიერებაში და ეს არის ის. ბრძანების კოდი შეიცავს 16 ბიტს, რომელიც რეზერვირებულია რეესტრის სიისთვის, ზუსტად იმ რეგისტრების რაოდენობას პროცესორის ბანკში. ამ ველში თითოეული ბიტი მიუთითებს, თუ რომელი რეესტრი მიიღებს მონაწილეობას ოპერაციაში.

ახლა წაკითხვის/ჩაწერის რეჟიმის შესახებ. აქ დაბნეულობის ადგილია. ფაქტია, რომ სხვადასხვა რეჟიმის სახელები შეიძლება გამოყენებულ იქნას ერთი და იგივე მოქმედებისთვის.

თუ მცირე ლირიკულ გადახრას გავაკეთებთ, მაშინ უნდა ვისაუბროთ... დასტაზე. სტეკი არის LIFO ტიპის მონაცემებზე წვდომის საშუალება - Last In First Out (wiki) - ბოლო შემოსული, პირველი გარეთ. სტეკი ფართოდ გამოიყენება პროგრამირებაში პროცედურების გამოძახებისას და რეგისტრების მდგომარეობის შენახვისას ფუნქციების შეყვანისას და მათი აღდგენისას გასასვლელში, ასევე გამოძახებულ პროცედურებზე პარამეტრების გადაცემისას.

არსებობს, ვინ იფიქრებდა, მეხსიერების სტეკის ოთხი ტიპი.

პირველი ტიპი არის სრული დაღმავალი. ეს ხდება მაშინ, როდესაც სტეკის მაჩვენებელი მიუთითებს დაკავებულ სტეკის ელემენტზე და სტეკი იზრდება მისამართების კლებისკენ. როდესაც დაგჭირდებათ სიტყვის დადება სტეკზე, ჯერ სტეკის მაჩვენებელი მცირდება (Decrement Before), შემდეგ სიტყვა იწერება სტეკის მაჩვენებლის მისამართზე. როდესაც გჭირდებათ კომპიუტერის სიტყვის დასტადან ამოღება, სიტყვა იკითხება სტეკის მაჩვენებლის ამჟამინდელი მნიშვნელობის გამოყენებით, შემდეგ კურსორი გადაადგილდება ზემოთ (Increment After).

მეორე ტიპი არის სრული აღმავალი. სტეკი არ იზრდება ქვემოთ, არამედ მაღლა, უფრო დიდი მისამართებისკენ. მაჩვენებელი ასევე მიუთითებს დაკავებულ ელემენტზე. როდესაც დაგჭირდებათ სიტყვის დადება დასტაზე, ჯერ სტეკის მაჩვენებელი მატულობს, შემდეგ სიტყვა იწერება პოინტერზე (Increment Before). როდესაც დაგჭირდებათ დასტიდან ამოღება, ჯერ წაიკითხავთ სტეკის მაჩვენებელს, რადგან ის მიუთითებს დაკავებულ ელემენტზე, შემდეგ მცირდება სტეკის მაჩვენებელი (Decrement After).

მესამე ტიპი არის ცარიელი დაღმავალი. სტეკი იზრდება ქვევით, როგორც სრული დაღმავალის შემთხვევაში, მაგრამ განსხვავება ისაა, რომ სტეკის მაჩვენებელი მიუთითებს დაუკავებელ უჯრედზე. ამრიგად, როდესაც თქვენ გჭირდებათ სიტყვის დასტა დასტაზე, მაშინვე კეთდება ჩანაწერი, შემდეგ სტეკის მაჩვენებელი მცირდება (Decrement After). სტეკიდან ამოღებისას კურსორი ჯერ მატულობს, შემდეგ იკითხება (Increment Before).

მეოთხე ტიპი არის ცარიელი აღმავალი. იმედი მაქვს, რომ ყველაფერი ნათელია - დასტა იზრდება ზემოთ. სტეკის მაჩვენებელი მიუთითებს ცარიელ ელემენტზე. დასტაზე დაყენება ნიშნავს სიტყვის დაწერას სტეკის მაჩვენებლის მისამართით და სტეკის მაჩვენებლის გაზრდას (Increment After). ამოიღეთ დასტიდან - შეამცირეთ სტეკის მაჩვენებელი და წაიკითხეთ სიტყვა (Decrement Before).

ამრიგად, სტეკზე ოპერაციების შესრულებისას საჭიროა კურსორის გაზრდა ან შემცირება - (Increment/Decrement) მეხსიერებაში წაკითხვის/ჩაწერის წინ ან შემდეგ (Before/After) სტეკის ტიპის მიხედვით. Intel-ის პროცესორებს, მაგალითად, აქვთ სპეციალური ბრძანებები სტეკთან მუშაობისთვის, როგორიცაა PUSH (სიტყვის დადება სტეკზე) ან POP (სიტყვის ამოღება სტეკიდან). ARM პროცესორში არ არის სპეციალური ინსტრუქციები, მაგრამ გამოიყენება ldm და stm ინსტრუქციები.

თუ დასტას განახორციელებთ ARM პროცესორის ინსტრუქციების გამოყენებით, მიიღებთ შემდეგ სურათს:

რატომ სჭირდებოდა ერთსა და იმავე გუნდს სხვადასხვა სახელების დარქმევა? საერთოდ არ მესმის... აქ, რა თქმა უნდა, უნდა აღინიშნოს, რომ ARM-ის სტეკის სტანდარტი ჯერ კიდევ Full Descendingა.

ARM პროცესორში სტეკის მაჩვენებელი არის sp ან r13 რეგისტრი. ეს ძირითადად შეთანხმებაა. რა თქმა უნდა, stm-ის დაწერა ან ldm-ის წაკითხვა შესაძლებელია სხვა ბაზის რეგისტრებითაც. ამასთან, უნდა გახსოვდეთ, თუ როგორ განსხვავდება sp რეესტრი სხვა რეგისტრებისგან - ის შეიძლება განსხვავდებოდეს პროცესორის მუშაობის სხვადასხვა რეჟიმში (USR, SVC, IRQ, FIRQ), რადგან მათ აქვთ საკუთარი რეგისტრის ბანკები.

და კიდევ ერთი შენიშვნა. ჩაწერეთ ასეთი ხაზი ARM ასამბლეის კოდში ბიძგი (r0-r3), რა თქმა უნდა შესაძლებელია. მხოლოდ რეალურად იგივე გუნდი იქნება stmfd sp!, (r0-r3).

ბოლოს მოვიყვან ასამბლეის კოდის და მისი შედგენილი დაშლილი ტექსტის მაგალითს. ჩვენ გვაქვს:


stmfd sp!, (r0-r3)
stmdb sp!, (r0-r3)
ბიძგი (r0-r3)

@ეს სამი ინსტრუქცია იგივეა და გააკეთე იგივე
pop (r0-r3)
ldmia sp!, (r0-r3)
ldmfd r13!, (r0-r3)

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

შედგენის შემდეგ ვიღებთ:

0: e92d000f ბიძგი (r0, r1, r2, r3)
4: e92d000f ბიძგი (r0, r1, r2, r3)
8: e92d000f ბიძგი (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, pc)
20: e8958001 ldm r5, (r0, pc)

გადასვლები პროგრამებში.

პროგრამირება შეუძლებელია გადასვლების გარეშე. ნებისმიერ პროგრამაში არის კოდის ციკლური შესრულება, პროცედურების და ფუნქციების გამოძახება, ასევე არის კოდის განყოფილებების პირობითი შესრულება.

Amber ARM v2a პროცესორს აქვს მხოლოდ ორი ბრძანება: b (სიტყვიდან Branch - ფილიალი, გარდამავალი) და bl (Branch with Link - გარდამავალი დაბრუნების მისამართის შენარჩუნებისას).

ბრძანების სინტაქსი ძალიან მარტივია:

ბ(კონდ) ეტიკეტი
bl(cond) label

გასაგებია, რომ ნებისმიერი გადასვლები შეიძლება იყოს პირობითი, ანუ პროგრამა შეიძლება შეიცავდეს მსგავს უცნაურ სიტყვებს, რომლებიც წარმოიქმნება ფესვებიდან "b" და "bl" და პირობის სუფიქსები (Cond):

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, blal, bl

მრავალფეროვნება საოცარია, არა?

გადასვლა ბრძანება შეიცავს 24-ბიტიან ოფსეტურ ოფსეტს. გადახტომის მისამართი გამოითვლება როგორც კომპიუტერის მაჩვენებლის ამჟამინდელი მნიშვნელობის ჯამი და ოფსეტური რიცხვი გადაინაცვლა 2 ბიტით მარცხნივ, ინტერპრეტირებული როგორც ხელმოწერილი რიცხვი:

ახალი pc = pc + Offset * 4

ამრიგად, გადასვლების დიაპაზონი არის 32 MB წინ ან უკან.

მოდით შევხედოთ რა არის გადასვლა დაბრუნების მისამართის შენარჩუნებისას bl. ეს ბრძანება გამოიყენება ქვეპროგრამების გამოსაძახებლად. ამ ბრძანების საინტერესო თვისებაა ის, რომ პროცედურის გამოძახებისას დაბრუნების მისამართი არ ინახება სტეკზე, როგორც Intel-ის პროცესორებზე, არამედ ჩვეულებრივ r14 რეესტრში. შემდეგ, პროცედურისგან დასაბრუნებლად, თქვენ არ გჭირდებათ სპეციალური ret ბრძანება, როგორც იგივე Intel პროცესორებით, მაგრამ შეგიძლიათ უბრალოდ დააკოპიროთ r14 მნიშვნელობა კომპიუტერზე. ახლა გასაგებია, რატომ აქვს რეგისტრაცია r14-ს ალტერნატიული სახელი lr (ბმულის რეგისტრაცია).

მოდით შევხედოთ outbyte პროცედურას Hello-world პროექტის Amber SoC-ისთვის.

000004a0<_outbyte>:
4a0: e59f1454 ldr r1, ; 8 fc< адрес регистра данных UART >
4a4: e59f3454 ldr r3, ; 900< адрес регистра статуса UART >
4a8: e5932000 ldr r2, ; წაიკითხეთ მიმდინარე სტატუსი
4ac: e2022020 და r2, r2, #32
4b0: e3520000 cmp r2, #0; შეამოწმეთ, რომ UART არ არის დაკავებული
4b4: 05c10000 strbeq r0, ; დაწერეთ სიმბოლო UART-ში მხოლოდ იმ შემთხვევაში, თუ ის დაკავებული არ არის
4b8: 01b0f00e movseq pc, lr ; პროცედურისგან პირობითი დაბრუნება, თუ UART არ იყო დაკავებული
4bc: 1afffff9 bne 4a8<_outbyte+0x8>; ციკლი UART სტატუსის შესამოწმებლად

ვფიქრობ, ამ ფრაგმენტის კომენტარებიდან ნათელია, როგორ მუშაობს ეს პროცედურა.

კიდევ ერთი მნიშვნელოვანი შენიშვნა გადასვლების შესახებ. რეგისტრი r15 (pc) შეიძლება გამოყენებულ იქნას ჩვეულებრივ არითმეტიკულ ან ლოგიკურ ოპერაციებში, როგორც მიმღების რეგისტრი. ასე რომ, ბრძანება, როგორიცაა add pc,pc,#8, საკმაოდ ინსტრუქციაა სხვა მისამართზე გადასასვლელად.

კიდევ ერთი შენიშვნაა საჭირო გადასვლებთან დაკავშირებით. ძველ ARM პროცესორებს ასევე აქვთ დამატებითი განშტოების ინსტრუქციები bx, blx და blj. ეს არის ბრძანებები სხვადასხვა ბრძანების სისტემით ფრაგმენტებზე გადახტომისთვის. Bx /blx საშუალებას გაძლევთ გადახვიდეთ ARM პროცესორების 16-ბიტიან THUMB კოდზე. Blj არის Jazelle ინსტრუქციის სისტემის პროცედურების გამოძახება (Java ენის მხარდაჭერა ARM პროცესორებში). ჩვენს Amber ARM v2a-ს არ აქვს ეს ბრძანებები.

გამარჯობა ყველას!
პროფესიით ვარ ჯავის პროგრამისტი. მუშაობის ბოლო თვეებმა მაიძულა გამეცნობა Android NDK-ის შემუშავება და შესაბამისად მშობლიური აპლიკაციების C-ზე დაწერა. აქ დამხვდა Linux-ის ბიბლიოთეკების ოპტიმიზაციის პრობლემა. ბევრი აღმოჩნდა სრულიად არაოპტიმიზებული ARM-ისთვის და მძიმედ დატვირთა პროცესორი. ადრე ასამბლეის ენაზე პრაქტიკულად არასდროს მქონია დაპროგრამება, ამიტომ თავიდან გამიჭირდა ამ ენის სწავლის დაწყება, მაგრამ მაინც გადავწყვიტე მეცადა. ეს სტატია დაიწერა, ასე ვთქვათ, დამწყებთათვის დამწყებთათვის. შევეცდები აღვწერო ის საფუძვლები, რაც უკვე ვისწავლე, იმედია ეს ვინმეს დააინტერესებს. გარდა ამისა, სიამოვნებით მივიღებ კონსტრუქციულ კრიტიკას პროფესიონალებისგან.

შესავალი
ასე რომ, პირველ რიგში, მოდით გაერკვნენ, რა არის ARM. ვიკიპედია იძლევა ამ განმარტებას:

ARM არქიტექტურა (Advanced RISC Machine, Acorn RISC Machine, advanced RISC machine) არის ARM Limited-ის მიერ შემუშავებული ლიცენზირებული 32-ბიტიანი და 64-ბიტიანი მიკროპროცესორული ბირთვების ოჯახი. კომპანია ექსკლუზიურად ავითარებს ბირთვებსა და ინსტრუმენტებს მათთვის (შემდგენელები, გამართვის ხელსაწყოები და ა.შ.), ფულის გამომუშავებით არქიტექტურის ლიცენზირებით მესამე მხარის მწარმოებლებზე.

თუ ვინმემ არ იცის, ახლა მობილური მოწყობილობებისა და ტაბლეტების უმეტესობა განვითარებულია ამ პროცესორის არქიტექტურაზე. ამ ოჯახის მთავარი უპირატესობა მისი დაბალი ენერგიის მოხმარებაა, რის გამოც მას ხშირად იყენებენ სხვადასხვა ჩაშენებულ სისტემებში. არქიტექტურა დროთა განმავლობაში განვითარდა და ARMv7-დან დაწყებული, განისაზღვრა 3 პროფილი: 'A'(აპლიკაცია) - აპლიკაციები, 'R' (რეალურ დრო) - რეალურ დროში, 'M' (მიკროკონტროლერი) - მიკროკონტროლერი. ამ ტექნოლოგიის განვითარების ისტორია და სხვა საინტერესო მონაცემები შეგიძლიათ წაიკითხოთ ვიკიპედიაზე ან ინტერნეტში გუგლის საშუალებით. ARM მხარს უჭერს სხვადასხვა ოპერაციულ რეჟიმს (Thumb და ARM, გარდა ამისა, ახლახან გამოჩნდა Thumb-2, რომელიც არის ARM-ისა და Thumb-ის ნაზავი). ამ სტატიაში ჩვენ გადავხედავთ თავად ARM რეჟიმს, რომელშიც შესრულებულია 32-ბიტიანი ინსტრუქციების ნაკრები.

თითოეული ARM პროცესორი იქმნება შემდეგი ბლოკებისგან:

  • 37 რეგისტრი (აქედან მხოლოდ 17 ჩანს განვითარების დროს)
  • არითმეტიკული ლოგიკური ერთეული (ALU) - ასრულებს არითმეტიკულ და ლოგიკურ დავალებებს
  • ლულის გადამრთველი - მოწყობილობა, რომელიც შექმნილია მონაცემთა ბლოკების გარკვეული რაოდენობის ბიტების გადასატანად
  • CP15 არის სპეციალური სისტემა, რომელიც აკონტროლებს ARM კოპროცესორებს
  • ინსტრუქციის დეკოდერი - ეხება ინსტრუქციების გარდაქმნას მიკროოპერაციების თანმიმდევრობით
ეს არ არის ARM-ის ყველა კომპონენტი, მაგრამ პროცესორის კონსტრუქციის ჯუნგლებში ჩაღრმავება ამ სტატიის ფარგლებს სცილდება.
მილსადენის შესრულება
ARM პროცესორები იყენებენ 3-საფეხურიან მილსადენს (ARM8-დან დაწყებული, განხორციელდა 5-საფეხურიანი მილსადენი). მოდით შევხედოთ მარტივ მილსადენს, რომელიც იყენებს ARM7TDMI პროცესორს, როგორც მაგალითი. თითოეული ინსტრუქციის შესრულება შედგება სამი ეტაპისგან:

1. ნიმუშის აღების ეტაპი (F)
ამ ეტაპზე ინსტრუქციები RAM-დან გადადის პროცესორის მილსადენში.
2. დეკოდირების ეტაპი (D)
ინსტრუქციები გაშიფრულია და მათი ტიპი აღიარებულია.
3. შესრულების ფაზა (E)
მონაცემები შედის ALU-ში და სრულდება და მიღებული მნიშვნელობა იწერება მითითებულ რეესტრში.

მაგრამ შემუშავებისას უნდა გავითვალისწინოთ, რომ არსებობს ინსტრუქციები, რომლებიც იყენებენ რამდენიმე შესრულების ციკლს, მაგალითად, ჩატვირთვას (LDR) ან შენახვას. ამ შემთხვევაში შესრულების ეტაპი (E) იყოფა ეტაპებად (E1, E2, E3...).

პირობითი აღსრულება
ARM ასამბლერის ერთ-ერთი ყველაზე მნიშვნელოვანი ფუნქციაა პირობითი შესრულება. თითოეული ინსტრუქცია შეიძლება შესრულდეს პირობითად და ამისთვის გამოიყენება სუფიქსები. თუ ინსტრუქციის სახელს ემატება სუფიქსი, მისი შესრულებამდე მოწმდება პარამეტრები. თუ პარამეტრები არ აკმაყოფილებს პირობას, მაშინ ინსტრუქცია არ არის შესრულებული. სუფიქსები:
MI - უარყოფითი რიცხვი
PL - დადებითი ან ნულოვანი
AL - ყოველთვის შეასრულეთ ინსტრუქციები
კიდევ ბევრი პირობითი შესრულების სუფიქსია. წაიკითხეთ დანარჩენი სუფიქსები და მაგალითები ოფიციალურ დოკუმენტაციაში: ARM დოკუმენტაცია
ახლა დროა განიხილოს...
ძირითადი ARM ასამბლერის სინტაქსი
მათთვის, ვინც ადრე მუშაობდა ასამბლერთან, შეგიძლიათ რეალურად გამოტოვოთ ეს წერტილი. ყველა დანარჩენისთვის მე აღვწერ ამ ენასთან მუშაობის საფუძვლებს. ასე რომ, ყველა ასამბლეის ენის პროგრამა შედგება ინსტრუქციებისგან. ინსტრუქცია იქმნება ამ გზით:
(ეტიკეტი) (ინსტრუქცია|ოპერანდები) (@comment)
ლეიბლი არასავალდებულო პარამეტრია. ინსტრუქცია არის ინსტრუქციების პირდაპირი მნემონიკა პროცესორისთვის. ძირითადი ინსტრუქციები და მათი გამოყენება ქვემოთ იქნება განხილული. ოპერანდები - მუდმივები, რეგისტრირებული მისამართები, მისამართები RAM-ში. კომენტარი არის არასავალდებულო პარამეტრი, რომელიც გავლენას არ ახდენს პროგრამის შესრულებაზე.
დაარეგისტრირე სახელები
დასაშვებია შემდეგი რეესტრის სახელები:
1.r0-r15

3.v1-v8 (ცვლადი რეგისტრები, r4-დან r11-მდე)

4.sb და SB (სტატიკური რეგისტრი, r9)

5.sl და SL (r10)

6.fp და FP (r11)

7.ip და IP (r12)

8.sp და SP (r13)

9.lr და LR (r14)

10.pc და PC (პროგრამის მრიცხველი, r15).

ცვლადები და მუდმივები
ARM ასამბლერში, როგორც ნებისმიერი (პრაქტიკულად) სხვა პროგრამირების ენა, შეიძლება გამოყენებულ იქნას ცვლადები და მუდმივები. ისინი იყოფა შემდეგ ტიპებად:
  • რიცხვითი
  • ლოგიკური
  • სიმებიანი
რიცხვითი ცვლადები ინიციალიზებულია ასე:
SETA 100; იქმნება რიცხვითი ცვლადი "a" მნიშვნელობით 100.
სიმებიანი ცვლადები:
improb SETS "literal"; იქმნება ცვლადი improb მნიშვნელობით "literal". ყურადღება! ცვლადის მნიშვნელობა არ უნდა აღემატებოდეს 5120 სიმბოლოს.
ლოგიკური ცვლადები იყენებენ მნიშვნელობებს TRUE და FALSE შესაბამისად.
ARM ასამბლერის ინსტრუქციების მაგალითები
ამ ცხრილში მე შევაგროვე ძირითადი ინსტრუქციები, რომლებიც საჭირო იქნება შემდგომი განვითარებისთვის (ყველაზე საბაზისო ეტაპზე:):

ძირითადი ინსტრუქციების გამოყენების გასაძლიერებლად, მოდით დავწეროთ რამდენიმე მარტივი მაგალითი, მაგრამ ჯერ დაგვჭირდება მკლავის ხელსაწყოების ჯაჭვი. მე ვმუშაობ Linux-ზე, ამიტომ ავირჩიე: frank.harvard.edu/~coldwell/toolchain (arm-unknown-linux-gnu toolchain). ის შეიძლება დაინსტალირდეს ისევე მარტივად, როგორც ნებისმიერი სხვა პროგრამა Linux-ზე. ჩემს შემთხვევაში (რუსული Fedora) მჭირდებოდა მხოლოდ rpm პაკეტების დაყენება ვებსაიტიდან.
ახლა დროა დავწეროთ მარტივი მაგალითი. პროგრამა აბსოლუტურად უსარგებლო იქნება, მაგრამ მთავარია ის იმუშავებს :) აი კოდი, რომელსაც მე გთავაზობთ:
დაწყება: @ არჩევითი ხაზი, რომელიც მიუთითებს პროგრამის დასაწყისზე mov r0, #3 @ ჩატვირთეთ რეგისტრი r0 მნიშვნელობით 3 mov r1, #2 @ იგივე გააკეთეთ რეგისტრი r1, მხოლოდ ახლა მნიშვნელობით 2 დაამატეთ r2, r1, r0 @ დაამატეთ r0 და r1 მნიშვნელობები, პასუხი იწერება r2 mul r3, r1, r0 @ გაამრავლეთ რეგისტრის r1 მნიშვნელობა რეგისტრის r0 მნიშვნელობაზე, პასუხი იწერება r3 გაჩერებაზე: b stop @ პროგრამის შეწყვეტის ხაზი
ჩვენ ვადგენთ პროგრამას .bin ფაილის მისაღებად:
/usr/arm/bin/arm-unknown-linux-gnu-as -o arm.o arm.s /usr/arm/bin/arm-unknown-linux-gnu-ld -Ttext=0x0 -o ​​Arm. elf arm .o /usr/arm/bin/arm-unknown-linux-gnu-objcopy -O ორობითი arm.elf arm.bin
(კოდი არის arm.s ფაილში და ჩემს შემთხვევაში ინსტრუმენტთა ჯაჭვი არის /usr/arm/bin/ დირექტორიაში)
თუ ყველაფერი კარგად წავიდა, გექნებათ 3 ფაილი: arm.s (ფაქტობრივი კოდი), arm.o, arm.elf, arm.bin (ფაქტობრივი შესრულებადი პროგრამა). პროგრამის მუშაობის შესამოწმებლად არ არის აუცილებელი გქონდეთ საკუთარი ხელის მოწყობილობა. საკმარისია QEMU-ს დაყენება. ცნობისთვის:

QEMU არის უფასო და ღია კოდის პროგრამა სხვადასხვა პლატფორმის ტექნიკის ემულაციისთვის.

მოყვება Intel x86 პროცესორების და I/O მოწყობილობების ემულაცია. შეუძლია 80386, 80486, Pentium, Pentium Pro, AMD64 და სხვა x86-თან თავსებადი პროცესორების მიბაძვა; PowerPC, ARM, MIPS, SPARC, SPARC64, m68k - მხოლოდ ნაწილობრივ.

მუშაობს Syllable, FreeBSD, FreeDOS, Linux, Windows 9x, Windows 2000, Mac OS X, QNX, Android და ა.შ.

ასე რომ, მკლავის ემულაციისთვის დაგჭირდებათ qemu-system-arm. ეს პაკეტი არის yum, ასე რომ მათთვის, ვისაც აქვს Fedora, თქვენ არ გჭირდებათ შეწუხება და უბრალოდ გაუშვით ბრძანება:
yum install qemu-system-arm

შემდეგი, ჩვენ უნდა გავუშვათ ARM ემულატორი ისე, რომ მან შეასრულოს ჩვენი arm.bin პროგრამა. ამისათვის ჩვენ შევქმნით ფაილს flash.bin, რომელიც იქნება ფლეშ მეხსიერება QEMU-სთვის. ამის გაკეთება ძალიან მარტივია:
dd if=/dev/zero of=flash.bin bs=4096 count=4096 dd if=arm.bin of=flash.bin bs=4096 conv=notrunc
ახლა ჩვენ ვტვირთავთ QEMU მიღებული ფლეშ მეხსიერებით:
qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
გამომავალი იქნება დაახლოებით ასეთი:

$ qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
QEMU 0.15.1 მონიტორი - აკრიფეთ "help" დამატებითი ინფორმაციისთვის
(qemu)

ჩვენს arm.bin პროგრამას უნდა შეეცვალა ოთხი რეგისტრის მნიშვნელობები, ამიტომ, სწორი ოპერაციის შესამოწმებლად, მოდით შევხედოთ იმავე რეგისტრებს. ეს კეთდება ძალიან მარტივი ბრძანებით: info რეგისტრაციას
გამოსავალზე ნახავთ ARM-ის 15-ვე რეგისტრს და მათგან ოთხს ექნება შეცვლილი მნიშვნელობები. შეამოწმეთ :) რეგისტრის მნიშვნელობები ემთხვევა იმას, რაც მოსალოდნელია პროგრამის შესრულების შემდეგ:
(qemu) ინფორმაციის რეგისტრები R00=00000003 R01=00000002 R02=00000005 R03=00000006 R04=00000000 R05=00000000 R06=00000000 R0000000 00000 R10=00000000 R11=00000000 R12=00000000 R13=00000000 R14= 00000000 R15=00000010 PSR=400001d3 -Z-- A svc32

P.S. ამ სტატიაში შევეცადე აღმეწერა პროგრამირების საფუძვლები ARM ასამბლერში. იმედი მაქვს მოგეწონათ! ეს საკმარისი იქნება ამ ენის ჯუნგლებში შემდგომი ჩაღრმავებისთვის და მასში პროგრამების დასაწერად. თუ ყველაფერი გამოვა, მე დავწერ იმას, რასაც თავად გავიგებ. თუ ხარვეზებია, გთხოვთ, არ დამეკაროთ, რადგან ახალი ვარ ასამბლერში.

გამარჯობა ყველას!
პროფესიით ვარ ჯავის პროგრამისტი. მუშაობის ბოლო თვეებმა მაიძულა გამეცნობა Android NDK-ის შემუშავება და შესაბამისად მშობლიური აპლიკაციების C-ზე დაწერა. აქ დამხვდა Linux-ის ბიბლიოთეკების ოპტიმიზაციის პრობლემა. ბევრი აღმოჩნდა სრულიად არაოპტიმიზებული ARM-ისთვის და მძიმედ დატვირთა პროცესორი. ადრე ასამბლეის ენაზე პრაქტიკულად არასდროს მქონია დაპროგრამება, ამიტომ თავიდან გამიჭირდა ამ ენის სწავლის დაწყება, მაგრამ მაინც გადავწყვიტე მეცადა. ეს სტატია დაიწერა, ასე ვთქვათ, დამწყებთათვის დამწყებთათვის. შევეცდები აღვწერო ის საფუძვლები, რაც უკვე ვისწავლე, იმედია ეს ვინმეს დააინტერესებს. გარდა ამისა, სიამოვნებით მივიღებ კონსტრუქციულ კრიტიკას პროფესიონალებისგან.

შესავალი
ასე რომ, პირველ რიგში, მოდით გაერკვნენ, რა არის ARM. ვიკიპედია იძლევა ამ განმარტებას:

ARM არქიტექტურა (Advanced RISC Machine, Acorn RISC Machine, advanced RISC machine) არის ARM Limited-ის მიერ შემუშავებული ლიცენზირებული 32-ბიტიანი და 64-ბიტიანი მიკროპროცესორული ბირთვების ოჯახი. კომპანია ექსკლუზიურად ავითარებს ბირთვებსა და ინსტრუმენტებს მათთვის (შემდგენელები, გამართვის ხელსაწყოები და ა.შ.), ფულის გამომუშავებით არქიტექტურის ლიცენზირებით მესამე მხარის მწარმოებლებზე.

თუ ვინმემ არ იცის, ახლა მობილური მოწყობილობებისა და ტაბლეტების უმეტესობა განვითარებულია ამ პროცესორის არქიტექტურაზე. ამ ოჯახის მთავარი უპირატესობა მისი დაბალი ენერგიის მოხმარებაა, რის გამოც მას ხშირად იყენებენ სხვადასხვა ჩაშენებულ სისტემებში. არქიტექტურა დროთა განმავლობაში განვითარდა და ARMv7-დან დაწყებული, განისაზღვრა 3 პროფილი: 'A'(აპლიკაცია) - აპლიკაციები, 'R' (რეალურ დრო) - რეალურ დროში, 'M' (მიკროკონტროლერი) - მიკროკონტროლერი. ამ ტექნოლოგიის განვითარების ისტორია და სხვა საინტერესო მონაცემები შეგიძლიათ წაიკითხოთ ვიკიპედიაზე ან ინტერნეტში გუგლის საშუალებით. ARM მხარს უჭერს სხვადასხვა ოპერაციულ რეჟიმს (Thumb და ARM, გარდა ამისა, ახლახან გამოჩნდა Thumb-2, რომელიც არის ARM-ისა და Thumb-ის ნაზავი). ამ სტატიაში ჩვენ გადავხედავთ თავად ARM რეჟიმს, რომელშიც შესრულებულია 32-ბიტიანი ინსტრუქციების ნაკრები.

თითოეული ARM პროცესორი იქმნება შემდეგი ბლოკებისგან:

  • 37 რეგისტრი (აქედან მხოლოდ 17 ჩანს განვითარების დროს)
  • არითმეტიკული ლოგიკური ერთეული (ALU) - ასრულებს არითმეტიკულ და ლოგიკურ დავალებებს
  • ლულის გადამრთველი - მოწყობილობა, რომელიც შექმნილია მონაცემთა ბლოკების გარკვეული რაოდენობის ბიტების გადასატანად
  • CP15 არის სპეციალური სისტემა, რომელიც აკონტროლებს ARM კოპროცესორებს
  • ინსტრუქციის დეკოდერი - ეხება ინსტრუქციების გარდაქმნას მიკროოპერაციების თანმიმდევრობით
ეს არ არის ARM-ის ყველა კომპონენტი, მაგრამ პროცესორის კონსტრუქციის ჯუნგლებში ჩაღრმავება ამ სტატიის ფარგლებს სცილდება.
მილსადენის შესრულება
ARM პროცესორები იყენებენ 3-საფეხურიან მილსადენს (ARM8-დან დაწყებული, განხორციელდა 5-საფეხურიანი მილსადენი). მოდით შევხედოთ მარტივ მილსადენს, რომელიც იყენებს ARM7TDMI პროცესორს, როგორც მაგალითი. თითოეული ინსტრუქციის შესრულება შედგება სამი ეტაპისგან:

1. ნიმუშის აღების ეტაპი (F)
ამ ეტაპზე ინსტრუქციები RAM-დან გადადის პროცესორის მილსადენში.
2. დეკოდირების ეტაპი (D)
ინსტრუქციები გაშიფრულია და მათი ტიპი აღიარებულია.
3. შესრულების ფაზა (E)
მონაცემები შედის ALU-ში და სრულდება და მიღებული მნიშვნელობა იწერება მითითებულ რეესტრში.

მაგრამ შემუშავებისას უნდა გავითვალისწინოთ, რომ არსებობს ინსტრუქციები, რომლებიც იყენებენ რამდენიმე შესრულების ციკლს, მაგალითად, ჩატვირთვას (LDR) ან შენახვას. ამ შემთხვევაში შესრულების ეტაპი (E) იყოფა ეტაპებად (E1, E2, E3...).

პირობითი აღსრულება
ARM ასამბლერის ერთ-ერთი ყველაზე მნიშვნელოვანი ფუნქციაა პირობითი შესრულება. თითოეული ინსტრუქცია შეიძლება შესრულდეს პირობითად და ამისთვის გამოიყენება სუფიქსები. თუ ინსტრუქციის სახელს ემატება სუფიქსი, მისი შესრულებამდე მოწმდება პარამეტრები. თუ პარამეტრები არ აკმაყოფილებს პირობას, მაშინ ინსტრუქცია არ არის შესრულებული. სუფიქსები:
MI - უარყოფითი რიცხვი
PL - დადებითი ან ნულოვანი
AL - ყოველთვის შეასრულეთ ინსტრუქციები
კიდევ ბევრი პირობითი შესრულების სუფიქსია. წაიკითხეთ დანარჩენი სუფიქსები და მაგალითები ოფიციალურ დოკუმენტაციაში: ARM დოკუმენტაცია
ახლა დროა განიხილოს...
ძირითადი ARM ასამბლერის სინტაქსი
მათთვის, ვინც ადრე მუშაობდა ასამბლერთან, შეგიძლიათ რეალურად გამოტოვოთ ეს წერტილი. ყველა დანარჩენისთვის მე აღვწერ ამ ენასთან მუშაობის საფუძვლებს. ასე რომ, ყველა ასამბლეის ენის პროგრამა შედგება ინსტრუქციებისგან. ინსტრუქცია იქმნება ამ გზით:
(ეტიკეტი) (ინსტრუქცია|ოპერანდები) (@comment)
ლეიბლი არასავალდებულო პარამეტრია. ინსტრუქცია არის ინსტრუქციების პირდაპირი მნემონიკა პროცესორისთვის. ძირითადი ინსტრუქციები და მათი გამოყენება ქვემოთ იქნება განხილული. ოპერანდები - მუდმივები, რეგისტრირებული მისამართები, მისამართები RAM-ში. კომენტარი არის არასავალდებულო პარამეტრი, რომელიც გავლენას არ ახდენს პროგრამის შესრულებაზე.
დაარეგისტრირე სახელები
დასაშვებია შემდეგი რეესტრის სახელები:
1.r0-r15

3.v1-v8 (ცვლადი რეგისტრები, r4-დან r11-მდე)

4.sb და SB (სტატიკური რეგისტრი, r9)

5.sl და SL (r10)

6.fp და FP (r11)

7.ip და IP (r12)

8.sp და SP (r13)

9.lr და LR (r14)

10.pc და PC (პროგრამის მრიცხველი, r15).

ცვლადები და მუდმივები
ARM ასამბლერში, როგორც ნებისმიერი (პრაქტიკულად) სხვა პროგრამირების ენა, შეიძლება გამოყენებულ იქნას ცვლადები და მუდმივები. ისინი იყოფა შემდეგ ტიპებად:
  • რიცხვითი
  • ლოგიკური
  • სიმებიანი
რიცხვითი ცვლადები ინიციალიზებულია ასე:
SETA 100; იქმნება რიცხვითი ცვლადი "a" მნიშვნელობით 100.
სიმებიანი ცვლადები:
improb SETS "literal"; იქმნება ცვლადი improb მნიშვნელობით "literal". ყურადღება! ცვლადის მნიშვნელობა არ უნდა აღემატებოდეს 5120 სიმბოლოს.
ლოგიკური ცვლადები იყენებენ მნიშვნელობებს TRUE და FALSE შესაბამისად.
ARM ასამბლერის ინსტრუქციების მაგალითები
ამ ცხრილში მე შევაგროვე ძირითადი ინსტრუქციები, რომლებიც საჭირო იქნება შემდგომი განვითარებისთვის (ყველაზე საბაზისო ეტაპზე:):

ძირითადი ინსტრუქციების გამოყენების გასაძლიერებლად, მოდით დავწეროთ რამდენიმე მარტივი მაგალითი, მაგრამ ჯერ დაგვჭირდება მკლავის ხელსაწყოების ჯაჭვი. მე ვმუშაობ Linux-ზე, ამიტომ ავირჩიე: frank.harvard.edu/~coldwell/toolchain (arm-unknown-linux-gnu toolchain). ის შეიძლება დაინსტალირდეს ისევე მარტივად, როგორც ნებისმიერი სხვა პროგრამა Linux-ზე. ჩემს შემთხვევაში (რუსული Fedora) მჭირდებოდა მხოლოდ rpm პაკეტების დაყენება ვებსაიტიდან.
ახლა დროა დავწეროთ მარტივი მაგალითი. პროგრამა აბსოლუტურად უსარგებლო იქნება, მაგრამ მთავარია ის იმუშავებს :) აი კოდი, რომელსაც მე გთავაზობთ:
დაწყება: @ არჩევითი ხაზი, რომელიც მიუთითებს პროგრამის დასაწყისზე mov r0, #3 @ ჩატვირთეთ რეგისტრი r0 მნიშვნელობით 3 mov r1, #2 @ იგივე გააკეთეთ რეგისტრი r1, მხოლოდ ახლა მნიშვნელობით 2 დაამატეთ r2, r1, r0 @ დაამატეთ r0 და r1 მნიშვნელობები, პასუხი იწერება r2 mul r3, r1, r0 @ გაამრავლეთ რეგისტრის r1 მნიშვნელობა რეგისტრის r0 მნიშვნელობაზე, პასუხი იწერება r3 გაჩერებაზე: b stop @ პროგრამის შეწყვეტის ხაზი
ჩვენ ვადგენთ პროგრამას .bin ფაილის მისაღებად:
/usr/arm/bin/arm-unknown-linux-gnu-as -o arm.o arm.s /usr/arm/bin/arm-unknown-linux-gnu-ld -Ttext=0x0 -o ​​Arm. elf arm .o /usr/arm/bin/arm-unknown-linux-gnu-objcopy -O ორობითი arm.elf arm.bin
(კოდი არის arm.s ფაილში და ჩემს შემთხვევაში ინსტრუმენტთა ჯაჭვი არის /usr/arm/bin/ დირექტორიაში)
თუ ყველაფერი კარგად წავიდა, გექნებათ 3 ფაილი: arm.s (ფაქტობრივი კოდი), arm.o, arm.elf, arm.bin (ფაქტობრივი შესრულებადი პროგრამა). პროგრამის მუშაობის შესამოწმებლად არ არის აუცილებელი გქონდეთ საკუთარი ხელის მოწყობილობა. საკმარისია QEMU-ს დაყენება. ცნობისთვის:

QEMU არის უფასო და ღია კოდის პროგრამა სხვადასხვა პლატფორმის ტექნიკის ემულაციისთვის.

მოყვება Intel x86 პროცესორების და I/O მოწყობილობების ემულაცია. შეუძლია 80386, 80486, Pentium, Pentium Pro, AMD64 და სხვა x86-თან თავსებადი პროცესორების მიბაძვა; PowerPC, ARM, MIPS, SPARC, SPARC64, m68k - მხოლოდ ნაწილობრივ.

მუშაობს Syllable, FreeBSD, FreeDOS, Linux, Windows 9x, Windows 2000, Mac OS X, QNX, Android და ა.შ.

ასე რომ, მკლავის ემულაციისთვის დაგჭირდებათ qemu-system-arm. ეს პაკეტი არის yum, ასე რომ მათთვის, ვისაც აქვს Fedora, თქვენ არ გჭირდებათ შეწუხება და უბრალოდ გაუშვით ბრძანება:
yum install qemu-system-arm

შემდეგი, ჩვენ უნდა გავუშვათ ARM ემულატორი ისე, რომ მან შეასრულოს ჩვენი arm.bin პროგრამა. ამისათვის ჩვენ შევქმნით ფაილს flash.bin, რომელიც იქნება ფლეშ მეხსიერება QEMU-სთვის. ამის გაკეთება ძალიან მარტივია:
dd if=/dev/zero of=flash.bin bs=4096 count=4096 dd if=arm.bin of=flash.bin bs=4096 conv=notrunc
ახლა ჩვენ ვტვირთავთ QEMU მიღებული ფლეშ მეხსიერებით:
qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
გამომავალი იქნება დაახლოებით ასეთი:

$ qemu-system-arm -M connex -pflash flash.bin -nographic -serial /dev/null
QEMU 0.15.1 მონიტორი - აკრიფეთ "help" დამატებითი ინფორმაციისთვის
(qemu)

ჩვენს arm.bin პროგრამას უნდა შეეცვალა ოთხი რეგისტრის მნიშვნელობები, ამიტომ, სწორი ოპერაციის შესამოწმებლად, მოდით შევხედოთ იმავე რეგისტრებს. ეს კეთდება ძალიან მარტივი ბრძანებით: info რეგისტრაციას
გამოსავალზე ნახავთ ARM-ის 15-ვე რეგისტრს და მათგან ოთხს ექნება შეცვლილი მნიშვნელობები. შეამოწმეთ :) რეგისტრის მნიშვნელობები ემთხვევა იმას, რაც მოსალოდნელია პროგრამის შესრულების შემდეგ:
(qemu) ინფორმაციის რეგისტრები R00=00000003 R01=00000002 R02=00000005 R03=00000006 R04=00000000 R05=00000000 R06=00000000 R0000000 00000 R10=00000000 R11=00000000 R12=00000000 R13=00000000 R14= 00000000 R15=00000010 PSR=400001d3 -Z-- A svc32

P.S. ამ სტატიაში შევეცადე აღმეწერა პროგრამირების საფუძვლები ARM ასამბლერში. იმედი მაქვს მოგეწონათ! ეს საკმარისი იქნება ამ ენის ჯუნგლებში შემდგომი ჩაღრმავებისთვის და მასში პროგრამების დასაწერად. თუ ყველაფერი გამოვა, მე დავწერ იმას, რასაც თავად გავიგებ. თუ ხარვეზებია, გთხოვთ, არ დამეკაროთ, რადგან ახალი ვარ ასამბლერში.

1. რეალურ დროში საათის მრიცხველი უნდა იყოს ჩართული (1); საათის წყაროს არჩევის ბიტი წაშლილია (2), თუ დაკვრა არ არის უზრუნველყოფილი საათის მთავარი გენერატორის მიერ.

2. შეწყვეტის მოვლენის არჩევის ერთი ან ორივე ბიტი (3) უნდა იყოს დაყენებული. და არჩეულია რომელი მოვლენები გამოიწვევს შეწყვეტის მოთხოვნას (5).

3. შეფერხების მოვლენის ნიღბები (4, 7) უნდა იყოს მითითებული.

2.5 ARM7 ასამბლერში დაპროგრამების შესახებ

ARM7 ინსტრუქციების ნაკრები (ნაწილი 1.4) მოიცავს მხოლოდ 45 ინსტრუქციას, რომლებიც საკმაოდ რთულია მისამართის მეთოდების მრავალფეროვნების, პირობითი ველებისა და მოდიფიკატორების გამო. ასამბლერის პროგრამა რთულია და

თან რთული წასაკითხი. ამიტომ, ასამბლერი იშვიათად გამოიყენება ARM7 არქიტექტურის პროგრამირებაში.

ამავდროულად, მაღალი დონის ენა C პროგრამისტს მალავს ბევრ არქიტექტურულ მახასიათებელს. პროგრამისტი პრაქტიკულად არ ეხება ისეთ პროცედურებს, როგორიცაა ბირთვის რეჟიმის არჩევა, მეხსიერების გამოყოფა სტეკისთვის და შეფერხებების მართვა. ამ პროცედურების შესასწავლად, სასარგებლოა მინიმუმ ერთი მარტივი პროგრამის დაწერა ასამბლეის ენაზე.

გარდა ამისა, C-ის გამოყენებისას კი მაინც უნდა მიმართოთ ასამბლეის ენას.

1. უნდა გაკონტროლდეს C შემდგენელი აკონტროლებს, გამორიცხა თუ არა მნიშვნელოვანი ბრძანებები ოპტიმიზაციის დროს, თვლის მათ არასაჭირო. არასაკმარისი ოპტიმიზაციის გამო კომპილერი აწარმოებს უკიდურესად არაეფექტურ კოდს შედარებით მარტივი ოპერაციისთვის. იმისათვის, რომ დარწმუნდეთ, რომ შემდგენელი რეალურად იყენებს იმ ტექნიკის რესურსებს, რომლებიც შექმნილია კონკრეტული ალგორითმის ეფექტურობის გასაზრდელად.

2. შეცდომების ან გამონაკლისების მიზეზების ძიებისას (ნაწილი 2.4.1).

3. კოდის მისაღებად, რომელიც აბსოლუტურად ოპტიმალურია შესრულების ან მეხსიერების მოხმარების თვალსაზრისით (სექციები 2.2.20, 3.1.5).

მოდით გადავხედოთ ასამბლერში პროგრამის დაწერის ძირითად ტექნიკას

თან მიზანია მიკროკონტროლერის მიერ შესრულებული ყველა კოდის დემონსტრირება, როგორც არის და შუამავლობის გარეშე C შემდგენელი.

ასამბლერზე დაფუძნებული პროექტის შექმნის პროცედურა თითქმის იგივეა, რაც C პროგრამებისთვის (სექციები 2.3.1–2.3.3). არსებობს მხოლოდ ორი გამონაკლისი:

ა) საწყის ტექსტურ ფაილს ენიჭება გაფართოება *.S;

ბ) აქ ვარაუდობენ, რომ STARTUP.S ფაილი არ არის დაკავშირებული პროგრამასთან.

2.5.1 ასამბლერში პროგრამების ჩაწერის ძირითადი წესები

ასამბლერის პროგრამის ტექსტი ჩვეულებრივ ფორმატირებულია ოთხ სვეტად. შეგვიძლია ვთქვათ, რომ თითოეული ხაზი შედგება ოთხი ველისაგან, კერძოდ: ეტიკეტები, ოპერაციები, ოპერანდები, კომენტარები. ველები ერთმანეთისგან გამოყოფილია ჩანართის სიმბოლოებით ან სივრცეებით.

ძირითადი სფეროებია ოპერაციები და ოპერანდები. სწორი ოპერაციები და მათი სინტაქსი მოცემულია ცხრილში (1.4.2)

ეტიკეტი არის ბრძანების მისამართის სიმბოლური აღნიშვნა. ყველგან, ლეიბლის ნაცვლად, შეიცვლება იმ ბრძანების მისამართი, რომელსაც წინ უძღვის ლეიბლი. ყველაზე ხშირად, ტეგები გამოიყენება საკონტროლო გადაცემის ბრძანებებში. თითოეული ეტიკეტი უნდა იყოს უნიკალური და არჩევითია. ბევრი სხვა ვერსიისგან განსხვავებით, RealView ასამბლერში ეტიკეტები არ მთავრდება ორწერტილით (":").

კომენტარები სურვილისამებრ მოთავსებულია სტრიქონის ბოლოს და გამოყოფილია მძიმით (";").

მოვიყვანოთ მარტივი მაგალითი.

2.5.2 ფსევდო-ბრძანებები

RealView ასამბლეერი მხარს უჭერს ეგრეთ წოდებულ ფსევდო ინსტრუქციებს. ფსევდო-ინსტრუქცია არის მნემონური აღნიშვნა, რომელიც რეალურად არ შეესაბამება პროცესორის ინსტრუქციების კომპლექტს, მაგრამ იცვლება ერთი ან (იშვიათად) რამდენიმე ინსტრუქციით. ფსევდო-ბრძანებები ერთგვარი მაკროა და ემსახურება სინტაქსის გამარტივებას. მხარდაჭერილი ფსევდო ბრძანებების სია მოცემულია ცხრილში (2.5.1).

2.5.3 ასამბლეის დირექტივები

ბრძანებებისგან განსხვავებით, დირექტივები არ ქმნიან შესრულებად კოდს, რომელიც იტვირთება მიკროკონტროლერის მეხსიერებაში. დირექტივები მხოლოდ ინსტრუქციებია ასამბლერისთვის, ისინი აკონტროლებენ შესრულებადი კოდის ფორმირებას.

მოდით გადავხედოთ ხშირად გამოყენებულ RealView 4 ასამბლერის დირექტივებს.

სახელი EQU Constant

მუდმივს ანიჭებს სიმბოლურ აღნიშვნას Name, რომელიც ხდება მუდმივის სინონიმი. მთავარი მიზანია საკონტროლო რეგისტრების სახელების გაცნობა,

არეალის სახელი, პარამეტრები

განსაზღვრავს მეხსიერების არეალს მოცემული სახელით. პარამეტრების გამოყენებით, თქვენ მიუთითებთ მეხსიერების არეალის დანიშნულებას, მაგალითად, DATA (მონაცემები) ან CODE (კოდი). განსაზღვრული ტერიტორიის მისამართები დამოკიდებულია არჩეულ დანიშნულებაზე. CODE ზონა მდებარეობს 0x00000000 მისამართიდან, DATA ზონა - 0x40000000 მისამართიდან. პროგრამას უნდა ჰქონდეს CODE არე, სახელად RESET. პროგრამის მეხსიერებაში მოთავსებული მუდმივები დეკლარირებული უნდა იყოს განყოფილებაში წყვილი პარამეტრით CODE, READONLY.

მიუთითებს პროგრამაში შესვლის წერტილს, აჩვენებს მის „დასაწყისს“. ერთი ასეთი დირექტივა ყოველთვის უნდა იყოს პროგრამაში. ჩვეულებრივ განთავსებულია AREA RESET, CODE დირექტივის შემდეგ დაუყოვნებლივ.

ცხრილი 2.5.1 – ფსევდო-ინსტრუქციები მხარდაჭერილი RealView 4 ასამბლერის მიერ

მნემონური აღნიშვნა

ოპერაცია

ფაქტობრივი განხორციელება

და სინტაქსი

ADR (კონდ.)

რეესტრში

კომპიუტერიდან მუდმივის დამატება ან გამოკლება co-

ADD ან SUB ბრძანებები

ADRL (კონდი)

რეესტრში

ორმაგი ADD ან SUB, რომელიც მოიცავს კომპიუტერს

(გაფართოებული მისამართის დიაპაზონი)

ASR(კონდი) (S)

არითმეტიკული ცვლა მარჯვნივ

ASR(კონდი) (S)

shift ოპერანდი

LDR (კონდ.)

რეესტრში

მისამართით (კომპიუტერი + დაუყოვნებელი ოფსეტური)

მუდმივის განთავსება

პროგრამის მეხსიერებაში

LDR (ინდექსის მისამართიდან-

tion. კომპიუტერი ემსახურება ოფსეტს.

LSL(პირობითი)(S)

ლოგიკური ცვლა მარცხნივ

LSL(პირობითი)(S)

shift ოპერანდი

LSR(კონდი) (S)

ლოგიკური ცვლა მარჯვნივ

LSR(კონდი) (S)

shift ოპერანდი

POP (კონდ.)

რეგისტრების აღდგენა სტეკიდან

აღდგენა

რეგისტრები

გუნდი

LDMIA R13!, (...)

PUSH (კონდ)

შენახვა

რეგისტრები

გუნდი

STMDB R13!, (...)

ROR(კონდ) (S)

ციკლური ცვლა მარჯვნივ

ROR(კონდ) (S)

shift ოპერანდი

RRX(კონდ.)(S)

ველოსიპედით პირდაპირ

გადარიცხვა 1 ციფრით

shift ოპერანდი

დასახელება SPACE Size

იტოვებს მეხსიერებას მოცემული ზომის მონაცემების შესანახად. სახელი ხდება რეზერვირებული სივრცის მისამართის სინონიმი. მისამართების სივრცის ერთიანობა ამ დირექტივის გამოყენების საშუალებას იძლევა როგორც მუდმივი, ასევე ოპერატიული მეხსიერება. მთავარი მიზანია გლობალური ცვლადების შექმნა RAM-ში (DATA ზონაში).

ეტიკეტი DCB/DCW/DCD მუდმივი

"Flash" მონაცემები (რიცხვითი მუდმივები) პროგრამის მეხსიერებაში. ეტიკეტი ხდება იმ მისამართის სინონიმი, რომელზეც ჩაიწერება მონაცემები. სხვადასხვა დირექტივები (DCB, DCW და DCD) ემსახურება სხვადასხვა ზომის მონაცემებს: ბაიტი, 16-ბიტიანი სიტყვა, 32-ბიტიანი სიტყვა (შესაბამისად).

ემსახურება ფაილის დასრულების ნიშანს. ამ დირექტივის შემდეგ ყველა ტექსტი იგნორირებულია ასამბლერის მიერ.

2.5.4 მაკრო

მაკრო არის წინასწარ განსაზღვრული პროგრამის ფრაგმენტი, რომელიც ასრულებს ზოგიერთ საერთო ოპერაციას. საკონტროლო გადაცემის ბრძანებების გამოყენებით მოწოდებული ქვეპროგრამებისგან განსხვავებით, მაკროების გამოყენება არ ამცირებს შესრულებას, მაგრამ არ ამცირებს პროგრამის მეხსიერების მოხმარებას. რადგან ყოველ ჯერზე მაკრო გამოძახებისას, ასამბლერი ათავსებს მის მთელ ტექსტს პროგრამაში.

მაკროს გამოსაცხადებლად გამოიყენეთ შემდეგი კონსტრუქცია

$ პარამეტრი1, $ პარამეტრი2, ...

პარამეტრები საშუალებას გაძლევთ შეცვალოთ მაკრო ტექსტი ყოველ ჯერზე მასზე წვდომისას. მაკროს შიგნით (სხეულში), პარამეტრები ასევე გამოიყენება წინა "$" ნიშნით. მაკროს სხეულში პარამეტრების ნაცვლად, ზარის დროს მითითებული პარამეტრები იცვლება.

მაკროს ასე ჰქვია:

სახელი Parameter1, Parameter2, ...

შესაძლებელია მდგომარეობის შემოწმებისა და განშტოების ორგანიზება.

IF "$Parameter" == "მნიშვნელობა"

გთხოვთ გაითვალისწინოთ, რომ ეს დიზაინი არ იწვევს მიკროკონტროლერის მიერ მდგომარეობის პროგრამულ შემოწმებას. მდგომარეობა შემოწმებულია ასამბლერის მიერ შესრულებადი კოდის გენერირების დროს.